From: Scott Jordan Date: Wed, 17 Feb 2021 22:36:42 +0000 (-0600) Subject: log/pcap: dump segments of both sides of tcp session. X-Git-Tag: suricata-7.0.0-beta1~568 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6cfc3343e771efef26e97afbc7398b5062d1213b;p=thirdparty%2Fsuricata.git log/pcap: dump segments of both sides of tcp session. This patch updates tcp segment dumping to dump segments from both sides of the session in order when capturing alerts and tags. --- diff --git a/src/log-pcap.c b/src/log-pcap.c index 631031e080..88c4f14be3 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -575,17 +575,11 @@ static void PcapLogDumpSegments( PcapLogThreadData *td, PcapLogCompressionData *connp, const Packet *p) { uint8_t flag; - /* check which side is packet */ - if (p->flowflags & FLOW_PKT_TOSERVER) { - flag = STREAM_DUMP_TOCLIENT; - } else { - flag = STREAM_DUMP_TOSERVER; - } - flag |= STREAM_DUMP_HEADERS; + flag = STREAM_DUMP_HEADERS; /* Loop on segment from this side */ struct PcapLogCallbackContext data = { td->pcap_log, connp, td->buf }; - StreamSegmentForEach(p, flag, PcapLogSegmentCallback, (void *)&data); + StreamSegmentForSession(p, flag, PcapLogSegmentCallback, (void *)&data); } /** @@ -702,6 +696,21 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) #else PcapLogDumpSegments(td, NULL, p); #endif + /* PcapLogDumpSegment has writtens over the PcapLogData variables so need to update */ + pl->h->ts.tv_sec = p->ts.tv_sec; + pl->h->ts.tv_usec = p->ts.tv_usec; + if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) { + rp = p->root; + SCMutexLock(&rp->tunnel_mutex); + pl->h->caplen = GET_PKT_LEN(rp); + pl->h->len = GET_PKT_LEN(rp); + len = sizeof(*pl->h) + GET_PKT_LEN(rp); + SCMutexUnlock(&rp->tunnel_mutex); + } else { + pl->h->caplen = GET_PKT_LEN(p); + pl->h->len = GET_PKT_LEN(p); + len = sizeof(*pl->h) + GET_PKT_LEN(p); + } } } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 42c120fd9b..4fa19c74a7 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -6296,12 +6296,13 @@ void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Pack } /** - * \brief Run callback function on each TCP segment + * \brief Run callback function on each TCP segment in a single direction. * * \note when stream engine is running in inline mode all segments are used, * in IDS/non-inline mode only ack'd segments are iterated. * * \note Must be called under flow lock. + * \var flag determines the direction to run callback on (either to server or to client). * * \return -1 in case of error, the number of segment in case of success * @@ -6354,6 +6355,100 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback return cnt; } +/** + * \brief Run callback function on each TCP segment in both directions of a session. + * + * \note when stream engine is running in inline mode all segments are used, + * in IDS/non-inline mode only ack'd segments are iterated. + * + * \note Must be called under flow lock. + * + * \return -1 in case of error, the number of segment in case of success + * + */ +int StreamTcpSegmentForSession( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) +{ + int ret = 0; + int cnt = 0; + + if (p->flow == NULL) + return 0; + + TcpSession *ssn = (TcpSession *)p->flow->protoctx; + + if (ssn == NULL) { + return -1; + } + + TcpStream *server_stream = &(ssn->server); + TcpStream *client_stream = &(ssn->client); + + TcpSegment *server_node = RB_ROOT(&(server_stream->seg_tree)); + TcpSegment *client_node = RB_ROOT(&(client_stream->seg_tree)); + if (server_node == NULL && client_node == NULL) { + return cnt; + } + + while (server_node != NULL || client_node != NULL) { + const uint8_t *seg_data; + uint32_t seg_datalen; + if (server_node == NULL) { + /* + * This means the server side RB Tree has been completely searched, + * thus all that remains is to dump the TcpSegments on the client + * side. + */ + StreamingBufferSegmentGetData( + &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen); + ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen); + if (ret != 1) { + SCLogDebug("Callback function has failed"); + return -1; + } + client_node = TCPSEG_RB_NEXT(client_node); + } else if (client_node == NULL) { + /* + * This means the client side RB Tree has been completely searched, + * thus all that remains is to dump the TcpSegments on the server + * side. + */ + StreamingBufferSegmentGetData( + &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen); + ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen); + if (ret != 1) { + SCLogDebug("Callback function has failed"); + return -1; + } + server_node = TCPSEG_RB_NEXT(server_node); + } else { + if (TIMEVAL_EARLIER( + client_node->pcap_hdr_storage->ts, server_node->pcap_hdr_storage->ts)) { + StreamingBufferSegmentGetData( + &client_stream->sb, &client_node->sbseg, &seg_data, &seg_datalen); + ret = CallbackFunc(p, client_node, data, seg_data, seg_datalen); + if (ret != 1) { + SCLogDebug("Callback function has failed"); + return -1; + } + client_node = TCPSEG_RB_NEXT(client_node); + } else { + StreamingBufferSegmentGetData( + &server_stream->sb, &server_node->sbseg, &seg_data, &seg_datalen); + ret = CallbackFunc(p, server_node, data, seg_data, seg_datalen); + if (ret != 1) { + SCLogDebug("Callback function has failed"); + return -1; + } + server_node = TCPSEG_RB_NEXT(server_node); + } + } + + cnt++; + } + return cnt; +} + int StreamTcpBypassEnabled(void) { return (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS); diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 2f3ddb9ec0..7918bf468f 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -124,6 +124,8 @@ Packet *StreamTcpPseudoSetup(Packet *, uint8_t *, uint32_t); int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); +int StreamTcpSegmentForSession( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); void StreamTcpReassembleConfigEnableOverlapCheck(void); void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size); diff --git a/src/stream.c b/src/stream.c index a09f125e35..59cc251f11 100644 --- a/src/stream.c +++ b/src/stream.c @@ -30,9 +30,10 @@ #include "stream-tcp.h" #include "flow-util.h" -/** \brief Run callback for all segments +/** \brief Run callback for all segments in a single direction. * * Must be called under flow lock. + * \var flag determines the direction to run callback on (either to server or to client). * * \return -1 in case of error, the number of segment in case of success */ @@ -53,3 +54,28 @@ int StreamSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback Ca } return 0; } + +/** \brief Run callback for all segments on both directions of the session + * + * Must be called under flow lock. + * + * \return -1 in case of error, the number of segments in case of success. + */ +int StreamSegmentForSession( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data) +{ + switch (p->proto) { + case IPPROTO_TCP: + return StreamTcpSegmentForSession(p, flag, CallbackFunc, data); + break; +#ifdef DEBUG + case IPPROTO_UDP: + SCLogWarning(SC_ERR_UNKNOWN_PROTOCOL, "UDP is currently unsupported"); + break; + default: + SCLogWarning(SC_ERR_UNKNOWN_PROTOCOL, "This protocol is currently unsupported"); + break; +#endif + } + return 0; +} diff --git a/src/stream.h b/src/stream.h index e8f2cad7e0..583747ca55 100644 --- a/src/stream.h +++ b/src/stream.h @@ -38,6 +38,8 @@ typedef int (*StreamSegmentCallback)( int StreamSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); +int StreamSegmentForSession( + const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); #endif /* __STREAM_H__ */