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