Until now, the TCP options would all be stored in the Packet structure.
The commonly used ones (wscale, ts, sack, sackok and mss*) then had a
pointer to the position in the option array. Overall this option array
was large. About 360 bytes on 64bit systems. Since no part of the engine
would every access this array other than through the common short cuts,
this was actually just wasteful.
This patch changes the approach. It stores just the common ones in the
packet. The rest is gone. This shrinks the packet structure with almost
300 bytes.
* even though mss wasn't actually used
#include "pkt-var.h"
#include "host.h"
+#define SET_OPTS(dst, src) \
+ (dst).type = (src).type; \
+ (dst).len = (src).len; \
+ (dst).data = (src).data
+
static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len)
{
+ uint8_t tcp_opt_cnt = 0;
+ TCPOpt tcp_opts[TCP_OPTMAX];
+
uint16_t plen = len;
while (plen)
{
return -1;
}
- p->TCP_OPTS[p->TCP_OPTS_CNT].type = *pkt;
- p->TCP_OPTS[p->TCP_OPTS_CNT].len = *(pkt+1);
+ tcp_opts[tcp_opt_cnt].type = *pkt;
+ tcp_opts[tcp_opt_cnt].len = *(pkt+1);
if (plen > 2)
- p->TCP_OPTS[p->TCP_OPTS_CNT].data = (pkt+2);
+ tcp_opts[tcp_opt_cnt].data = (pkt+2);
else
- p->TCP_OPTS[p->TCP_OPTS_CNT].data = NULL;
+ tcp_opts[tcp_opt_cnt].data = NULL;
/* we are parsing the most commonly used opts to prevent
* us from having to walk the opts list for these all the
* time. */
- switch (p->TCP_OPTS[p->TCP_OPTS_CNT].type) {
+ switch (tcp_opts[tcp_opt_cnt].type) {
case TCP_OPT_WS:
- if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_WS_LEN) {
+ if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_WS_LEN) {
ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
- if (p->tcpvars.ws != NULL) {
+ if (p->tcpvars.ws.type != 0) {
ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE);
} else {
- p->tcpvars.ws = &p->TCP_OPTS[p->TCP_OPTS_CNT];
+ SET_OPTS(p->tcpvars.ws, tcp_opts[tcp_opt_cnt]);
}
}
break;
case TCP_OPT_MSS:
- if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_MSS_LEN) {
+ if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_MSS_LEN) {
ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
- if (p->tcpvars.mss != NULL) {
+ if (p->tcpvars.mss.type != 0) {
ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE);
} else {
- p->tcpvars.mss = &p->TCP_OPTS[p->TCP_OPTS_CNT];
+ SET_OPTS(p->tcpvars.mss, tcp_opts[tcp_opt_cnt]);
}
}
break;
case TCP_OPT_SACKOK:
- if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_SACKOK_LEN) {
+ if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_SACKOK_LEN) {
ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
- if (p->tcpvars.sackok != NULL) {
+ if (p->tcpvars.sackok.type != 0) {
ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE);
} else {
- p->tcpvars.sackok = &p->TCP_OPTS[p->TCP_OPTS_CNT];
+ SET_OPTS(p->tcpvars.sackok, tcp_opts[tcp_opt_cnt]);
}
}
break;
case TCP_OPT_TS:
- if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_TS_LEN) {
+ if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_TS_LEN) {
ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
- if (p->tcpvars.ts != NULL) {
+ if (p->tcpvars.ts.type != 0) {
ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE);
} else {
- p->tcpvars.ts = &p->TCP_OPTS[p->TCP_OPTS_CNT];
+ SET_OPTS(p->tcpvars.ts, tcp_opts[tcp_opt_cnt]);
}
}
break;
case TCP_OPT_SACK:
- SCLogDebug("SACK option, len %u", p->TCP_OPTS[p->TCP_OPTS_CNT].len);
- if (p->TCP_OPTS[p->TCP_OPTS_CNT].len < TCP_OPT_SACK_MIN_LEN ||
- p->TCP_OPTS[p->TCP_OPTS_CNT].len > TCP_OPT_SACK_MAX_LEN ||
- !((p->TCP_OPTS[p->TCP_OPTS_CNT].len - 2) % 8 == 0))
+ SCLogDebug("SACK option, len %u", tcp_opts[tcp_opt_cnt].len);
+ if (tcp_opts[tcp_opt_cnt].len < TCP_OPT_SACK_MIN_LEN ||
+ tcp_opts[tcp_opt_cnt].len > TCP_OPT_SACK_MAX_LEN ||
+ !((tcp_opts[tcp_opt_cnt].len - 2) % 8 == 0))
{
ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
- if (p->tcpvars.sack != NULL) {
+ if (p->tcpvars.sack.type != 0) {
ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE);
} else {
- p->tcpvars.sack = &p->TCP_OPTS[p->TCP_OPTS_CNT];
+ SET_OPTS(p->tcpvars.sack, tcp_opts[tcp_opt_cnt]);
}
}
break;
}
- pkt += p->TCP_OPTS[p->TCP_OPTS_CNT].len;
- plen -= (p->TCP_OPTS[p->TCP_OPTS_CNT].len);
- p->TCP_OPTS_CNT++;
+ pkt += tcp_opts[tcp_opt_cnt].len;
+ plen -= (tcp_opts[tcp_opt_cnt].len);
+ tcp_opt_cnt++;
}
}
return 0;
#ifdef DEBUG
SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s",
GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len,
- p->tcpvars.sackok ? "SACKOK " : "", p->tcpvars.sack ? "SACK " : "",
- p->tcpvars.ws ? "WS " : "", p->tcpvars.ts ? "TS " : "",
- p->tcpvars.mss ? "MSS " : "");
+ TCP_HAS_SACKOK(p) ? "SACKOK " : "", TCP_HAS_SACK(p) ? "SACK " : "",
+ TCP_HAS_WSCALE(p) ? "WS " : "", TCP_HAS_TS(p) ? "TS " : "",
+ TCP_HAS_MSS(p) ? "MSS " : "");
#endif
/* Flow is an integral part of us */
goto end;
}
- if (p->tcpvars.sack == NULL) {
+ if (!TCP_HAS_SACK(p)) {
printf("tcp packet sack not decoded: ");
goto end;
}
/** Max valid wscale value. */
#define TCP_WSCALE_MAX 14
-#define TCP_OPTS tcpvars.tcp_opts
-#define TCP_OPTS_CNT tcpvars.tcp_opt_cnt
-
#define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4)
#define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f)
#define TCP_GET_RAW_SRC_PORT(tcph) ntohs((tcph)->th_sport)
/** macro for getting the first timestamp from the packet. Timestamp is in host
* order and either returned from the cache or from the packet directly. */
#define TCP_GET_TSVAL(p) \
- (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts->data))
+ (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts.data))
/** macro for getting the second timestamp from the packet. Timestamp is in
* host order and either returned from the cache or from the packet directly. */
#define TCP_GET_TSECR(p) \
- (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts->data+4)))
+ (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts.data+4)))
+
+#define TCP_HAS_WSCALE(p) ((p)->tcpvars.ws.type == TCP_OPT_WS)
+#define TCP_HAS_SACK(p) ((p)->tcpvars.sack.type == TCP_OPT_SACK)
+#define TCP_HAS_SACKOK(p) ((p)->tcpvars.sackok.type == TCP_OPT_SACKOK)
+#define TCP_HAS_TS(p) ((p)->tcpvars.ts.type == TCP_OPT_TS)
+#define TCP_HAS_MSS(p) ((p)->tcpvars.mss.type == TCP_OPT_MSS)
/** macro for getting the wscale from the packet. */
-#define TCP_GET_WSCALE(p) ((p)->tcpvars.ws ? (((*(uint8_t *)(p)->tcpvars.ws->data) <= TCP_WSCALE_MAX) ? (*(uint8_t *)((p)->tcpvars.ws->data)) : 0) : 0)
+#define TCP_GET_WSCALE(p) (TCP_HAS_WSCALE((p)) ? \
+ (((*(uint8_t *)(p)->tcpvars.ws.data) <= TCP_WSCALE_MAX) ? \
+ (*(uint8_t *)((p)->tcpvars.ws.data)) : 0) : 0)
-#define TCP_GET_SACKOK(p) ((p)->tcpvars.sackok ? 1 : 0)
-#define TCP_GET_SACK_PTR(p) (p)->tcpvars.sack ? (p)->tcpvars.sack->data : NULL
-#define TCP_GET_SACK_CNT(p) ((p)->tcpvars.sack ? (((p)->tcpvars.sack->len - 2) / 8) : 0)
+#define TCP_GET_SACKOK(p) (TCP_HAS_SACKOK((p)) ? 1 : 0)
+#define TCP_GET_SACK_PTR(p) TCP_HAS_SACK((p)) ? (p)->tcpvars.sack.data : NULL
+#define TCP_GET_SACK_CNT(p) (TCP_HAS_SACK((p)) ? (((p)->tcpvars.sack.len - 2) / 8) : 0)
#define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph)
#define TCP_GET_HLEN(p) (TCP_GET_OFFSET((p)) << 2)
typedef struct TCPVars_
{
- uint8_t tcp_opt_cnt;
- TCPOpt tcp_opts[TCP_OPTMAX];
-
- /* ptrs to commonly used and needed opts */
- TCPOpt *ts;
- TCPOpt *sack;
- TCPOpt *sackok;
- TCPOpt *ws;
- TCPOpt *mss;
+ /* commonly used and needed opts */
+ TCPOpt ts;
+ TCPOpt sack;
+ TCPOpt sackok;
+ TCPOpt ws;
+ TCPOpt mss;
} TCPVars;
#define CLEAR_TCP_PACKET(p) { \
(p)->tcph = NULL; \
(p)->level4_comp_csum = -1; \
- (p)->tcpvars.tcp_opt_cnt = 0; \
- (p)->tcpvars.ts = NULL; \
- (p)->tcpvars.sack = NULL; \
- (p)->tcpvars.sackok = NULL; \
- (p)->tcpvars.ws = NULL; \
- (p)->tcpvars.mss = NULL; \
+ (p)->tcpvars.ts.type = 0; \
+ (p)->tcpvars.sack.type = 0; \
+ (p)->tcpvars.sackok.type = 0; \
+ (p)->tcpvars.ws.type = 0; \
+ (p)->tcpvars.mss.type = 0; \
}
void DecodeTCPRegisterTests(void);
/** If the client has a wscale option the server had it too,
* so set the wscale for the server to max. Otherwise none
* will have the wscale opt just like it should. */
- if (p->tcpvars.ws != NULL) {
+ if (TCP_HAS_WSCALE(p)) {
ssn->client.wscale = TCP_GET_WSCALE(p);
ssn->server.wscale = TCP_WSCALE_MAX;
}
/* Set the timestamp value for both streams, if packet has timestamp
* option enabled.*/
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
ssn->server.last_ts = TCP_GET_TSVAL(p);
ssn->client.last_ts = TCP_GET_TSECR(p);
SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
/* Set the stream timestamp value, if packet has timestamp option
* enabled. */
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
ssn->client.last_ts = TCP_GET_TSVAL(p);
- SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts,
- ssn->client.last_ts);
+ SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts);
if (ssn->client.last_ts == 0)
ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
}
ssn->server.window = TCP_GET_WINDOW(p);
- if (p->tcpvars.ws != NULL) {
+ if (TCP_HAS_WSCALE(p)) {
ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
ssn->server.wscale = TCP_GET_WSCALE(p);
}
/* Set the timestamp value for both streams, if packet has timestamp
* option enabled.*/
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
ssn->client.last_ts = TCP_GET_TSVAL(p);
ssn->server.last_ts = TCP_GET_TSECR(p);
SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
if (TCP_GET_SACKOK(p) == 1)
q->flags |= STREAMTCP_QUEUE_FLAG_SACK;
- if (p->tcpvars.ws != NULL) {
+ if (TCP_HAS_WSCALE(p)) {
q->flags |= STREAMTCP_QUEUE_FLAG_WS;
q->wscale = TCP_GET_WSCALE(p);
}
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
q->flags |= STREAMTCP_QUEUE_FLAG_TS;
q->ts = TCP_GET_TSVAL(p);
}
/* Set the timestamp values used to validate the timestamp of
* received packets. */
- if ((p->tcpvars.ts != NULL) &&
+ if ((TCP_HAS_TS(p)) &&
(ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
{
ssn->client.last_ts = TCP_GET_TSVAL(p);
/** check for the presense of the ws ptr to determine if we
* support wscale at all */
if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
- (p->tcpvars.ws != NULL))
+ (TCP_HAS_WSCALE(p)))
{
ssn->server.wscale = TCP_GET_WSCALE(p);
} else {
/* Set the stream timestamp value, if packet has timestamp
* option enabled. */
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
ssn->server.last_ts = TCP_GET_TSVAL(p);
- SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn,
- p->tcpvars.ts, ssn->server.last_ts);
+ SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts);
if (ssn->server.last_ts == 0)
ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
}
ssn->server.window = TCP_GET_WINDOW(p);
- if (p->tcpvars.ws != NULL) {
+ if (TCP_HAS_WSCALE(p)) {
ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
ssn->server.wscale = TCP_GET_WSCALE(p);
} else {
/* Set the timestamp values used to validate the timestamp of
* received packets.*/
- if (p->tcpvars.ts != NULL &&
+ if (TCP_HAS_TS(p) &&
(ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
{
ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
StreamTcpSetOSPolicy(receiver_stream, p);
}
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
uint32_t ts = TCP_GET_TSVAL(p);
uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
uint32_t last_ts = sender_stream->last_ts;
StreamTcpSetOSPolicy(receiver_stream, p);
}
- if (p->tcpvars.ts != NULL) {
+ if (TCP_HAS_TS(p)) {
uint32_t ts = TCP_GET_TSVAL(p);
if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
StreamTcpThread stt;
TCPHdr tcph;
uint8_t payload[1] = {0x42};
- TCPVars tcpvars;
- TCPOpt ts;
uint32_t data[2];
PacketQueue pq;
memset(&tv, 0, sizeof (ThreadVars));
memset(&stt, 0, sizeof(StreamTcpThread));
memset(&tcph, 0, sizeof(TCPHdr));
- memset(&tcpvars, 0, sizeof(TCPVars));
- memset(&ts, 0, sizeof(TCPOpt));
FLOW_INITIALIZE(&f);
p->flow = &f;
data[0] = htonl(10);
data[1] = htonl(11);
- ts.type = TCP_OPT_TS;
- ts.len = 10;
- ts.data = (uint8_t *)data;
- tcpvars.ts = &ts;
- p->tcpvars = tcpvars;
+ p->tcpvars.ts.type = TCP_OPT_TS;
+ p->tcpvars.ts.len = 10;
+ p->tcpvars.ts.data = (uint8_t *)data;
p->payload = payload;
p->payload_len = 1;
p->flowflags = FLOW_PKT_TOSERVER;
data[0] = htonl(2);
- p->tcpvars.ts->data = (uint8_t *)data;
+ p->tcpvars.ts.data = (uint8_t *)data;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11) {
StreamTcpThread stt;
TCPHdr tcph;
uint8_t payload[1] = {0x42};
- TCPVars tcpvars;
- TCPOpt ts;
uint32_t data[2];
memset(p, 0, SIZE_OF_PACKET);
memset(&tv, 0, sizeof (ThreadVars));
memset(&stt, 0, sizeof(StreamTcpThread));
memset(&tcph, 0, sizeof(TCPHdr));
- memset(&tcpvars, 0, sizeof(TCPVars));
- memset(&ts, 0, sizeof(TCPOpt));
FLOW_INITIALIZE(&f);
p->flow = &f;
data[0] = htonl(10);
data[1] = htonl(11);
- ts.type = TCP_OPT_TS;
- ts.len = 10;
- ts.data = (uint8_t *)data;
- tcpvars.ts = &ts;
- p->tcpvars = tcpvars;
+ p->tcpvars.ts.type = TCP_OPT_TS;
+ p->tcpvars.ts.len = 10;
+ p->tcpvars.ts.data = (uint8_t *)data;
p->payload = payload;
p->payload_len = 1;
p->flowflags = FLOW_PKT_TOSERVER;
data[0] = htonl(12);
- p->tcpvars.ts->data = (uint8_t *)data;
+ p->tcpvars.ts.data = (uint8_t *)data;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;