1 #ifndef SANCP_H
2 #include "sancp.h"
3 #endif
4 /**************************************************************************
5  **SA Network Connection Profiler [sancp] - A TCP/IP statistical/collection tool
6  * ************************************************************************
7  * * Copyright (C) 2003 John Curry <john.curry@metre.net>
8  * *
9  * * This program is distributed under the terms of version 1.0 of the
10  * * Q Public License.  See LICENSE.QPL for further details.
11  * *
12  * * This program is distributed in the hope that it will be useful,
13  * * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  * *
16  * ***********************************************************************/
17 
18 /***************************************************
19  *    CHECK  THIS  PACKET                          *
20  ***************************************************/
21 
process(struct cnx * new_cnx,int len,u_char * pkt)22 struct cnx *process(struct cnx* new_cnx, int len, u_char * pkt){
23 	extern struct gvars gVars;
24 	struct cnx *tmptr=0;
25 	tmptr=update_state_node(new_cnx);
26 
27 	// We update our single raw count of bytes for this connection here
28 	// including data for all headers
29 	tmptr->total_bytes+=len;
30 
31 	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)) ){
32 		if((tmptr->limit == 0) || (tmptr->collected<tmptr->limit)){
33 		   tmptr->fH->write((char *)pkt,len,&gVars.timeptr);
34 		   tmptr->collected+=len;
35 		}
36         }
37 	// If we don't need this anymore, get rid of it
38 	if(new_cnx->free==1){
39 		new_cnx->CBufferPtr->Free();
40                	new_cnx->CBufferPtr=NULL;
41 		new_cnx=NULL;
42 	}else{
43 		// This really was a new connection, see if we should write a realtime
44 		// Should only happen when we are 'collecting' data on this connection
45 		// and when realtimes is enabled globally by default and/or specifically by rule.
46 		if(new_cnx->realtime)
47 		{
48 			// record a realtime
49 			record(new_cnx,gVars.rfH);
50 			if(!gVars.daemon_mode && gVars.console_mode){
51 				record(new_cnx,gVars.sdF);
52 			}
53 		}
54 	}
55 	return(tmptr);
56 }
57 
update_state_node(struct cnx * nc)58 struct cnx * update_state_node(struct cnx *nc) {
59         struct cnx *cn=NULL;
60 	extern struct gvars gVars;
61 	int direction=0;
62 	int thispkt_direction=0;
63 	u_int16_t cKey = 0;
64 	nc->hash= cKey = ((nc->s_ip + nc->d_ip)) % HASH_KEYS;
65         cn=gVars.cnx_head[cKey];
66 	nc->direction=FROM_INITIATOR;
67         while (cn!=NULL) {
68           if ( cn->h_proto==nc->h_proto ){
69 	    if(cn->proto==nc->proto){
70 		if( ((cn->s_ip==nc->s_ip) && (cn->d_ip==nc->d_ip)) &&
71                  ((cn->s_port==nc->s_port)&&(cn->d_port==nc->d_port)) ){
72 			direction=1;
73 			break;
74 		}else if( ((cn->d_ip==nc->s_ip) && (cn->s_ip==nc->d_ip)) &&
75                     ((cn->d_port==nc->s_port)&&(cn->s_port==nc->d_port)) ){
76 			direction=2;
77 			break;
78 		}
79             }
80 	  }/*long if*/
81           cn=cn->next;
82         }/*while*/
83 
84 
85 	if(direction>0){
86 	// We have a found a pre-existing connection that we can associated with this packet
87                	cn->last_pkt=nc->last_pkt;
88 		// The following four values are used to log data for the current packet
89                 nc->cmode=cn->cmode;
90 		nc->fH=cn->fH;
91                 nc->stats=cn->stats;
92                 nc->pcap=cn->pcap;
93                 nc->realtime=cn->realtime;
94 		// Notice we don't transfer cn->realtime, we have already generated one by the first packet.
95                 nc->limit=cn->limit;
96 		if(direction==1){
97               		cn->s_total_bytes=cn->s_total_bytes + nc->s_total_bytes;
98                		cn->s_total_pkts++;
99 			gVars.pkts_in++;
100 			gVars.bytes_in+=nc->s_total_bytes;
101 			// Check if this did not match a rule???
102 		}else{
103 			//nc->direction=FROM_TARGET;
104                		cn->d_total_bytes += nc->s_total_bytes;
105                		cn->d_total_pkts++;
106 			gVars.pkts_out++;
107 			gVars.bytes_out+=nc->s_total_bytes;
108 		}
109                	//nc->start_time=cn->start_time;
110 		nc->free=1;
111 		// Move matched connection to top of list
112 		if(cn!=gVars.cnx_head[cKey])
113 		{
114 			if(gVars.cnx_tail[cKey]==cn)
115        				gVars.cnx_tail[cKey]=cn->prev;
116 			if(cn->prev)
117 			{
118 				cn->prev->next=cn->next;
119 			}
120 			if(cn->next)
121 			{
122 				cn->next->prev=cn->prev;
123 			}
124                		cn->prev=NULL;
125                		cn->next = gVars.cnx_head[cKey];
126                		gVars.cnx_head[cKey]->prev=cn;
127                		gVars.cnx_head[cKey]=cn;
128 		}
129 
130 	}else{
131 	// We will use this 'nc' as a new connection
132 	//
133 		//
134 		//if this is positively either the first or second tcp packet
135 	//
136 	// and which direction we believe the connection is headed
137 		if(nc->proto==IPPROTO_TCP || nc->proto == IPPROTO_UDP){
138 			// See if we recognise the source port
139                 	if(CheckPort(nc->proto,ntohs(nc->s_port))){
140 				// See if we don't recognise the destination port
141 				if(CheckPort(nc->proto,ntohs(nc->d_port))==0){
142 					// Hour known_ports indicates the connection is reversed
143 					nc->reversed=CNX_REVERSED;
144 					// if we never see packets from the 'source' then we will
145 					// correct this decision when we 'close' the cnx and log the stats
146 				}else
147 				// Well, we recognise both ports. Perhaps, this is a TCP syn ack?
148 				   if(nc->proto == IPPROTO_TCP && (nc->tcpFlags[0]&(R_SYN+R_ACK))==(R_SYN+R_ACK))
149 				   {
150 					// Ah, this is the second packet in a TCP connection
151 					// its direction is surely reverse that of this initial packet
152 					nc->reversed=CNX_REVERSED;
153 					// if we never see packets from the 'source' then we will
154 					// correct this decision when we 'close' the cnx and log the stats
155 				   }
156 				   else
157 				   {
158 					// Ok, well we tried folks...  *shrug*
159 					// it might be reversed, it might not. we reconized both ports
160 					// so we're logging this the way we see it
161 					nc->reversed=CNX_BOTH_PORTS_KNOWN;
162 				   }
163 			}else if(CheckPort(nc->proto,ntohs(nc->d_port))==0){
164 				// Well, that was fun. we didn't find anything
165 				// it might be reversed, it might not. We didn't recognise
166 				// any of the ports in the known_ports list(s)
167 				// we're logging this the way we see it
168 				nc->reversed=CNX_BOTH_PORTS_UNKNOWN;
169 			}
170 		}
171 		/*
172 		*      If this connection really looks reversed, lets make a final note here
173 		*      We only reverse the packet information at the time we print it
174 		*/
175 		if(nc->reversed==CNX_REVERSED)
176 		{
177 			// We reference this when we write realtimes or stats
178 			// Also when we print the 'ongoing' connection list ( kill -USR2 )
179 			nc->direction=FROM_TARGET;
180 		}
181 		direction=1;
182 		nc->cid=gVars.timeptr.tv_sec;
183 		nc->cid<<=32;
184 		nc->cid+=gVars.timeptr.tv_usec;
185 
186 		// Let's make certain we have a unique connection id
187 		if(nc->cid<=gVars.cnx_id){
188 			gVars.cnx_id++;
189 			nc->cid=gVars.cnx_id;
190 		}else{
191 		        gVars.cnx_id=nc->cid;
192                 }
193 		nc->fH=0;
194 
195 		// Now we are ready to apply the rule, based on it's [perceived] direction
196 		apply_rule(nc);
197 
198 		cn=nc;
199 		cn->free=0;
200        		cn->prev=NULL;
201        	 	if(gVars.cnx_head[cKey])
202 			gVars.cnx_head[cKey]->prev=cn;
203 
204 		cn->next = gVars.cnx_head[cKey];
205       		gVars.cnx_head[cKey]=cn;
206 
207 		if(!gVars.cnx_tail[cKey])
208        			gVars.cnx_tail[cKey]=cn;
209 
210 		gVars.cnx_head[cKey]=cn;
211 
212 	}
213 
214 	if(cn->proto==IPPROTO_TCP)
215 	{
216 		/* culmulatively record tcpFlags */
217 		if(cn!=nc){
218 			cn->tcpFlags[ direction - 1 ] |= nc->tcpFlags[0];
219 			// Record os_info from first SYN packet seen coming from the destination
220 			if(direction==2 && (nc->tcpFlags[0]&(R_SYN))==R_SYN && cn->os_info2.len==0){
221 				// Record os_info flags from second host
222 				memcpy(&cn->os_info2,&nc->os_info,sizeof(struct os_info));
223 			}
224 		}
225 		/* record reset flag */
226 		cn->tcpCFlags |= ( ( nc->tcpFlags[thispkt_direction] & R_RST )<<( direction - 1 ) );
227 		/* record fin flag */
228 		cn->tcpCFlags |= ( ( nc->tcpFlags[thispkt_direction] & R_FIN )<<( direction - 1 ) );
229 		/* look for a fin from this packet's sender */
230 		if( cn->tcpCFlags & ( (0x01)<<( direction - 1 ) ))
231 		{
232 		/* record ack - preceeding fin */
233 			cn->tcpCFlags |= ( ( nc->tcpCFlags & R_ACK )<<( direction - 1 ) );
234 		}
235 	}
236 
237   return(cn);
238 }/*proc*/
239