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.
pull/7430/head
Scott Jordan 5 years ago committed by Victor Julien
parent 6f06f7c22c
commit 6cfc3343e7

@ -575,17 +575,11 @@ static void PcapLogDumpSegments(
PcapLogThreadData *td, PcapLogCompressionData *connp, const Packet *p) PcapLogThreadData *td, PcapLogCompressionData *connp, const Packet *p)
{ {
uint8_t flag; uint8_t flag;
/* check which side is packet */ flag = STREAM_DUMP_HEADERS;
if (p->flowflags & FLOW_PKT_TOSERVER) {
flag = STREAM_DUMP_TOCLIENT;
} else {
flag = STREAM_DUMP_TOSERVER;
}
flag |= STREAM_DUMP_HEADERS;
/* Loop on segment from this side */ /* Loop on segment from this side */
struct PcapLogCallbackContext data = { td->pcap_log, connp, td->buf }; 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 #else
PcapLogDumpSegments(td, NULL, p); PcapLogDumpSegments(td, NULL, p);
#endif #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);
}
} }
} }

@ -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, * \note when stream engine is running in inline mode all segments are used,
* in IDS/non-inline mode only ack'd segments are iterated. * in IDS/non-inline mode only ack'd segments are iterated.
* *
* \note Must be called under flow lock. * \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 * \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; 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) int StreamTcpBypassEnabled(void)
{ {
return (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS); return (stream_config.flags & STREAMTCP_INIT_FLAG_BYPASS);

@ -124,6 +124,8 @@ Packet *StreamTcpPseudoSetup(Packet *, uint8_t *, uint32_t);
int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, int StreamTcpSegmentForEach(const Packet *p, uint8_t flag,
StreamSegmentCallback CallbackFunc, StreamSegmentCallback CallbackFunc,
void *data); void *data);
int StreamTcpSegmentForSession(
const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data);
void StreamTcpReassembleConfigEnableOverlapCheck(void); void StreamTcpReassembleConfigEnableOverlapCheck(void);
void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size); void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size);

@ -30,9 +30,10 @@
#include "stream-tcp.h" #include "stream-tcp.h"
#include "flow-util.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. * 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 * \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; 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;
}

@ -38,6 +38,8 @@ typedef int (*StreamSegmentCallback)(
int StreamSegmentForEach(const Packet *p, uint8_t flag, int StreamSegmentForEach(const Packet *p, uint8_t flag,
StreamSegmentCallback CallbackFunc, StreamSegmentCallback CallbackFunc,
void *data); void *data);
int StreamSegmentForSession(
const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data);
#endif /* __STREAM_H__ */ #endif /* __STREAM_H__ */

Loading…
Cancel
Save