1 #ifndef NCP_H
2 #include "sancp.h"
3 #endif
4 #include <unistd.h>
5 /**************************************************************************
6 **SA Network Connection Profiler [sancp] - A TCP/IP statistical/collection tool
7 * ************************************************************************
8 * * Copyright (C) 2003 John Curry <john.curry@metre.net>
9 * *
10 * * This program is distributed under the terms of version 1.0 of the
11 * * Q Public License. See LICENSE.QPL for further details.
12 * *
13 * * This program is distributed in the hope that it will be useful,
14 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * *
17 * ***********************************************************************/
18
19
20 //
21 // use to set/get the current connection counter to/from a file
22 // a = 0 GET CID, a = 1 SET CID
manage_cid(int a)23 void manage_cid(int a)
24 {
25 extern struct gvars gVars;
26 u_int64_t cid=0;
27 int len;
28 char *tmp;
29 // We need a connection id fileHandle
30 // Connection ID tracking fileHandle
31 if(!gVars.cfH){
32 tmp = createFileName(".cnxid",false);
33 gVars.cfH = new fileHandle(tmp,WRITE_MODE);
34 free(tmp);
35 }
36
37 // Are we suppose to write once to the file?
38 if(a==1)
39 {
40 if(gVars.cfH->getMode()!=WRITE_MODE){
41 gVars.cfH->setMode(WRITE_MODE);
42 gVars.cfH->reopen();
43 }
44 gVars.cfH->write((char *)&gVars.cnx_id,8);
45 }else{
46 if(gVars.cfH->getMode()!=READ_MODE){
47 gVars.cfH->setMode(READ_MODE);
48 gVars.cfH->reopen();
49 }
50 if(!gVars.cfH->open()){ syslog (LOG_ERR,"Unable to open file %s\n",gVars.cfH->getFileName()) ; }
51 gVars.cfH->seek(0L,SEEK_SET);
52 if((len = gVars.cfH->read((char *)&cid,8))==0){
53 syslog(LOG_ERR,"Didn't retrieved last connection ID, read on %d bytes\n", len);
54 gVars.cnx_id=0;
55 }else{
56 syslog(LOG_INFO,"Retrieved last connection ID: %llu %d %d\n", cid,len,errno);
57 gVars.cnx_id=cid;
58 }
59 switch (errno){
60 case EINTR:
61 syslog(LOG_ERR,"Error reading: EINTR\n");
62 break;
63 case EAGAIN:
64 syslog(LOG_ERR,"Error reading: EAGAIN\n");
65 break;
66 case EIO:
67 syslog(LOG_ERR,"Error reading: EIO\n");
68 break;
69 case EISDIR:
70 syslog(LOG_ERR,"Error reading: EISDIR\n");
71 break;
72 case EBADF:
73 syslog(LOG_ERR,"Error reading: EBADF\n");
74 break;
75 case EINVAL:
76 syslog(LOG_ERR,"Error reading: EINVAL\n");
77 break;
78 case EFAULT:
79 syslog(LOG_ERR,"Error reading: EFAULT\n");
80 break;
81 }
82
83 #ifdef DEBUG
84 printf("Retrieved last connection ID: %llu\n", cid);
85 #endif
86 }
87 }
88
open_files()89 void open_files()
90 {
91 extern struct gvars gVars;
92 char *tmp=0;
93 // Pcap fileHandle
94 if(!gVars.pfH && gVars.pmode){
95 tmp=createFileName(gVars.pcap_fname,gVars.pmode == OMODE_TSFILENAME);
96 gVars.pfH = new pcapFileHandle(tmp);
97 free(tmp);
98 }
99 // Realtime fileHandle
100 if(!gVars.rfH && gVars.rmode){
101 tmp=createFileName(gVars.realtime_fname,gVars.rmode == OMODE_TSFILENAME);
102 gVars.rfH = new outputFileHandle(tmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE);
103 gVars.rfH->setFormat(gVars.realtime_fmt,gVars.realtime_fmt_len);
104 gVars.rfH->setEor(gVars.realtime_eor);
105 gVars.rfH->setDelimiter(gVars.realtime_delimiter);
106 free(tmp);
107 }
108 // Stats fileHandle -- moved to erase_idle - the only function that writes to it
109 if(!gVars.sfH && gVars.smode){
110 tmp=createFileName(gVars.stats_fname,gVars.smode == OMODE_TSFILENAME);
111 gVars.sfH = new outputFileHandle(tmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE);
112 gVars.sfH->setFormat(gVars.stats_fmt,gVars.stats_fmt_len);
113 gVars.sfH->setEor(gVars.stats_eor);
114 gVars.sfH->setDelimiter(gVars.stats_delimiter);
115 free(tmp);
116 }
117 // This is done in manage_cid() as needed
118 // Connection ID tracking fileHandle
119 //if(!gVars.cfH && gVars.enable_cid){
120 //tmp = createFileName(".cid",false);
121 //gVars.cfH = new fileHandle(tmp);
122 //free(tmp);
123 //}
124 // Debug Pcap Raw fileHandle
125 if(!gVars.rpfH && gVars.pcap_raw){
126 tmp=createFileName(PCAP_RAW_FNAME);
127 gVars.rpfH = new pcapFileHandle(tmp);
128 free(tmp);
129 }
130 // stdout fileHandle
131 if(!gVars.sdF){
132 gVars.sdF = new outputFileHandle(stdout,APPEND_MODE,gVars.stdout_fmt,gVars.stdout_fmt_len);
133 gVars.sdF->setFormat(gVars.stdout_fmt,gVars.stdout_fmt_len);
134 gVars.sdF->setEor(gVars.stdout_eor);
135 gVars.sdF->setDelimiter(gVars.stdout_delimiter);
136 }
137 //
138 // bpf files are only created once at startup for now
139 //
140 //if(!gVars.bfH && strlen(gVars.bpf_fname))
141 //{
142 //tmp=createFileName(BPF_FNAME);
143 //gVars.bfH = new fileHandle(gVars.bpf_fname);
144 //free(tmp);
145 //}
146 }
147
close_files(int a)148 void close_files(int a){
149 extern struct gvars gVars;
150 if(gVars.pfH){
151 gVars.pfH->destroy(); gVars.pfH=NULL;
152 }
153 if(gVars.rfH){
154 gVars.rfH->destroy(); gVars.rfH=NULL;
155 }
156 if(gVars.sfH && !(a==2 && gVars.burst_mode==1)){
157 gVars.sfH->destroy(); gVars.sfH=NULL;
158 }
159 if(gVars.cfH){
160 gVars.cfH->destroy(); gVars.cfH=NULL;
161 }
162 if(gVars.rpfH){
163 gVars.rpfH->destroy(); gVars.rpfH=NULL;
164 }
165 if(gVars.sdF){
166 gVars.sdF->destroy(); gVars.sdF=NULL;
167 }
168 // bpf files are only handled, when specified at startup, for now
169 //if(gVars.bfH)
170 //gVars.bfH->destroy();
171 }
172
createFileName(const char * name)173 char * createFileName(const char *name)
174 {
175 return createFileName(name,true);
176 }
177
createFileName(const char * name,bool enable_timestamp=true)178 char * createFileName(const char *name, bool enable_timestamp = true)
179 {
180 extern struct gvars gVars;
181 //extern time_t restart_time;
182 char *f = (char *) calloc( 1, MAX_VAR );
183 if(enable_timestamp){
184 if(name[0]=='/' || !gVars.log_directory){
185 snprintf(f,MAX_VAR,"%s.%s.%ld",name,gVars.default_device,(long)gVars.restart_time);
186 }else{
187 snprintf(f,MAX_VAR,"%s%s.%s.%ld",gVars.log_directory,name,gVars.default_device,(long)gVars.restart_time);
188 }
189 }else{
190 if(name[0]=='/' || !gVars.log_directory){
191 snprintf(f,MAX_VAR,"%s",name);
192 }else{
193 snprintf(f,MAX_VAR,"%s%s",gVars.log_directory,name);
194 }
195 }
196 return f;
197 }
198
createPcapFileName(const struct cnx * c)199 char * createPcapFileName(const struct cnx *c)
200 {
201 extern struct gvars gVars;
202 //extern time_t restart_time;
203 char *x = (char *) calloc( 1, MAX_VAR+1 );
204 char *f = (char *) calloc( 1, MAX_VAR+1 );
205 snprintf(x,MAX_VAR,"%s%s",gVars.log_directory,inet_ntoa(*(struct in_addr*) &c->s_ip));
206 bzero(f,MAX_VAR);
207 snprintf(f,MAX_VAR,"%s:%d_%s:%d-%d.%ld",x,ntohs(c->s_port),inet_ntoa(*(struct in_addr*) &c->d_ip),ntohs(c->d_port),c->proto,(long)gVars.restart_time);
208 free(x);
209 return f;
210 }
211
createPcapFileName(const struct acl * a)212 char * createPcapFileName(const struct acl *a)
213 {
214 extern struct gvars gVars;
215 //extern time_t restart_time;
216 char *x = (char *) calloc( 1, 256 );
217 char *f = (char *) calloc( 1, 256 );
218 snprintf(f,255,"%s%s",gVars.log_directory,inet_ntoa(*(struct in_addr*) &a->s_ip));
219 bzero(x,255);
220 snprintf(x,255,"%s-%s",f,inet_ntoa(*(struct in_addr*) &a->s_mask));
221 bzero(f,255);
222 snprintf(f,255,"%s:%s",x,inet_ntoa(*(struct in_addr*) &a->d_ip));
223 bzero(x,255);
224 snprintf(x,255,"%s-%s",f,inet_ntoa(*(struct in_addr*) &a->d_mask));
225 bzero(f,255);
226 snprintf(f,255,"%s_%d-%d:%d-%d_%d-%d.%ld",x,a->s_port_l,a->s_port_h,a->d_port_l,a->d_port_h,a->proto_l,a->proto_h,(long)gVars.restart_time);
227 free(x);
228 return f;
229 }
230
231
set_signals()232 void set_signals()
233 {
234 signal(SIGHUP, reload_config);
235 signal(SIGALRM, erase_idle);
236 signal(SIGUSR1, print_acl);
237 signal(SIGUSR2, record_all);
238 signal(SIGTERM, exit_all);
239 signal(SIGINT, exit_all);
240 signal(SIGKILL, exit_all);
241 signal(SIGQUIT, exit_all);
242 }
243
reopen_files(int a)244 void reopen_files(int a){
245 extern struct gvars gVars;
246 // Close default pcap, stats, realtime and debug_pcap_raw
247 close_files(a);
248 //manage_cid(0);
249 gVars.restart_time = time(0);
250 // Open default pcap, stats, realtime and debug_pcap_raw
251 open_files();
252 }
253
reload_config(int a)254 void reload_config(int a){
255 manage_cid(1);
256 build_config(1);
257 syslog(LOG_INFO,"Reloading configuration");
258 }
259
exit_all(int a)260 void exit_all(int a){
261 extern gvars gVars;
262 // We should stop collecting packets now
263 close_pcap_file(gVars.ph);
264 if(gVars.console_mode && !gVars.daemon_mode)
265 record_all(1);
266 manage_cid(1);
267 free_all(1);
268 syslog(LOG_INFO,"Exiting");
269 close_files(1);
270 // close syslog
271 closelog();
272 exit(0);
273 }
274
free_all(int a)275 void free_all(int a)
276 {
277
278 extern struct gvars gVars;
279 //extern struct acl *acl_head;
280 struct acl *acl_tmp;
281 //extern struct cnx *cnx_head[];
282 struct cnx *cnx_tmp;
283 struct cnx *cnx_thead;
284 //extern struct t_ports *ports[];
285 struct t_ports *ports_head, *tmp_port;
286 int p=0;
287 int cKey;
288
289 ////printf("FreeAll... predelete T: %d U: %d F: %d\n",cnx_pool.GetTotalBuffers(),cnx_pool.GetUsedBuffers(),cnx_pool.GetFreeBuffers() );
290 while(gVars.acl_head!=NULL){
291 acl_tmp=gVars.acl_head;
292 gVars.acl_head=acl_tmp->next;
293 if(acl_tmp->fH){ acl_tmp->fH->destroy(); acl_tmp->fH=0; }
294 free(acl_tmp);
295 }
296 while(gVars.expired_cnxs.head!=NULL){
297 //We really need to check whether we actually recieved
298 //any bytes from the source 'first' before we record.
299 cnx_tmp=gVars.expired_cnxs.head;
300 gVars.expired_cnxs.head=gVars.expired_cnxs.head->next;
301 free(cnx_tmp);
302 }
303 if(!gVars.sfH && gVars.smode && gVars.stats_fname){
304 char *tmp=createFileName(gVars.stats_fname,gVars.smode == OMODE_TSFILENAME);
305 gVars.sfH = new outputFileHandle(tmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE);
306 gVars.sfH->setFormat(gVars.stats_fmt,gVars.stats_fmt_len);
307 gVars.sfH->setEor(gVars.stats_eor);
308 gVars.sfH->setDelimiter(gVars.stats_delimiter);
309 free(tmp);
310 }
311 for(cKey=0; cKey< HASH_KEYS; cKey++)
312 {
313 cnx_thead=gVars.cnx_head[cKey];
314 while(cnx_thead!=NULL){
315 cnx_tmp=cnx_thead;
316 if(cnx_tmp->stats){
317 // We check whether we ever actually received any bytes from the
318 // source - to avoid recording an obvious, 'reversed' connection
319 // and we will record out decision too
320 if( cnx_tmp->reversed==CNX_REVERSED && cnx_tmp->d_total_pkts==0){
321 cnx_tmp->reversed=CNX_REREVERSED;
322 }
323 if(gVars.sfH)
324 record(cnx_tmp,gVars.sfH);
325 }
326 cnx_thead=cnx_tmp->next;
327 if(cnx_tmp->fH){
328 cnx_tmp->fH->destroy(); cnx_tmp->fH=0;}
329 cnx_tmp->CBufferPtr->Free();
330 cnx_tmp->CBufferPtr=NULL;
331 cnx_tmp=NULL;
332 }
333 }
334 for(p=0; p<MAX_IP_PROTO; p++)
335 {
336 ports_head=gVars.ports[p];
337 while(ports_head!=NULL){
338 tmp_port=ports_head;
339 ports_head=tmp_port->next;
340 free(tmp_port);
341 }
342 }
343
344 // Clear out any memory allocated to gVars
345 free(gVars.cnx_pool);
346 free(gVars.acl_pool);
347
348 if(gVars.bpf_filter)
349 free(gVars.bpf_filter);
350 if(gVars.bpf_fname)
351 free(gVars.bpf_fname);
352 if(gVars.pcap_fname)
353 free(gVars.pcap_fname);
354 if(gVars.username)
355 free(gVars.username);
356 if(gVars.groupname)
357 free(gVars.groupname);
358 if(gVars.stdout_fmt)
359 free(gVars.stdout_fmt);
360 if(gVars.stats_fmt)
361 free(gVars.stats_fmt);
362 if(gVars.realtime_fmt)
363 free(gVars.realtime_fmt);
364 }
365
record_all(int a)366 void record_all(int a){
367 extern struct gvars gVars;
368 struct cnx *cnx_tmp;
369
370 int cKey;
371 for(cKey=0; cKey< HASH_KEYS; cKey++)
372 {
373 cnx_tmp=gVars.cnx_head[cKey];
374 while(cnx_tmp!=NULL){
375 // We really need to check whether we actually recieved
376 // any bytes from the source 'first' before we record.
377 if(cnx_tmp->reversed==CNX_REVERSED && cnx_tmp->d_total_pkts==0){
378 cnx_tmp->reversed=CNX_REREVERSED;
379 }
380 record(cnx_tmp,gVars.sdF);
381 cnx_tmp=cnx_tmp->next;
382 }
383 }
384
385 cnx_tmp=gVars.expired_cnxs.head;
386 gVars.expired_cnxs.head=NULL;
387 gVars.expired_cnxs.tail=NULL;
388 while(cnx_tmp!=NULL){
389 // We really need to check whether we actually recieved
390 // any packets from the 'source' before we record.
391 if(cnx_tmp->reversed==CNX_REVERSED && cnx_tmp->d_total_pkts==0){
392 cnx_tmp->reversed=CNX_REREVERSED;
393 }
394 record(cnx_tmp,gVars.sdF);
395 cnx_tmp=cnx_tmp->next;
396 }
397 }
398
399 // To be re-discovered...
print_stats(int a)400 void print_stats(int a){
401 extern u_int16_t pkts_in, pkts_out, bytes_in, bytes_out;
402 extern u_int16_t l_pkts_in, l_pkts_out, l_bytes_in, l_bytes_out;
403 extern struct gvars gVars;
404 u_int16_t pavg_in, pavg_out, bavg_in, bavg_out, dpkts, dbytes;
405 u_int32_t dtime;
406 if((dtime=gVars.timeptr.tv_sec-gVars.timelast.tv_sec)==0){ dtime=1; }
407 dpkts=pkts_in-l_pkts_in;
408 pavg_in=(u_int16_t)dpkts/dtime;
409 dpkts=pkts_out-l_pkts_out;
410 pavg_out=(u_int16_t)dpkts/dtime;
411 dbytes=bytes_in-l_bytes_in;
412 bavg_in=(u_int16_t)dbytes/dtime;
413 dbytes=bytes_out-l_bytes_out;
414 bavg_out=(u_int16_t)dbytes/dtime;
415 fprintf(stdout,"# PKTS\tIN\tOUT\t BYTES\tIN\tOUT\n");
416 fprintf(stdout,"# \t%d\t%d\t \t%d\t%d\n",pkts_in,pkts_out,bytes_in,bytes_out);
417 fprintf(stdout,"# \t%d/s\t%d/s\t \t%d/s\t%d/s\n",pavg_in,pavg_out,bavg_in,bavg_out);
418 l_pkts_in=pkts_in;
419 l_pkts_out=pkts_out;
420 l_bytes_in=bytes_in;
421 l_bytes_out=bytes_out;
422 //pkts_in=pkts_out=bytes_in=bytes_out=0;
423 gVars.timelast.tv_sec=gVars.timeptr.tv_sec;
424 gVars.timelast.tv_usec=gVars.timeptr.tv_usec;
425 }
426
427
CheckPort(u_int8_t proto,u_int16_t port)428 int CheckPort(u_int8_t proto, u_int16_t port)
429 {
430 extern struct gvars gVars;
431 struct t_ports *ports_head;
432 struct t_ports *tp;
433 ports_head=gVars.ports[proto];
434 while(ports_head!=NULL){
435 if(port >= ports_head->l_port && port <= ports_head->h_port)
436 return 1;
437 tp=ports_head;
438 ports_head=tp->next;
439 }
440 return 0;
441 }
442
443
444