/* Copyright (c) 2008 Victor Julien */ /* 2009 Gurvinder Singh */ #include "decode.h" #include #include #include #include #include #include #include #include #include #include #include "eidps.h" #include "debug.h" #include "detect.h" #include "flow.h" #include "threads.h" #include "threadvars.h" #include "tm-modules.h" #include "util-pool.h" #include "util-unittest.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream.h" #include "stream-tcp.h" int StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *); int StreamTcpThreadInit(ThreadVars *, void *, void **); int StreamTcpThreadDeinit(ThreadVars *, void *); void StreamTcpExitPrintStats(ThreadVars *, void *); static int ValidReset(TcpSession * , Packet *); static int StreamTcpHandleFin(TcpSession *, Packet *); void StreamTcpStreamReturntoPool (Packet *); void StreamTcpRegisterTests (void); void *StreamTcpSessionAlloc(void *null) { void *ptr = malloc(sizeof(TcpSession)); if (ptr == NULL) return NULL; memset(ptr, 0, sizeof(TcpSession)); return ptr; } #define StreamTcpSessionFree free static Pool *ssn_pool; static pthread_mutex_t ssn_pool_mutex; void TmModuleStreamTcpRegister (void) { StreamTcpReassembleInit(); tmm_modules[TMM_STREAMTCP].name = "StreamTcp"; tmm_modules[TMM_STREAMTCP].Init = StreamTcpThreadInit; tmm_modules[TMM_STREAMTCP].Func = StreamTcp; tmm_modules[TMM_STREAMTCP].ExitPrintStats = StreamTcpExitPrintStats; tmm_modules[TMM_STREAMTCP].Deinit = StreamTcpThreadDeinit; tmm_modules[TMM_STREAMTCP].RegisterTests = StreamTcpRegisterTests; ssn_pool = PoolInit(262144, 32768, StreamTcpSessionAlloc, NULL, StreamTcpSessionFree); if (ssn_pool == NULL) { exit(1); } pthread_mutex_init(&ssn_pool_mutex, NULL); } typedef struct StreamTcpThread_ { u_int64_t pkts; } StreamTcpThread; /** * \brief Function to handle the TCP_CLOSED or NONE state. The function handles * packets while the session state is None which means a newly * initialized structure, or a fully closed session. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { switch (p->tcph->th_flags) { case TH_SYN: /* get a stream */ mutex_lock(&ssn_pool_mutex); p->flow->stream = PoolGet(ssn_pool); mutex_unlock(&ssn_pool_mutex); TcpSession *ssn = (TcpSession *)p->flow->stream; if (ssn == NULL) return -1; /* set the state */ ssn->state = TCP_SYN_SENT; printf("StreamTcpPacketStateNone (%p): =~ ssn state is now TCP_SYN_SENT\n", ssn); /* set the sequence numbers and window */ ssn->client.isn = TCP_GET_SEQ(p); ssn->client.ra_base_seq = ssn->client.isn; ssn->client.next_seq = ssn->client.isn + 1; ssn->client.window = TCP_GET_WINDOW(p); //ssn->server.last_ack = ssn->client.isn + 1; //ssn->server.last_ack = TCP_GET_ACK(p); printf("StreamTcpPacketStateNone (%p): ssn->client.isn %u, ssn->client.next_seq %u, ssn->SERVER.last_ack %u\n", ssn, ssn->client.isn, ssn->client.next_seq, ssn->server.last_ack); if (p->tcpvars.ws != NULL) { printf("StreamTcpPacketStateNone (%p): p->tcpvars.ws %p, %02x\n", ssn, p->tcpvars.ws, *p->tcpvars.ws->data); ssn->client.wscale = *p->tcpvars.ws->data; } break; default: printf("StreamTcpPacketStateNone: default case\n"); break; } return 0; } /** * \brief Function to handle the TCP_SYN_SENT state. The function handles * SYN, SYN/ACK, RSTpackets and correspondingly changes the connection * state. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch (p->tcph->th_flags) { case TH_SYN: printf("StreamTcpPacketStateSynSent (%p): SYN packet on state SYN_SENT... resent\n", ssn); break; case TH_SYN|TH_ACK: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateSynSent (%p): SYN/ACK received in the wrong direction\n", ssn); return -1; } /* Check if the SYN/ACK packet ack's the earlier * received SYN packet. */ if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) { printf("StreamTcpPacketStateSynSent (%p): ACK mismatch, packet ACK %u != %u from stream\n", ssn, TCP_GET_ACK(p), ssn->client.isn + 1); return -1; } /* update state */ ssn->state = TCP_SYN_RECV; printf("StreamTcpPacketStateSynSent (%p): =~ ssn state is now TCP_SYN_RECV\n", ssn); /* sequence number & window */ ssn->server.isn = TCP_GET_SEQ(p); ssn->server.ra_base_seq = ssn->server.isn; ssn->server.next_seq = ssn->server.isn + 1; ssn->server.window = TCP_GET_WINDOW(p); printf("StreamTcpPacketStateSynSent: (%p): window %u\n", ssn, ssn->server.window); ssn->client.last_ack = TCP_GET_ACK(p); ssn->server.last_ack = ssn->server.isn + 1; if (ssn->client.wscale != 0 && p->tcpvars.ws != NULL) { printf("StreamTcpPacketStateSynSent (%p): p->tcpvars.ws %p, %02x\n", ssn, p->tcpvars.ws, *p->tcpvars.ws->data); ssn->server.wscale = *p->tcpvars.ws->data; } else { ssn->client.wscale = 0; } ssn->server.next_win = ssn->server.last_ack + ssn->server.window; printf("StreamTcpPacketStateSynSent (%p): next_win %u\n", ssn, ssn->server.next_win); printf("StreamTcpPacketStateSynSent (%p): ssn->server.isn %u, ssn->server.next_seq %u, ssn->CLIENT.last_ack %u\n", ssn, ssn->server.isn, ssn->server.next_seq, ssn->client.last_ack); break; case TH_RST: case TH_RST|TH_ACK: /* seq should be 0, win should be 0, ack should be isn +1. * check Snort's stream4/5 for more security*/ if(ValidReset(ssn, p)){ if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) && SEQ_EQ(TCP_GET_WINDOW(p), 0) && SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) { ssn->state = TCP_CLOSED; StreamTcpStreamReturntoPool(p); } } else return -1; break; default: printf("StreamTcpPacketStateSynSent (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_SYN_RECV state. The function handles * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes * the connection state. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch (p->tcph->th_flags) { case TH_SYN: printf("StreamTcpPacketStateSynRecv (%p): SYN packet on state SYN_RECV... resent\n", ssn); break; case TH_SYN|TH_ACK: printf("StreamTcpPacketStateSynRecv (%p): SYN/ACK packet on state SYN_RECV... resent\n", ssn); break; case TH_ACK: if (PKT_IS_TOCLIENT(p)) { printf("StreamTcpPacketStateSynRecv (%p): ACK received in the wrong direction\n", ssn); return -1; } if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) { printf("StreamTcpPacketStateSynRecv (%p): ACK received in the wrong direction\n", ssn); return -1; } printf("StreamTcpPacketStateSynRecv (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); ssn->state = TCP_ESTABLISHED; printf("StreamTcpPacketStateSynRecv (%p): =~ ssn state is now TCP_ESTABLISHED\n", ssn); ssn->client.next_seq += p->payload_len; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->server.last_ack = TCP_GET_ACK(p); ssn->client.next_win = ssn->client.last_ack + ssn->client.window; printf("StreamTcpPacketStateSynRecv (%p): next_win %u\n", ssn, ssn->client.next_win); break; case TH_RST: case TH_RST|TH_ACK: if(ValidReset(ssn, p)) { ssn->state = TCP_CLOSED; StreamTcpStreamReturntoPool(p); } else return -1; break; case TH_FIN: /*FIN is handled in the same way as in TCP_ESTABLISHED case */; if((StreamTcpHandleFin(ssn, p)) == -1) return -1; break; default: printf("StreamTcpPacketStateSynRecv (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_ESTABLISHED state. The function handles * ACK, FIN, RST packets and correspondingly changes the connection * state. The function handles the data inside packets and call * StreamTcpReassembleHandleSegment() to handle the reassembling. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch (p->tcph->th_flags) { case TH_SYN: printf("StreamTcpPacketStateEstablished (%p): SYN packet on state ESTABLISED... resent\n", ssn); break; case TH_SYN|TH_ACK: printf("StreamTcpPacketStateEstablished (%p): SYN/ACK packet on state ESTABLISHED... resent\n", ssn); break; case TH_ACK: case TH_ACK|TH_PUSH: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateEstablished (%p): =+ pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) { ssn->client.next_seq += p->payload_len; printf("StreamTcpPacketStateEstablished (%p): ssn->client.next_seq %u\n", ssn, ssn->client.next_seq); } if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.last_ack) && SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win)) { ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); if (SEQ_GT(ssn->client.last_ack + ssn->client.window, ssn->client.next_win)) { ssn->client.next_win = ssn->client.last_ack + ssn->client.window; printf("StreamTcpPacketStateEstablished (%p): ssn->client.next_win %u\n", ssn, ssn->client.next_win); } StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); } else { printf("StreamTcpPacketStateEstablished (%p): server !!!!! => SEQ mismatch, packet SEQ %u, payload size %u (%u), last_ack %u, next_win %u\n", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.last_ack, ssn->client.next_win); } printf("StreamTcpPacketStateEstablished (%p): next SEQ %u, last ACK %u, next win %u, win %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack, ssn->client.next_win, ssn->client.window); } else { /* implied to client */ printf("StreamTcpPacketStateEstablished (%p): =+ pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) { ssn->server.next_seq += p->payload_len; printf("StreamTcpPacketStateEstablished (%p): ssn->server.next_seq %u\n", ssn, ssn->server.next_seq); } if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.last_ack) && SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win)) { ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); if (SEQ_GT(ssn->server.last_ack + ssn->server.window, ssn->server.next_win)) { ssn->server.next_win = ssn->server.last_ack + ssn->server.window; printf("StreamTcpPacketStateEstablished (%p): ssn->server.next_win %u\n", ssn, ssn->server.next_win); } StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); } else { printf("StreamTcpPacketStateEstablished (%p): client !!!!! => SEQ mismatch, packet SEQ %u, payload size %u (%u), last_ack %u, next_win %u\n", ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->server.last_ack, ssn->server.next_win); } printf("StreamTcpPacketStateEstablished (%p): next SEQ %u, last ACK %u, next win %u, win %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack, ssn->server.next_win, ssn->server.window); } break; case TH_FIN: case TH_FIN|TH_ACK: case TH_FIN|TH_ACK|TH_PUSH: if((StreamTcpHandleFin(ssn, p)) == -1) return -1; break; case TH_RST: case TH_RST|TH_ACK: if(ValidReset(ssn, p)) { if(PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateEstablished (%p): Reset received and state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; /*Similar remote application is closed, so jump to CLOSE_WAIT*/ ssn->client.next_seq = TCP_GET_ACK(p); ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1; printf("StreamTcpPacketStateEstablished (%p): ssn->server.next_seq %u\n", ssn, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateEstablished (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); StreamTcpStreamReturntoPool(p); } else { printf("StreamTcpPacketStateEstablished (%p): Reset received and state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; /*Similar remote application is closed, so jump to CLOSE_WAIT*/ ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1; ssn->client.next_seq = TCP_GET_ACK(p); printf("StreamTcpPacketStateEstablished (%p): ssn->server.next_seq %u\n", ssn, ssn->server.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateEstablished (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); StreamTcpStreamReturntoPool(p); } } else return -1; break; default: printf("StreamTcpPacketStateEstablished (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the FIN packets for states TCP_SYN_RECV and * TCP_ESTABLISHED and changes to another TCP state as required. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpHandleFin(TcpSession *ssn, Packet *p) { if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacket (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window))) { printf("StreamTcpPacket (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacket (%p): state changed to TCP_CLOSE_WAIT\n", ssn); ssn->state = TCP_CLOSE_WAIT; ssn->client.next_seq = TCP_GET_ACK(p); ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1; printf("StreamTcpPacket (%p): ssn->server.next_seq %u\n", ssn, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacket (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ printf("StreamTcpPacket (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { printf("StreamTcpPacket (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacket (%p): state changed to TCP_FIN_WAIT1\n", ssn); ssn->state = TCP_FIN_WAIT1; ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1; ssn->client.next_seq = TCP_GET_ACK(p); printf("StreamTcpPacket (%p): ssn->server.next_seq %u\n", ssn, ssn->server.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacket (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } return 0; } /** * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles * ACK, FIN, RST packets and correspondingly changes the connection * state. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch (p->tcph->th_flags) { case TH_ACK: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateFinWait1 (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); printf("StreamTcpPacketStateFinWait1 (%p): state changed to TCP_FIN_WAIT2\n", ssn); ssn->state = TCP_FIN_WAIT2; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateFinWait1 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ printf("StreamTcpPacketStateFinWait1 (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); printf("StreamTcpPacketStateFinWait1 (%p): state changed to TCP_FIN_WAIT2\n", ssn); ssn->state = TCP_FIN_WAIT2; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateFinWait1 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } break; case TH_FIN: case TH_FIN|TH_ACK: case TH_FIN|TH_ACK|TH_PUSH: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateFinWait1 (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))) { printf("StreamTcpPacketStateFinWait1 (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacketStateFinWait1 (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateFinWait1 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ printf("StreamTcpPacketStateFinWait1 (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { printf("StreamTcpPacketStateFinWait1 (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacketStateFinWait1 (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateFinWait1 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } break; case TH_RST: case TH_RST|TH_ACK: if(ValidReset(ssn, p)) { printf("StreamTcpPacketStateFinWait1 (%p): Reset received state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; StreamTcpStreamReturntoPool(p); } else return -1; break; default: printf("StreamTcpPacketStateFinWait1 (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles * ACK, RST, FIN packets and correspondingly changes the connection * state. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch (p->tcph->th_flags) { case TH_ACK: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateFinWait2 (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->client.next_seq) { printf("StreamTcpPacketStateFinWait2 (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacketStateFinWait2 (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateFinWait2 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ printf("StreamTcpPacketStateFinWait2 (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->server.next_seq) { printf("StreamTcpPacketStateFinWait2 (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacketStateFinWait2 (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateFinWait2 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } break; case TH_RST: case TH_RST|TH_ACK: if(ValidReset(ssn, p)) { printf("StreamTcpPacketStateFinWait2 (%p): Reset received state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; StreamTcpStreamReturntoPool(p); } else return -1; break; case TH_FIN: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateFinWait2 (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq || SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))) { printf("StreamTcpPacketStateFinWait2 (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacketStateFinWait2 (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateFinWait2 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ printf("StreamTcpPacketStateFinWait2 (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { printf("StreamTcpPacketStateFinWait2 (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacketStateFinWait2 (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateFinWait2 (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } break; default: printf("StreamTcpPacketStateFinWait2 (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK * the connection goes to TCP_TIME_WAIT state. The state has been * reached as both end application has been closed. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch(p->tcph->th_flags) { case TH_ACK: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateClosing (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->client.next_seq) { printf("StreamTcpPacketStateClosing (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacketStateClosing (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateClosing (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); } else { /* implied to client */ printf("StreamTcpPacketStateClosing (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->server.next_seq) { printf("StreamTcpPacketStateClosing (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacketStateClosing (%p): state changed to TCP_TIME_WAIT\n", ssn); ssn->state = TCP_TIME_WAIT; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateClosing (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } break; default: printf("StreamTcpPacketStateClosing (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN * packet from server the connection goes to TCP_LAST_ACK state. * The state is possible only for server host. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch(p->tcph->th_flags) { case TH_FIN: if (PKT_IS_TOCLIENT(p)) { printf("StreamTcpPacketStateCloseWait (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) || SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window))) { printf("StreamTcpPacketStateCloseWait (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacketStateCloseWait (%p): state changed to TCP_LAST_ACK\n", ssn); ssn->state = TCP_LAST_ACK; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateCloseWait (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); } break; default: printf("StreamTcpPacketStateCloseWait (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK * the connection goes to TCP_CLOSED state and stream memory is * returned back to pool. The state is possible only for server host. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPakcetStateLastAck(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch(p->tcph->th_flags) { case TH_ACK: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateLastAck (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->client.next_seq) { printf("StreamTcpPacketStateLastAck (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacketStateLastAck (%p): state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateLastAck (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); StreamTcpStreamReturntoPool(p); } break; default: printf("StreamTcpPacketStateLastAck (%p): default case\n", ssn); break; } return 0; } /** * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK * the connection goes to TCP_CLOSED state and stream memory is * returned back to pool. * * \param tv Thread Variable containig input/output queue, cpu affinity etc. * \param p Packet which has to be handled in this TCP state. * \param stt Strean Thread module registered to handle the stream handling */ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; switch(p->tcph->th_flags) { case TH_ACK: if (PKT_IS_TOSERVER(p)) { printf("StreamTcpPacketStateTimeWait (%p): pkt (%u) is to server: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->client.next_seq) { printf("StreamTcpPacketStateTimeWait (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->client.next_seq); return -1; } printf("StreamTcpPacketStateTimeWait (%p): state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack)) ssn->server.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->client, p); printf("StreamTcpPacketStateTimeWait (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->client.next_seq, ssn->server.last_ack); StreamTcpStreamReturntoPool(p); } else { printf("StreamTcpPacketStateTimeWait (%p): pkt (%u) is to client: SEQ %u, ACK %u\n", ssn, p->payload_len, TCP_GET_SEQ(p), TCP_GET_ACK(p)); if (TCP_GET_SEQ(p) != ssn->server.next_seq) { printf("StreamTcpPacketStateTimeWait (%p): -> SEQ mismatch, packet SEQ %u != %u from stream\n", ssn, TCP_GET_SEQ(p), ssn->server.next_seq); return -1; } printf("StreamTcpPacketStateTimeWait (%p): state changed to TCP_CLOSED\n", ssn); ssn->state = TCP_CLOSED; ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack)) ssn->client.last_ack = TCP_GET_ACK(p); StreamTcpReassembleHandleSegment(ssn, &ssn->server, p); printf("StreamTcpPacketStateTimeWait (%p): =+ next SEQ %u, last ACK %u\n", ssn, ssn->server.next_seq, ssn->client.last_ack); StreamTcpStreamReturntoPool(p); } break; default: printf("StreamTcpPacketStateTimeWait (%p): default case\n", ssn); break; } return 0; } /* flow is and stays locked */ static int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt) { TcpSession *ssn = (TcpSession *)p->flow->stream; if (ssn == NULL || ssn->state == 0 || ssn->state == TCP_CLOSED) { StreamTcpPacketStateNone(tv, p, stt); } else { switch (ssn->state) { case TCP_SYN_SENT: StreamTcpPacketStateSynSent(tv, p, stt); break; case TCP_SYN_RECV: StreamTcpPacketStateSynRecv(tv, p, stt); break; case TCP_ESTABLISHED: StreamTcpPacketStateEstablished(tv, p, stt); break; case TCP_FIN_WAIT1: StreamTcpPacketStateFinWait1(tv, p, stt); break; case TCP_FIN_WAIT2: StreamTcpPacketStateFinWait2(tv, p, stt); break; case TCP_CLOSING: StreamTcpPacketStateClosing(tv, p, stt); break; case TCP_CLOSE_WAIT: StreamTcpPacketStateCloseWait(tv, p, stt); break; case TCP_LAST_ACK: StreamTcpPakcetStateLastAck(tv, p, stt); break; case TCP_TIME_WAIT: StreamTcpPacketStateTimeWait(tv, p, stt); break; } } return 0; } int StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { StreamTcpThread *stt = (StreamTcpThread *)data; //PerfCounterAddUI64(COUNTER_STREAMTCP_STREAMS, tv->pca, a); if (!(PKT_IS_TCP(p))) return 0; if (p->flow == NULL) return 0; #if 0 printf("StreamTcp: seq %u, ack %u, %s%s%s%s%s%s%s%s: ", TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_ISSET_FLAG_FIN(p) ? "FIN " :"", TCP_ISSET_FLAG_SYN(p) ? "SYN " :"", TCP_ISSET_FLAG_RST(p) ? "RST " :"", TCP_ISSET_FLAG_PUSH(p)? "PUSH ":"", TCP_ISSET_FLAG_ACK(p) ? "ACK " :"", TCP_ISSET_FLAG_URG(p) ? "URG " :"", TCP_ISSET_FLAG_RES2(p)? "RES2 ":"", TCP_ISSET_FLAG_RES1(p)? "RES1 ":""); #endif mutex_lock(&p->flow->m); StreamTcpPacket(tv, p, stt); mutex_unlock(&p->flow->m); stt->pkts++; return 0; } int StreamTcpThreadInit(ThreadVars *t, void *initdata, void **data) { StreamTcpThread *stt = malloc(sizeof(StreamTcpThread)); if (stt == NULL) { return -1; } memset(stt, 0, sizeof(StreamTcpThread)); /* XXX */ *data = (void *)stt; PerfRegisterCounter("streamTcp.tcp_streams", "StreamTcp", TYPE_DOUBLE, "NULL", &t->pctx, TYPE_Q_AVERAGE, 1); t->pca = PerfGetAllCountersArray(&t->pctx); PerfAddToClubbedTMTable("StreamTcp", &t->pctx); return 0; } int StreamTcpThreadDeinit(ThreadVars *t, void *data) { StreamTcpThread *stt = (StreamTcpThread *)data; if (stt == NULL) { return 0; } /* XXX */ /* clear memory */ memset(stt, 0, sizeof(StreamTcpThread)); free(stt); return 0; } void StreamTcpExitPrintStats(ThreadVars *tv, void *data) { StreamTcpThread *stt = (StreamTcpThread *)data; if (stt == NULL) { return; } printf(" - (%s) Packets %llu.\n", tv->name, stt->pkts); } /** * \brief Function to check the validity of the RST packets based on the target * OS of the given packet. * * \param ssn TCP session to which the given packet belongs * \param p Packet which has to be checked for its validity */ static int ValidReset(TcpSession *ssn, Packet *p) { u_int8_t os_policy; if (PKT_IS_TOSERVER(p)) os_policy = ssn->server.os_policy; else os_policy = ssn->client.os_policy; switch(os_policy) { case OS_POLICY_BSD: case OS_POLICY_FIRST: case OS_POLICY_HPUX10: case OS_POLICY_IRIX: case OS_POLICY_MACOS: case OS_POLICY_LAST: case OS_POLICY_WINDOWS: case OS_POLICY_WINDOWS2K3: case OS_POLICY_VISTA: if(PKT_IS_TOSERVER(p)){ if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { printf("Reset is Valid! Pakcet SEQ: %u\n", TCP_GET_SEQ(p)); return 1; } else { printf("Reset is not Valid! Packet SEQ: %u and server SEQ: %u\n", TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { printf("Reset is Valid! Pakcet SEQ: %u\n", TCP_GET_SEQ(p)); return 1; } else { printf("Reset is not Valid! Packet SEQ: %u and client SEQ: %u\n", TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } break; case OS_POLICY_HPUX11: if(PKT_IS_TOSERVER(p)){ if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) { printf("Reset is Valid! Pakcet SEQ: %u\n", TCP_GET_SEQ(p)); return 1; } else { printf("Reset is not Valid! Packet SEQ: %u and server SEQ: %u\n", TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) { printf("Reset is Valid! Pakcet SEQ: %u\n", TCP_GET_SEQ(p)); return 1; } else { printf("Reset is not Valid! Packet SEQ: %u and client SEQ: %u\n", TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } break; case OS_POLICY_OLD_LINUX: case OS_POLICY_LINUX: case OS_POLICY_SOLARIS: if(PKT_IS_TOSERVER(p)){ if(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack)) { /*window base is needed !!*/ if(SEQ_LT(TCP_GET_SEQ(p), (ssn->client.next_seq + ssn->client.window))) { printf("Reset is Valid! Pakcet SEQ: %u\n", TCP_GET_SEQ(p)); return 1; } } else { printf("Reset is not Valid! Packet SEQ: %u and server SEQ: %u\n", TCP_GET_SEQ(p), ssn->client.next_seq); return 0; } } else { /* implied to client */ if(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack)) { /*window base is needed !!*/ if(SEQ_LT(TCP_GET_SEQ(p), (ssn->server.next_seq + ssn->server.window))) { printf("Reset is Valid! Pakcet SEQ: %u\n", TCP_GET_SEQ(p)); return 1; } } else { printf("Reset is not Valid! Packet SEQ: %u and client SEQ: %u\n", TCP_GET_SEQ(p), ssn->server.next_seq); return 0; } } break; default: printf("Reset is not Valid! Packet SEQ: %u & os_policy default case\n", TCP_GET_SEQ(p)); break; } return 0; } /** * \brief Function to return the stream back to the pool. * * \param p Packet used to identify the stream. */ void StreamTcpStreamReturntoPool (Packet *p) { /* get a stream */ mutex_lock(&ssn_pool_mutex); PoolReturn(ssn_pool, p->flow->stream); mutex_unlock(&ssn_pool_mutex); p->flow->stream = NULL; } /*static int StreamTcpReassembleTest01 (void) { TcpSession ssn; TcpStream cstream, sstream; Packet p; ThreadVars tv; Flow f; StreamTcpThread stt; TCPHdr tcph; u_int8_t payload[] = { 0x41, 0x41, 0x41 }; memset(&tv, 0, sizeof(ThreadVars)); memset(&ssn, 0, sizeof(TcpSession)); memset(&cstream, 0, sizeof(TcpStream)); memset(&sstream, 0, sizeof(TcpStream)); memset(&p, 0, sizeof(Packet)); memset(&f, 0, sizeof(Flow)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); cstream.os_policy = OS_POLICY_BSD; sstream.os_policy = OS_POLICY_BSD; //ssn.state = 0; ssn.client = cstream; ssn.server = sstream; ssn.client.isn = 10; ssn.server.isn = 30; f.stream = &ssn; p.src.family = AF_INET; p.dst.family = AF_INET; //p.src = Address"10.0.0.1"; //p.dst = "10.0.0.2"; p.payload = NULL; p.payload_len = 0; p.proto = IPPROTO_TCP; tcph.th_seq = htonl(10); tcph.th_win = 5480; tcph.th_flags = TH_SYN; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; p.flow = &f; printf("I am executing hello world!!\n"); //for (i=0; i<39; i++) { //p = (Packet)pkts[i]; StreamTcpPacket(&tv, &p, &stt); //} tcph.th_seq = htonl(30); tcph.th_ack = htonl(11); tcph.th_win = 5480; tcph.th_flags = TH_SYN|TH_ACK; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOCLIENT; StreamTcpPacket(&tv, &p, &stt); tcph.th_seq = htonl(11); tcph.th_ack = htonl(31); tcph.th_win = 5480; tcph.th_flags = TH_ACK; p.tcph = &tcph; p.flowflags = FLOW_PKT_TOSERVER; StreamTcpPacket(&tv, &p, &stt); tcph.th_seq = htonl(12); tcph.th_ack = htonl(31); tcph.th_win = 5480; tcph.th_flags = TH_PUSH|TH_ACK; p.tcph = &tcph; //payload = p.payload = payload; p.payload_len = 3; p.flowflags = FLOW_PKT_TOSERVER; StreamTcpPacket(&tv, &p, &stt); return 1; } */ void StreamTcpRegisterTests (void) { #ifdef UNITTESTS //UtRegisterTest("StreamTcpReassembleTest01", StreamTcpReassembleTest01, 1); /* set up the reassembly tests as well */ StreamTcpReassembleRegisterTests(); #endif /* UNITTESTS */ }