PAWS support and one unittest

remotes/origin/master-1.0.x
Gurvinder Singh 17 years ago committed by Victor Julien
parent 45cb8f5f0c
commit 573027a1ec

@ -360,8 +360,8 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread *
ssn, ssn->server.isn, ssn->server.next_seq, ssn->server.last_ack);
#endif
if (p->tcpvars.ts != NULL) {
ssn->server.last_ts = GET_TIMESTAMP(p->tcpvars.ts->data);
ssn->client.last_ts = GET_TIMESTAMP((p->tcpvars.ts->data) + 4);
ssn->client.last_ts = TCP_GET_TS1(p);
ssn->server.last_ts = TCP_GET_TS2(p);
#ifdef DEBUG
printf("StreamTcpPacketStateNone (%p): ssn->server.last_ts %" PRIu32" ssn->client.last_ts %" PRIu32"\n", ssn, ssn->server.last_ts, ssn->client.last_ts);
#endif
@ -422,8 +422,8 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread *
ssn->server.wscale = TCP_WSCALE_MAX;
if (p->tcpvars.ts != NULL) {
ssn->server.last_ts = GET_TIMESTAMP (p->tcpvars.ts->data);
ssn->client.last_ts = GET_TIMESTAMP ((p->tcpvars.ts->data) + 4);
ssn->client.last_ts = TCP_GET_TS1(p);
ssn->server.last_ts = TCP_GET_TS2(p);
#ifdef DEBUG
printf("StreamTcpPacketStateNone (%p): ssn->server.last_ts %" PRIu32" ssn->client.last_ts %" PRIu32"\n", ssn, ssn->server.last_ts, ssn->client.last_ts);
#endif
@ -681,8 +681,19 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT
case TH_ACK:
case TH_ACK|TH_PUSH:
if (!ValidTimestamp(ssn, p))
return -1;
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
/*XXX GS should we drop the packet or carry on normally. Snort
does not drop it. Snort validate the timestamp based on target OS
should we also use target based validation or keep it general ?*/
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
@ -813,6 +824,20 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpT
case TH_FIN:
case TH_FIN|TH_ACK:
case TH_FIN|TH_ACK|TH_PUSH:
/*XXX GS i have replicated this check for each state and their cases
we can either check it on each state or check for particular case.
if check for each state only, then in some cases we will check where we
don't even need like checking for SYN packet in TCP_ESTABLISHED state.*/
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
#ifdef DEBUG
printf("StreamTcpPacketStateEstablished (%p): FIN received SEQ %" PRIu32 ", last ACK %" PRIu32 ", next win %" PRIu32 ", win %" PRIu32 "\n",
ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, ssn->server.window);
@ -976,6 +1001,17 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpThre
switch (p->tcph->th_flags) {
case TH_ACK:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateFinWait1 (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1016,6 +1052,17 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpThre
case TH_FIN:
case TH_FIN|TH_ACK:
case TH_FIN|TH_ACK|TH_PUSH:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateFinWait1 (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1109,6 +1156,17 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpThre
switch (p->tcph->th_flags) {
case TH_ACK:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateFinWait2 (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1176,6 +1234,17 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpThre
return -1;
break;
case TH_FIN:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateFinWait2 (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1258,6 +1327,17 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpThrea
switch(p->tcph->th_flags) {
case TH_ACK:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateClosing (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1341,6 +1421,17 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpThr
switch(p->tcph->th_flags) {
case TH_FIN:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOCLIENT(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateCloseWait (%p): pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1396,6 +1487,17 @@ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, StreamTcpThrea
switch(p->tcph->th_flags) {
case TH_ACK:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateLastAck (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1447,6 +1549,17 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpThre
switch(p->tcph->th_flags) {
case TH_ACK:
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p)) {
#ifdef DEBUG
printf("StreamTcpPacketStateTimeWait (%p): pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ", ACK %" PRIu32 "\n",
@ -1655,12 +1768,22 @@ static int ValidReset(TcpSession *ssn, Packet *p) {
uint8_t os_policy;
if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
if (p->tcpvars.ts != NULL) {
if (!ValidTimestamp(ssn, p)) {
return -1;
}
} else {
printf("Packet does not have Timestamp on connection with Timestamping enabled !!\n");
}
}
if (PKT_IS_TOSERVER(p))
os_policy = ssn->server.os_policy;
else
os_policy = ssn->client.os_policy;
switch(os_policy) {
switch (os_policy) {
case OS_POLICY_HPUX11:
if(PKT_IS_TOSERVER(p)){
if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
@ -1791,13 +1914,31 @@ int StreamTcpGetFlowState(void *s) {
}
static int ValidTimestamp (TcpSession *ssn, Packet *p) {
/*XXX GS its WIP*/
if (!(ssn->flags & STREAMTCP_FLAG_TIMESTAMP)) {
return 1;
} else {
TcpStream *stream;
uint8_t ret = 1;
if (PKT_IS_TOSERVER(p))
stream = &ssn->client;
else
stream = &ssn->server;
if ((int32_t) (TCP_GET_TS1(p) - stream->last_ts) < 0) {
printf("Timestamp is not valid stream->last_ts %" PRIu32 " p->tcpvars->ts %" PRIu32 "\n", stream->last_ts, TCP_GET_TS1(p));
ret = 0;
} else if ((stream->last_pkt_ts != 0) && (((uint32_t) p->ts.tv_sec) > stream->last_pkt_ts + PAWS_24DAYS)) {
printf("Packet is not valid stream->last_pkt_ts %" PRIu32 " p->ts.tv_sec %" PRIu32 "\n", stream->last_pkt_ts, (uint32_t)p->ts.tv_sec);
ret = 0;
}
return 1;
if (ret == 0) {
if ((SEQ_EQ(stream->next_seq, TCP_GET_SEQ(p)))
&& (((uint32_t) p->ts.tv_sec > (stream->last_pkt_ts + PAWS_24DAYS)))) {
stream->last_ts = TCP_GET_TS1(p);
stream->last_pkt_ts = p->ts.tv_sec;
ret = 1;
}
}
return ret;
}
#ifdef UNITTESTS
@ -2208,6 +2349,91 @@ end:
return ret;
}
/**
* \test Test the working on PAWS. The packet will be dropped by stream, as
* its timestamp is old, although the segment is in the window.
*
* \retval On success it returns 1 and on failure 0.
*/
static int StreamTcpTest07 (void) {
Packet p;
Flow f;
ThreadVars tv;
StreamTcpThread stt;
TCPHdr tcph;
u_int8_t payload[1] = {0x42};
TCPVars tcpvars;
TCPOpt ts;
uint8_t len = 10;
uint8_t data[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x37, 0x38, 0x39};
memset (&p, 0, sizeof(Packet));
memset (&f, 0, sizeof(Flow));
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));
p.flow = &f;
int ret = 0;
StreamTcpInitConfig(TRUE);
/* prevent L7 from kicking in */
StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 4096);
StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 4096);
StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
tcph.th_win = htons(5480);
tcph.th_seq = htonl(10);
tcph.th_ack = htonl(20);
tcph.th_flags = TH_ACK|TH_PUSH;
p.tcph = &tcph;
ts.type = TCP_OPT_TS;
ts.len = len;
ts.data = data;
tcpvars.ts = &ts;
p.tcpvars = tcpvars;
p.payload = payload;
p.payload_len = 1;
if (StreamTcpPacket(&tv, &p, &stt) == -1)
goto end;
printf ("the timestamp values are client %"PRIu32" server %" PRIu32 "\n", TCP_GET_TS1(&p), TCP_GET_TS2(&p));
p.tcph->th_seq = htonl(11);
p.tcph->th_ack = htonl(23);
p.tcph->th_flags = TH_ACK|TH_PUSH;
p.flowflags = FLOW_PKT_TOSERVER;
data[0] = 0x11;
data[1] = 0x12;
data[2] = 0x11;
data[3] = 0x11;
p.tcpvars.ts->data = data;
if (StreamTcpPacket(&tv, &p, &stt) == -1)
goto end;
printf ("the timestamp values are client %"PRIu32" server %" PRIu32 "\n", TCP_GET_TS1(&p), TCP_GET_TS2(&p));
if (((TcpSession *)(p.flow->protoctx))->client.next_seq != 11)
goto end;
StreamTcpSessionPktFree(&p);
ret = 1;
end:
StreamTcpFreeConfig(TRUE);
return ret;
}
#endif /* UNITTESTS */
void StreamTcpRegisterTests (void) {
@ -2218,6 +2444,7 @@ void StreamTcpRegisterTests (void) {
UtRegisterTest("StreamTcpTest04 -- SYN/ACK missed MidStream session", StreamTcpTest04, 1);
UtRegisterTest("StreamTcpTest05 -- 3WHS missed MidStream session", StreamTcpTest05, 1);
UtRegisterTest("StreamTcpTest06 -- FIN, RST message MidStream session", StreamTcpTest06, 1);
UtRegisterTest("StreamTcpTest07 -- PAWS", StreamTcpTest07, 1);
/* set up the reassembly tests as well */
StreamTcpReassembleRegisterTests();
#endif /* UNITTESTS */

Loading…
Cancel
Save