📄 spp_tcp_stream.c
字号:
/*** Copyright (C) 1998,1999,2000,2001 Martin Roesch <roesch@clark.net>** Copyright (C) 1999,2000,2001 Christopher E. Cramer <cec@ee.duke.edu>** ** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License as published by** the Free Software Foundation; either version 2 of the License, or** (at your option) any later version.** ** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.** ** You should have received a copy of the GNU General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//* $Id: spp_tcp_stream.c,v 1.14 2001/01/18 21:49:06 cec Exp $ *//* spp_tcp_stream * * Purpose: * * Construct tcp streams from observed packets * * Usage: * * preprocessor stream: <arg set 1>, <arg set 2>, ... * * Arguments: one or more of the following separated by commas * * timeout <timeout value> * * ports <port 1> ... <port N> * * maxbytes <maxbytes> * * <timeout> - the max time in seconds for which a stream will be * kept alive if we haven't seen a packet for it * <port x> - a server port to monitor. we don't want to monitor * all tcp streams (do we?) * <maxbytes> - maximum bytes in our reconstructed packets * * example: * preprocessor stream: timeout 5, ports 21 23 80 8080, maxbytes 16384 * * Effect: * * creates a buffer for each observed tcp stream. upon seeing a RETURN * or receiving a maximum number of bytes, generate a packet containing * the reconstructed data * * Comments: * * the size of <timeout> will directly impact the amount of memory used. * The longer the timeout the more streams kept in memory, the greater * the memory usage. * * To Do: * make buffers circular to avoid copying * check RST packets to verify sequence number * allow tighter checks on what we monitor - reduce memory usage. * */#include "spp_tcp_stream.h"#ifndef WIN32 #include <strings.h> #include <sys/time.h>#else #include <time.h>#endif#include <sys/types.h>#undef HAVE_64/* external globals from rules.c */extern char *file_name;extern int file_line;TcpStreamData StreamData;FILE *TcpStreamFile;int sesscount = 0;/* * Function: SetupTcpStream() * * Purpose: Registers the preprocessor keyword and initialization * function into the preprocessor list. This is the function that * gets called from InitPreprocessors() in plugbase.c. * * Arguments: None. * * Returns: void function * */void SetupTcpStream(){ /* link the preprocessor keyword to the init function in the preproc list */ RegisterPreprocessor("stream", TcpStreamInit);#ifdef DEBUG printf("Preprocessor: TcpStream is setup...\n");#endif}/* * Function: TcpStreamInit(u_char *) * * Purpose: Calls the argument parsing function, performs final setup on data * structs, links the preproc function into the function list. * * Arguments: args => ptr to argument string * * Returns: void function * */void TcpStreamInit(u_char *args){ int i;#ifdef DEBUG printf("Preprocessor: TcpStream Initialized\n");#endif /* parse the argument list from the rules file */ for(i=0;i<256;i++) StreamData.heads[i] = (TcpStreamSession *)NULL; ParseTcpStreamArgs(args); /* Set the preprocessor function into the function list */ AddFuncToPreprocList(TcpStreamPacket);}/* * Function: ParseTcpStreamArgs(char *) * * Purpose: Process the preprocessor arguements from the rules file and * initialize the preprocessor's data struct. This function doesn't * have to exist if it makes sense to parse the args in the init * function. * * Arguments: args => argument list * * Returns: void function * */void ParseTcpStreamArgs(char *args){ /* your parsing function goes here, check out the other spp files for examples */ char **toks, **secs; int num_toks, num_secs; int i,j; if(args == NULL) { FatalError("ERROR %s (%d)=> No arguments to TcpStream preprocessor!\n", file_name, file_line); } StreamData.maxbytes = 0x01<<12; StreamData.prunetime = 10; /* tokenize the argument list */ secs = mSplit(args, ",", 33, &num_secs, '\\'); for(i=0;i<num_secs;i++) { toks = mSplit(secs[i], " ", 33, &num_toks, '\\'); if(strcmp(toks[0],"timeout") == 0) { if(num_toks != 2) FatalError("ERROR %s (%d)=> timeout takes 1 argument!\n",file_name,file_line); StreamData.prunetime = atoi(toks[1]); if(StreamData.prunetime <= 0) { FatalError("ERROR %s (%d)=> Time between prunings must be >0 seconds!\n",file_name,file_line); } } else if(strcmp(toks[0],"maxbytes") == 0) { if(num_toks != 2) FatalError("ERROR %s (%d)=> maxbytes takes 1 argument!\n",file_name,file_line); StreamData.maxbytes = atoi(toks[1]); if(StreamData.maxbytes < 0 || StreamData.maxbytes > (0x1 << 15)) { FatalError("ERROR %s (%d)=> maxbytes must be >= 0 and <= 32K bytes!\n",file_name,file_line); } } else if(strcmp(toks[0],"ports") == 0) { for(j = 1; j < num_toks; j++) { StreamData.ports[j-1] = atoi(toks[j]); } StreamData.num_entries = num_toks-1; } else { FatalError("ERROR %s (%d)=> unknown argument to preprocessor stream: %s!\n",file_name,file_line,toks[0]); } for(j=0;j<num_toks;j++) free(toks[j]); } for(i=0;i<num_secs;i++) free(secs[i]);}/* * Function: TcpStreamPacket(Packet *) * * Purpose: take a packet, determine if it is tcp. if so, is it the start of a stream? * yes - create new stream. no - do we have that stream? yes - deal w/ packet. * no - return * * * Arguments: p => pointer to the current packet data struct * * Returns: void function * */void TcpStreamPacket(Packet *p){ int i; int pos;#ifdef DEBUG char sip[16]; char dip[16];#endif u_long tm; TcpStreamSession * sptr = NULL; u_int32_t lack, lseq; int server_packet; u_long bytes_in_buf, made_packet; int bin; /* statuses (client-status & server-status) from TCP/IP Illustrated v1, p 241: 0 - closed 1 - listen 2 - SYN_RCVD 3 - SYN_SENT 4 - ESTABLISHED (data xfer mode) 5 - CLOSE_WAIT 6 - LAST_ACK 7 - FIN_WAIT_1 8 - CLOSING 9 - FIN_WAIT_2 10- TIME_WAIT */ if(!PacketIsTCP(p)) {#ifdef DEBUG printf("It isn't TCP session traffic\n");#endif return; } /* don't accept packets w/ bad checksums */ if(p->csum_flags & CSE_IP || p->csum_flags & CSE_TCP) {#ifdef DEBUG printf("Discarding packet based on checksum errors!\n");#endif return; } if(p->tcph->th_ack == 0 && p->tcph->th_seq == 0) {#ifdef DEBUG printf("TcpStream Preprocessor shouldn't be handling it's own packets! :-)\n");#endif return; } for(i = 0; i < StreamData.num_entries; i++) if((StreamData.ports[i] == p->dp) || (StreamData.ports[i] == p->sp)) break; if(i == StreamData.num_entries) return; /* not a monitored port */ pc.tcp_stream_pkts ++; /* a packet we use */ if(StreamData.ports[i] == p->sp) { server_packet = 1; } else { server_packet = 0; } tm = TcpStreamTime(); if(tm - StreamData.timestamp >= StreamData.prunetime) { TcpStreamPruneSessions(); StreamData.timestamp = tm; } lack = ntohl(p->tcph->th_ack); lseq = ntohl(p->tcph->th_seq);#if DEBUG strncpy(sip, inet_ntoa(p->iph->ip_src), 16); strncpy(dip, inet_ntoa(p->iph->ip_dst), 16); printf("Packet (%x %u/%u %i) - %s:%i -> %s:%i (%i)\n",p->tcph->th_flags,lseq,lack,p->tcph->th_win,sip,p->sp,dip,p->dp,p->dsize);#endif sptr = TcpStreamCheckSession(p,StreamData.ports[i], &bin); if(sptr == (TcpStreamSession *)NULL) { if(p->tcph->th_flags == R_SYN) { /* new stream, SYN packet */ sptr = (TcpStreamSession *)malloc(sizeof(TcpStreamSession)); sptr->next = StreamData.heads[bin]; StreamData.heads[bin] = sptr; pc.tcp_streams ++; /* new tcp stream */ sptr->client_status = SYN_SENT; sptr->server_status = SYN_RCVD; sptr->c_inbuf = sptr->s_inbuf = 0; sptr->cip = p->iph->ip_src.s_addr; sptr->cp = p->sp; sptr->sip = p->iph->ip_dst.s_addr; sptr->sp = p->dp; sptr->c_first_seq = lseq + 1; sptr->c_last_acked = lseq + 1; /* cheat mode */ sptr->c_buf_start = lseq + 1; sptr->c_last_byte = sptr->s_last_byte = 0; sptr->timestamp = tm; sptr->c_buf = NULL; sptr->s_buf = NULL; if(p->tcph->th_win > 0) { sptr->c_buf_siz = ntohs(p->tcph->th_win) + StreamData.maxbytes; sptr->c_buf = (u_char *)malloc(sptr->c_buf_siz); sptr->c_buf_allocd = 1; } else { sptr->c_buf_allocd = 0; } sptr->s_buf_allocd = 0; } return; /* either way, we are done here */ } sptr->timestamp = tm; if(p->tcph->th_flags == R_SYN) /* j'accuse - we have a stream, but */ return; /* we've been sent a SYN - spoofer */ if(p->tcph->th_flags & R_RST) { /* handle RST by putting going to CLOSED state */ sptr->client_status = CLOSED; sptr->server_status = CLOSED; sptr->c_inbuf = sptr->s_inbuf = 0; sptr->c_first_seq = lseq + 1; sptr->c_last_acked = lseq + 1; /* cheat mode */ sptr->c_last_byte = sptr->s_last_byte = 0; sptr->timestamp = tm; return; } if(p->tcph->th_flags == (R_SYN | R_ACK)) { /* SYN/ACK */ if(!server_packet) return; /* Client should not SYN/ACK */ if(lack != sptr->c_first_seq) return; /* False SYN/ACK - bad seq*/ if((sptr->client_status == SYN_SENT) && (sptr->server_status = SYN_RCVD)) { sptr->s_first_seq = lseq+1; sptr->s_last_acked = lseq+1; /* cheat mode on */ sptr->s_buf_start = lseq+1; sptr->client_status = ESTABLISHED; /* client happy, should send ACK */ if(p->tcph->th_win != 0) { sptr->s_buf_siz = ntohs(p->tcph->th_win) + StreamData.maxbytes; sptr->s_buf = (u_char *) malloc(sptr->s_buf_siz); sptr->s_buf_allocd = 1; } } return; } /* If buffers haven't been allocated, try to do so here */ if(!server_packet && !sptr->c_buf_allocd) { if(p->tcph->th_win != 0) { sptr->c_buf_siz = ntohs(p->tcph->th_win) + StreamData.maxbytes; sptr->c_buf = (u_char *) malloc(sptr->c_buf_siz); sptr->c_buf_allocd = 1; } } if(server_packet && !sptr->s_buf_allocd) { if(p->tcph->th_win != 0) { sptr->s_buf_siz = ntohs(p->tcph->th_win) + StreamData.maxbytes; sptr->s_buf = (u_char *) malloc(sptr->s_buf_siz); sptr->s_buf_allocd = 1; } }#if DEBUG printf("statuses: %i/%i\n",sptr->server_status, sptr->client_status);#endif /* Check here to see if we inject new server packet */ if(!server_packet && sptr->server_status >= ESTABLISHED) { /* check to see if server buffer has proper data */ if(lack - sptr->s_first_seq > 0x7fffffff) bytes_in_buf = 0; else bytes_in_buf = lack - sptr->s_first_seq; /* shouldn't happen in a sane world */ if(bytes_in_buf > sptr->s_buf_siz) {#ifdef DEBUG ErrorMessage("[!] WARNING: TCP stream reassembler, Server Bytes in Buffer > Buffer Size (%i > %i)\n", bytes_in_buf, sptr->s_buf_siz);#endif bytes_in_buf = sptr->s_buf_siz; } made_packet = 0; if(bytes_in_buf >= StreamData.maxbytes) { TcpStreamPacketize(p, sptr->s_buf, StreamData.maxbytes, server_packet); made_packet = StreamData.maxbytes; } else { if (!sptr->s_buf_allocd) {#ifdef DEBUG printf("WARNING: TCP stream reassembler never got proper window size, setting to max!\n");#endif sptr->s_buf_siz = 65536 + StreamData.maxbytes; sptr->s_buf = (u_char *) malloc(sptr->s_buf_siz); sptr->s_buf_allocd = 1; } for(i=bytes_in_buf; i > (int)(sptr->s_last_acked - sptr->s_first_seq); i--) if(sptr->s_buf[i-1] == 0xa || sptr->s_buf[i-1] == 0xd) { TcpStreamPacketize(p, sptr->s_buf, i, server_packet); made_packet = i; break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -