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