How to get the payload from TCP packet? - tcp

I want to extract the tcp payload data from tcp packet using pcapplusplus library, or other similar libraries as well. I search documentation but not able to find how to get the tcp payload, but i can get almost anything in the tcp header by using the various api's. How can i get the payload?
Public Member Functions
TcpLayer (uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet)
TcpLayer ()
TcpLayer (uint16_t portSrc, uint16_t portDst)
TcpLayer (const TcpLayer &other)
TcpLayer & operator= (const TcpLayer &other)
tcphdr * getTcpHeader () const
uint16_t getSrcPort () const
uint16_t getDstPort () const
TcpOption getTcpOption (TcpOptionType option) const
TcpOption getFirstTcpOption () const
TcpOption getNextTcpOption (TcpOption &tcpOption) const
size_t getTcpOptionCount () const
TcpOption addTcpOption (const TcpOptionBuilder &optionBuilder)
TcpOption addTcpOptionAfter (const TcpOptionBuilder &optionBuilder, TcpOptionType prevOptionType=TCPOPT_Unknown)
bool removeTcpOption (TcpOptionType optionType)
bool removeAllTcpOptions ()
uint16_t calculateChecksum (bool writeResultToPacket)
void parseNextLayer ()
size_t getHeaderLen () const
void computeCalculateFields ()
std::string toString () const
OsiModelLayer getOsiModelLayer () const
THese are API's to get tcp header data.

In order to get (any) layer payload you should use the getLayerPayload() API, for example:
pcpp::TcpLayer* tcpLayer = myPacket.getLayerOfType<pcpp::TcpLayer>();
uint8_t* payload = tcpLayer->getLayerPayload();
size_t payloadSize = tcpLayer->getLayerPayloadSize();

I got the answer after extensive searching. It is TcpStreamData::getData() method. You can see this link for the API documentation.

Related

nghttp2: Using server-sent events to be use by EventSource

