|
|
|
|
@ -113,6 +113,21 @@ static int DecodeTCPOptions(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t le
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
|
{
|
|
|
|
|
DECODER_SET_EVENT(p,TCP_OPT_INVALID_LEN);
|
|
|
|
|
} else {
|
|
|
|
|
if (p->tcpvars.sack != NULL) {
|
|
|
|
|
DECODER_SET_EVENT(p,TCP_OPT_DUPLICATE);
|
|
|
|
|
} else {
|
|
|
|
|
p->tcpvars.sack = &p->TCP_OPTS[p->TCP_OPTS_CNT];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkt += p->TCP_OPTS[p->TCP_OPTS_CNT].len;
|
|
|
|
|
@ -411,6 +426,72 @@ end:
|
|
|
|
|
SCFree(p);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int TCPGetSackTest01(void)
|
|
|
|
|
{
|
|
|
|
|
int retval = 0;
|
|
|
|
|
static uint8_t raw_tcp[] = {
|
|
|
|
|
0x00, 0x50, 0x06, 0xa6, 0xfa, 0x87, 0x0b, 0xf5,
|
|
|
|
|
0xf1, 0x59, 0x02, 0xe0, 0xa0, 0x10, 0x3e, 0xbc,
|
|
|
|
|
0x1d, 0xe7, 0x00, 0x00, 0x01, 0x01, 0x05, 0x12,
|
|
|
|
|
0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64,
|
|
|
|
|
0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 };
|
|
|
|
|
static uint8_t raw_tcp_sack[] = {
|
|
|
|
|
0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64,
|
|
|
|
|
0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 };
|
|
|
|
|
Packet *p = SCMalloc(SIZE_OF_PACKET);
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
IPV4Hdr ip4h;
|
|
|
|
|
ThreadVars tv;
|
|
|
|
|
DecodeThreadVars dtv;
|
|
|
|
|
|
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
|
|
|
memset(p, 0, SIZE_OF_PACKET);
|
|
|
|
|
p->pkt = (uint8_t *)(p + 1);
|
|
|
|
|
memset(&dtv, 0, sizeof(DecodeThreadVars));
|
|
|
|
|
memset(&ip4h, 0, sizeof(IPV4Hdr));
|
|
|
|
|
|
|
|
|
|
p->src.family = AF_INET;
|
|
|
|
|
p->dst.family = AF_INET;
|
|
|
|
|
p->ip4h = &ip4h;
|
|
|
|
|
|
|
|
|
|
FlowInitConfig(FLOW_QUIET);
|
|
|
|
|
DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp), NULL);
|
|
|
|
|
FlowShutdown();
|
|
|
|
|
|
|
|
|
|
if (p->tcph == NULL) {
|
|
|
|
|
printf("tcp packet decode failed: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p->tcpvars.sack == NULL) {
|
|
|
|
|
printf("tcp packet sack not decoded: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sack = TCP_GET_SACK_CNT(p);
|
|
|
|
|
if (sack != 2) {
|
|
|
|
|
printf("expected 2 sack records, got %u: ", TCP_GET_SACK_CNT(p));
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t *sackptr = TCP_GET_SACK_PTR(p);
|
|
|
|
|
if (sackptr == NULL) {
|
|
|
|
|
printf("no sack data: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (memcmp(sackptr, raw_tcp_sack, 16) != 0) {
|
|
|
|
|
printf("malformed sack data: ");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retval = 1;
|
|
|
|
|
end:
|
|
|
|
|
SCFree(p);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
|
|
|
|
|
void DecodeTCPRegisterTests(void)
|
|
|
|
|
@ -427,5 +508,6 @@ void DecodeTCPRegisterTests(void)
|
|
|
|
|
UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01, 1);
|
|
|
|
|
UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02, 1);
|
|
|
|
|
UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03, 1);
|
|
|
|
|
UtRegisterTest("TCPGetSackTest01", TCPGetSackTest01, 1);
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
}
|
|
|
|
|
|