#ifndef SANCP_H #include "sancp.h" #endif /************************************************************************** **SA Network Connection Profiler [sancp] - A TCP/IP statistical/collection tool * ************************************************************************ * * Copyright (C) 2003 John Curry * * * * This program is distributed under the terms of version 1.0 of the * * Q Public License. See LICENSE.QPL for further details. * * * * 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. * * * ***********************************************************************/ /*************************************************** * CHECK THIS PACKET * ***************************************************/ struct cnx *process(struct cnx* new_cnx, int len, u_char * pkt){ extern struct gvars gVars; struct cnx *tmptr=0; tmptr=update_state_node(new_cnx); // We update our single raw count of bytes for this connection here // including data for all headers tmptr->total_bytes+=len; if(new_cnx->pcap && (new_cnx->cmode==CMODE_BOTH || (new_cnx->cmode==CMODE_SRC && new_cnx->direction ==FROM_INITIATOR) || (new_cnx->cmode==CMODE_DST && new_cnx->direction == FROM_TARGET)) ){ if((tmptr->limit == 0) || (tmptr->collectedlimit)){ tmptr->fH->write((char *)pkt,len,&gVars.timeptr); tmptr->collected+=len; } } // If we don't need this anymore, get rid of it if(new_cnx->free==1){ new_cnx->CBufferPtr->Free(); new_cnx->CBufferPtr=NULL; new_cnx=NULL; }else{ // This really was a new connection, see if we should write a realtime // Should only happen when we are 'collecting' data on this connection // and when realtimes is enabled globally by default and/or specifically by rule. if(new_cnx->realtime) { // record a realtime record(new_cnx,gVars.rfH); if(!gVars.daemon_mode && gVars.console_mode){ record(new_cnx,gVars.sdF); } } } return(tmptr); } struct cnx * update_state_node(struct cnx *nc) { struct cnx *cn=NULL; extern struct gvars gVars; int direction=0; int thispkt_direction=0; u_int16_t cKey = 0; nc->hash= cKey = ((nc->s_ip + nc->d_ip)) % HASH_KEYS; cn=gVars.cnx_head[cKey]; nc->direction=FROM_INITIATOR; while (cn!=NULL) { if ( cn->h_proto==nc->h_proto ){ if(cn->proto==nc->proto){ if( ((cn->s_ip==nc->s_ip) && (cn->d_ip==nc->d_ip)) && ((cn->s_port==nc->s_port)&&(cn->d_port==nc->d_port)) ){ direction=1; break; }else if( ((cn->d_ip==nc->s_ip) && (cn->s_ip==nc->d_ip)) && ((cn->d_port==nc->s_port)&&(cn->s_port==nc->d_port)) ){ direction=2; break; } } }/*long if*/ cn=cn->next; }/*while*/ if(direction>0){ // We have a found a pre-existing connection that we can associated with this packet cn->last_pkt=nc->last_pkt; // The following four values are used to log data for the current packet nc->cmode=cn->cmode; nc->fH=cn->fH; nc->stats=cn->stats; nc->pcap=cn->pcap; nc->realtime=cn->realtime; // Notice we don't transfer cn->realtime, we have already generated one by the first packet. nc->limit=cn->limit; if(direction==1){ cn->s_total_bytes=cn->s_total_bytes + nc->s_total_bytes; cn->s_total_pkts++; gVars.pkts_in++; gVars.bytes_in+=nc->s_total_bytes; // Check if this did not match a rule??? }else{ //nc->direction=FROM_TARGET; cn->d_total_bytes += nc->s_total_bytes; cn->d_total_pkts++; gVars.pkts_out++; gVars.bytes_out+=nc->s_total_bytes; } //nc->start_time=cn->start_time; nc->free=1; // Move matched connection to top of list if(cn!=gVars.cnx_head[cKey]) { if(gVars.cnx_tail[cKey]==cn) gVars.cnx_tail[cKey]=cn->prev; if(cn->prev) { cn->prev->next=cn->next; } if(cn->next) { cn->next->prev=cn->prev; } cn->prev=NULL; cn->next = gVars.cnx_head[cKey]; gVars.cnx_head[cKey]->prev=cn; gVars.cnx_head[cKey]=cn; } }else{ // We will use this 'nc' as a new connection // // //if this is positively either the first or second tcp packet // // and which direction we believe the connection is headed if(nc->proto==IPPROTO_TCP || nc->proto == IPPROTO_UDP){ // See if we recognise the source port if(CheckPort(nc->proto,ntohs(nc->s_port))){ // See if we don't recognise the destination port if(CheckPort(nc->proto,ntohs(nc->d_port))==0){ // Hour known_ports indicates the connection is reversed nc->reversed=CNX_REVERSED; // if we never see packets from the 'source' then we will // correct this decision when we 'close' the cnx and log the stats }else // Well, we recognise both ports. Perhaps, this is a TCP syn ack? if(nc->proto == IPPROTO_TCP && (nc->tcpFlags[0]&(R_SYN+R_ACK))==(R_SYN+R_ACK)) { // Ah, this is the second packet in a TCP connection // its direction is surely reverse that of this initial packet nc->reversed=CNX_REVERSED; // if we never see packets from the 'source' then we will // correct this decision when we 'close' the cnx and log the stats } else { // Ok, well we tried folks... *shrug* // it might be reversed, it might not. we reconized both ports // so we're logging this the way we see it nc->reversed=CNX_BOTH_PORTS_KNOWN; } }else if(CheckPort(nc->proto,ntohs(nc->d_port))==0){ // Well, that was fun. we didn't find anything // it might be reversed, it might not. We didn't recognise // any of the ports in the known_ports list(s) // we're logging this the way we see it nc->reversed=CNX_BOTH_PORTS_UNKNOWN; } } /* * If this connection really looks reversed, lets make a final note here * We only reverse the packet information at the time we print it */ if(nc->reversed==CNX_REVERSED) { // We reference this when we write realtimes or stats // Also when we print the 'ongoing' connection list ( kill -USR2 ) nc->direction=FROM_TARGET; } direction=1; nc->cid=gVars.timeptr.tv_sec; nc->cid<<=32; nc->cid+=gVars.timeptr.tv_usec; // Let's make certain we have a unique connection id if(nc->cid<=gVars.cnx_id){ gVars.cnx_id++; nc->cid=gVars.cnx_id; }else{ gVars.cnx_id=nc->cid; } nc->fH=0; // Now we are ready to apply the rule, based on it's [perceived] direction apply_rule(nc); cn=nc; cn->free=0; cn->prev=NULL; if(gVars.cnx_head[cKey]) gVars.cnx_head[cKey]->prev=cn; cn->next = gVars.cnx_head[cKey]; gVars.cnx_head[cKey]=cn; if(!gVars.cnx_tail[cKey]) gVars.cnx_tail[cKey]=cn; gVars.cnx_head[cKey]=cn; } if(cn->proto==IPPROTO_TCP) { /* culmulatively record tcpFlags */ if(cn!=nc){ cn->tcpFlags[ direction - 1 ] |= nc->tcpFlags[0]; // Record os_info from first SYN packet seen coming from the destination if(direction==2 && (nc->tcpFlags[0]&(R_SYN))==R_SYN && cn->os_info2.len==0){ // Record os_info flags from second host memcpy(&cn->os_info2,&nc->os_info,sizeof(struct os_info)); } } /* record reset flag */ cn->tcpCFlags |= ( ( nc->tcpFlags[thispkt_direction] & R_RST )<<( direction - 1 ) ); /* record fin flag */ cn->tcpCFlags |= ( ( nc->tcpFlags[thispkt_direction] & R_FIN )<<( direction - 1 ) ); /* look for a fin from this packet's sender */ if( cn->tcpCFlags & ( (0x01)<<( direction - 1 ) )) { /* record ack - preceeding fin */ cn->tcpCFlags |= ( ( nc->tcpCFlags & R_ACK )<<( direction - 1 ) ); } } return(cn); }/*proc*/