I'm using nghttp2 to implement a REST server which should use HTTP/2 and server-sent events (to be consumed by an EventSource in the browser). However, based on the examples it is unclear to me how to implement SSE. Using res.push() as in asio-sv.cc doesn't seem to be the right approach.
What would be the right way to do it? I'd prefer to use nghttp2's C++ API, but the C API would do as well.
Yup, I did something like that back in 2018. The documentation was rather sparse :).
First of all, ignore response::push because that's the HTTP2 push -- something for proactively sending unsolicited objects to the client before it requests them. I know it sounds like what you need, but it is not -- the typical use case would be proactively sending a CSS file and some images along with the originally requested HTML page.
The key thing is that your end() callback must eventually return NGHTTP2_ERR_DEFERRED whenever you run out of data to send. When your application somehow obtains more data to be sent, call http::response::resume().
Here's a simple code. Build it as g++ -std=c++17 -Wall -O3 -ggdb clock.cpp -lssl -lcrypto -pthread -lnghttp2_asio -lspdlog -lfmt. Be careful, modern browsers don't do HTTP/2 over a plaintext socket, so you'll need to reverse-proxy it via something like nghttpx -f '*,8080;no-tls' -b '::1,10080;;proto=h2'.
#include <boost/asio/io_service.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/signals2.hpp>
#include <chrono>
#include <list>
#include <nghttp2/asio_http2_server.h>
#define SPDLOG_FMT_EXTERNAL
#include <spdlog/spdlog.h>
#include <thread>
using namespace nghttp2::asio_http2;
using namespace std::literals;
using Signal = boost::signals2::signal<void(const std::string& message)>;
class Client {
const server::response& res;
enum State {
HasEvents,
WaitingForEvents,
};
std::atomic<State> state;
std::list<std::string> queue;
mutable std::mutex mtx;
boost::signals2::scoped_connection subscription;
size_t send_chunk(uint8_t* destination, std::size_t len, uint32_t* data_flags [[maybe_unused]])
{
std::size_t written{0};
std::lock_guard lock{mtx};
if (state != HasEvents) throw std::logic_error{std::to_string(__LINE__)};
while (!queue.empty()) {
auto num = std::min(queue.front().size(), len - written);
std::copy_n(queue.front().begin(), num, destination + written);
written += num;
if (num < queue.front().size()) {
queue.front() = queue.front().substr(num);
spdlog::debug("{} send_chunk: partial write", (void*)this);
return written;
}
queue.pop_front();
spdlog::debug("{} send_chunk: sent one event", (void*)this);
}
state = WaitingForEvents;
return written;
}
public:
Client(const server::request& req, const server::response& res, Signal& signal)
: res{res}
, state{WaitingForEvents}
, subscription{signal.connect([this](const auto& msg) {
enqueue(msg);
})}
{
spdlog::warn("{}: {} {} {}", (void*)this, boost::lexical_cast<std::string>(req.remote_endpoint()), req.method(), req.uri().raw_path);
res.write_head(200, {{"content-type", {"text/event-stream", false}}});
}
void onClose(const uint32_t ec)
{
spdlog::error("{} onClose", (void*)this);
subscription.disconnect();
}
ssize_t process(uint8_t* destination, std::size_t len, uint32_t* data_flags)
{
spdlog::trace("{} process", (void*)this);
switch (state) {
case HasEvents:
return send_chunk(destination, len, data_flags);
case WaitingForEvents:
return NGHTTP2_ERR_DEFERRED;
}
__builtin_unreachable();
}
void enqueue(const std::string& what)
{
{
std::lock_guard lock{mtx};
queue.push_back("data: " + what + "\n\n");
}
state = HasEvents;
res.resume();
}
};
int main(int argc [[maybe_unused]], char** argv [[maybe_unused]])
{
spdlog::set_level(spdlog::level::trace);
Signal sig;
std::thread timer{[&sig]() {
for (int i = 0; /* forever */; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds{666});
spdlog::info("tick: {}", i);
sig("ping #" + std::to_string(i));
}
}};
server::http2 server;
server.num_threads(4);
server.handle("/events", [&sig](const server::request& req, const server::response& res) {
auto client = std::make_shared<Client>(req, res, sig);
res.on_close([client](const auto ec) {
client->onClose(ec);
});
res.end([client](uint8_t* destination, std::size_t len, uint32_t* data_flags) {
return client->process(destination, len, data_flags);
});
});
server.handle("/", [](const auto& req, const auto& resp) {
spdlog::warn("{} {} {}", boost::lexical_cast<std::string>(req.remote_endpoint()), req.method(), req.uri().raw_path);
resp.write_head(200, {{"content-type", {"text/html", false}}});
resp.end(R"(<html><head><title>nghttp2 event stream</title></head>
<body><h1>events</h1><ul id="x"></ul>
<script type="text/javascript">
const ev = new EventSource("/events");
ev.onmessage = function(event) {
const li = document.createElement("li");
li.textContent = event.data;
document.getElementById("x").appendChild(li);
};
</script>
</body>
</html>)");
});
boost::system::error_code ec;
if (server.listen_and_serve(ec, "::", "10080")) {
return 1;
}
return 0;
}
I have a feeling that my queue handling is probably too complex. When testing via curl, I never seem to run out of buffer space. In other words, even if the client is not reading any data from the socket, the library keep invoking send_chunk, asking for up to 16kB of data at a time for me. Strange. I have no idea how it works when pushing more data more heavily.
My "real code" used to have a third state, Closed, but I think that blocking events via on_close is enough here. However, I think you never want to enter send_chunk if the client has already disconnected, but before the destructor gets called.

Why doesn't F() macro (to store string in .text) compile?

At the bottom of the documentation on PROGMEM, it shows what looks like a wonderfully simple way to compile strings into the program .text segment:
The F() macro
When an instruction like:
Serial.print("Write something");
is used, the string to be printed is normally saved in RAM. If your sketch prints a lot of stuff on the Serial Monitor, you can easily fill the RAM. If you have free FLASH memory space, you can easily indicate that the string must be saved in FLASH using the syntax:
Serial.print(F("Write something that is stored in FLASH"));
However, I have had only bad luck getting this to compile.
#include <avr/pgmspace.h>
static const struct {short cmd; const char *txt;} cmds[] = {
{2, F("Hi")},
};
It complains with
t.c:3: error: initializer element is not constant
{2, F("hi")},
^
t.c:3: error: (near initialization for 'cmds[0].txt')
exit status 1
initializer element is not constant
Without the F macro, it compiles just fine.
{2, "Hi"},
Does anyone have experience getting this to work? I have like 10K of strings I'd like to get into the program space.
The F macro can only be used in executable parts of the code, not variable definitions. And because struct member can't have the PROGMEM attribute, you have to do it in two steps: declare each text string in PROGMEM, then use the PROGMEM address in the struct.
An array of structs can be in PROGMEM, too.
static const char cmd_0_txt[] PROGMEM = "Hello";
static const char cmd_1_txt[] PROGMEM = "World";
struct cmd_t {short cmd; const char *txt; }; // the struct type
// An array of structs in PROGMEM
static const cmd_t cmds[] PROGMEM = {
{2, cmd_0_txt},
{2, cmd_1_txt},
};
void setup()
{
Serial.begin( 9600 );
Serial.println( F("Test") );
for (uint8_t i=0; i < sizeof(cmds)/sizeof(cmds[0]); i++) {
// First, read the PROGMEM txt member (a pointer to the text)
const char *ptr = (const char *) pgm_read_word( &cmds[i].txt ); // cast required
// Next, read each text character from that PROGMEM location
for (;;) {
char c = pgm_read_byte( ptr++ );
if (!c)
break;
Serial.print( c );
}
Serial.println();
}
}
void loop()
{}

error: expected identifier before '_Bool'

I previously had the following code when dealing with my sync tuple:
static void sync_tuple_changed_callback(const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) {
persist_write_bool(key,new_tuple->value->bool);
}
However, I just tried building this (in Cloud Pebble), and got the error:
../src/main.c: In function 'sync_tuple_changed_callback':
../src/main.c:25:44: error: expected identifier before '_Bool'
What's going on?
There is no bool member of the value union - your best bet is to use the uint8 member instead, passing 1 for true and 0 for false:
static void sync_tuple_changed_callback(const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) {
persist_write_bool(key,new_tuple->value->uint8 != 0);
}

Using QList as the input for QwtPlotCurves setSamples

I have two QList (XList, YList) which saves the dynamic data. I want to use these as the input of the QwtPlotCurves by setSamples. After I check the documentation:
void setSamples (const double *xData, const double *yData, int size)
void setSamples (const QVector< double > &xData, const QVector< double > &yData)
void setSamples (const QVector< QPointF > &)
It seems do not support QList. Is there workaround to this or do I have to overload it?
Julio
There is method in QList that returns a const QVector.
So:
setSamples( XList.toVector(), YList.toVector() )
Check QVector QList::toVector () const

How to use Qlist to create a user profile model with about 15 different fields

I know some professional developers are shaking there heads with disappointment... Im just trying to wrap my head around how to use Qlist to store multiple types of data within one table. And I know I will use QTableModel to set this data right? Building a billing app. Basic ideas or links will be fine... Thanks guys
Here is a good read for the best practices for Model/View Programming in Qt.
The examples and links at the bottom of the above link are nice, too.
As for storing multiple types, I would look at QVariant and QSettings; using QVariant is referenced many times in the Model/View Programming in Qt.
QVariant is very robust and works well with many different types. It is core in reading values out of QSettings. Be sure to read the description of QSettings for more ideas.
QBitArray toBitArray () const
bool toBool () const
QByteArray toByteArray () const
QChar toChar () const
QDate toDate () const
QDateTime toDateTime () const
double toDouble ( bool * ok = 0 ) const
QEasingCurve toEasingCurve () const
float toFloat ( bool * ok = 0 ) const
QHash<QString, QVariant> toHash () const
int toInt ( bool * ok = 0 ) const
QLine toLine () const
QLineF toLineF () const
QList<QVariant> toList () const
QLocale toLocale () const
qlonglong toLongLong ( bool * ok = 0 ) const
QMap<QString, QVariant> toMap () const
QPoint toPoint () const
QPointF toPointF () const
qreal toReal ( bool * ok = 0 ) const
QRect toRect () const
QRectF toRectF () const
QRegExp toRegExp () const
QSize toSize () const
QSizeF toSizeF () const
QString toString () const
QStringList toStringList () const
QTime toTime () const
uint toUInt ( bool * ok = 0 ) const
qulonglong toULongLong ( bool * ok = 0 ) const
QUrl toUrl () const
Another good option is QString. It has a number of built in conversions also:
QByteArray toAscii () const
QString toCaseFolded () const
double toDouble ( bool * ok = 0 ) const
float toFloat ( bool * ok = 0 ) const
int toInt ( bool * ok = 0, int base = 10 ) const
QByteArray toLatin1 () const
QByteArray toLocal8Bit () const
long toLong ( bool * ok = 0, int base = 10 ) const
qlonglong toLongLong ( bool * ok = 0, int base = 10 ) const
QString toLower () const
short toShort ( bool * ok = 0, int base = 10 ) const
std::string toStdString () const
std::wstring toStdWString () const
uint toUInt ( bool * ok = 0, int base = 10 ) const
ulong toULong ( bool * ok = 0, int base = 10 ) const
qulonglong toULongLong ( bool * ok = 0, int base = 10 ) const
ushort toUShort ( bool * ok = 0, int base = 10 ) const
QVector<uint> toUcs4 () const
QString toUpper () const
QByteArray toUtf8 () const
int toWCharArray ( wchar_t * array ) const
When saving numerical values to a QString, be sure to use QString::number().

Resources