1 #ifndef NCP_H
2 
3 #include "sancp.h"
4 
5 #endif
6 
7 /**************************************************************************
8  **SA Network Connection Profiler [sancp] - A TCP/IP statistical/collection tool
9  * ************************************************************************
10  * * Copyright (C) 2003 John Curry <john.curry@metre.net>
11  * *
12  * * This program is distributed under the terms of version 1.0 of the
13  * * Q Public License.  See LICENSE.QPL for further details.
14  * *
15  * * This program is distributed in the hope that it will be useful,
16  * * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18  * *
19  * ***********************************************************************/
20 
21 /*************
22  *Global Vars*
23  *************/
24 
25 u_int64_t cnx_id=0;
26 u_int16_t bytes_in=0;
27 u_int16_t bytes_out=0;
28 u_int16_t pkts_in=0;
29 u_int16_t pkts_out=0;
30 u_int16_t l_bytes_in=0;
31 u_int16_t l_bytes_out=0;
32 u_int16_t l_pkts_in=0;
33 u_int16_t l_pkts_out=0;
34 
35 struct gvars gVars;
36 
37 
38 	/* Here are all the possible output fields */
39 	/* MAXFLDS & MAXFLDSIZE are defined in sancp.h */
40 
41 /* Modifications to this statement can cause alignment problems with 'enum id' in gvars.h */
42 /* Make certain all strings are represented in the same order (as barewords) in 'enum id' in gvars.h */
43 char fmtnames[MAXFLDS][MAXFLDSIZE] = { {"null"},{"sancp_id"},{"start_time_gmt"},{"start_time_local"},{"stop_time_gmt"},{"stop_time_local"},{"erased_time_gmt"},{"erased_time_local"},{"eth_proto_hex"},{"eth_proto"},{"ip_proto"},{"src_ip_decimal"},{"src_ip_dotted"},{"src_port"},{"dst_ip_decimal"},{"dst_ip_dotted"},{"dst_port"},{"duration"},{"timeout"},{"src_pkts"},{"dst_pkts"},{"src_bytes"},{"dst_bytes"},{"sflags_hex"},{"sflags"},{"sflags_1"},{"sflags_2"},{"sflags_U"},{"sflags_A"},{"sflags_P"},{"sflags_R"},{"sflags_S"},{"sflags_F"},{"dflags_hex"},{"dflags"},{"dflags_1"},{"dflags_2"},{"dflags_U"},{"dflags_A"},{"dflags_P"},{"dflags_R"},{"dflags_S"},{"dflags_F"},{"cflags_hex"},{"cflags"},{"cflags_DA"},{"cflags_SA"},{"cflags_DR"},{"cflags_SR"},{"cflags_DF"},{"cflags_SF"},{"ip_len_s"},{"ip_ttl_s"},{"ip_df_s"},{"tcp_wss_s"},{"tcp_mss_s"},{"tcp_wscale_s"},{"tcp_sack_ok_s"},{"tcp_nop_s"},{"ip_len_d"},{"ip_ttl_d"},{"ip_df_d"},{"tcp_wss_d"},{"tcp_mss_d"},{"tcp_wscale_d"},{"tcp_sack_ok_d"},{"tcp_nop_d"},{"total_bytes"},{"collect"},{"collected"},{"climit"},{"tcplag"},{"pcap"},{"realtime"},{"stats"},{"reversed"},{"hash"},{"rid"},{"rgid"},{"node"},{"zone"},{"status"},{"retro"},{"src_mac"},{"dst_mac"} };
44 
45 	/* This will be our default stats and realtime layout */
46 
47 	char dfltfmt[]= { sancp_id,start_time_gmt,stop_time_gmt,erased_time_gmt,eth_proto,ip_proto,src_ip_decimal,src_port,dst_ip_decimal,dst_port,duration,timeout,src_pkts,dst_pkts,src_bytes,dst_bytes,sflags,dflags,cflags,ip_len_s,ip_ttl_s,ip_df_s,tcp_wss_s,tcp_mss_s,tcp_wscale_s,tcp_sack_ok_s,tcp_nop_s,ip_len_d,ip_ttl_d,ip_df_d,tcp_wss_d,tcp_mss_d,tcp_wscale_d,tcp_sack_ok_d,tcp_nop_d,total_bytes,collect,collected,climit,tcplag,pcap,realtime,stats,reversed,hash,rid,rgid,node,zone,status,retro,src_mac,dst_mac };
48 	//char dfltfmt[]= { sancp_id,start_time_gmt,src_mac,dst_mac,eth_proto,src_ip_dotted,dst_ip_dotted,ip_proto,src_port,dst_port };
49 	char dfltfmt_human_readable[]= { sancp_id,start_time_gmt,stop_time_gmt,erased_time_gmt,eth_proto,ip_proto,src_ip_dotted,src_port,dst_ip_dotted,dst_port,duration,timeout,src_pkts,dst_pkts,src_bytes,dst_bytes,sflags_hex,dflags_hex,cflags_hex,ip_len_s,ip_ttl_s,ip_df_s,tcp_wss_s,tcp_mss_s,tcp_wscale_s,tcp_sack_ok_s,tcp_nop_s,ip_len_d,ip_ttl_d,ip_df_d,tcp_wss_d,tcp_mss_d,tcp_wscale_d,tcp_sack_ok_d,tcp_nop_d,total_bytes,collect,collected,climit,tcplag,pcap,realtime,stats,reversed,hash,rid,rgid,node,zone,status,retro,src_mac,dst_mac };
50 
51 
52 /*************
53  *  Main     *
54  *************/
55 
main(int argc,char * argv[])56 int main(int argc, char *argv[]) {
57 	extern struct gvars gVars;
58 	int cKey;
59 	pid_t pid=0;
60 
61 	/*
62 	 * Setup our defaults for the enviroment
63 	 */
64 
65 	bzero(&gVars,sizeof(struct gvars));
66 	gVars.default_timeout=DEFAULT_TIMEOUT;
67 	gVars.default_limit=DEFAULT_LIMIT;
68 	gVars.default_tcplag=DEFAULT_LAG;
69 	gVars.shift=1;  //DEFAULT_DEVICE is 'any' so we need this set from the start
70         gVars.cmdl_pcap_action=ACTION_LOG;
71         gVars.cmdl_stats_action=ACTION_LOG;
72         gVars.cmdl_realtimes_action=ACTION_LOG;
73 	gVars.default_flush_interval=DEFAULT_FLUSH_INTERVAL;
74 	gVars.default_expire_interval=DEFAULT_EXPIRE_INTERVAL;
75 	gVars.print_schemas=0;
76 //gVars.log_facility=LOG_DAEMON;
77 	gVars.log_facility=LOG_LOCAL1;
78 	gVars.pmode=OMODE_TSFILENAME;
79 	gVars.smode=OMODE_TSFILENAME;
80 	gVars.rmode=OMODE_TSFILENAME;
81 	gVars.burst_mode=ENABLED;
82 	gVars.strip_80211=DISABLED;
83         gVars.cnx_pool = new CMemoryPool(true,sizeof(struct cnx),1024);//
84         gVars.acl_pool = new CMemoryPool(true,sizeof(struct acl),24);//
85 	gVars.timeptr.tv_sec=gVars.lastrun=gVars.restart_time=gVars.start_time=time(0);
86 
87         gVars.realtime_fmt_len=sizeof(dfltfmt);
88         gVars.realtime_fmt=(char *) calloc(gVars.realtime_fmt_len,1);
89         memcpy(gVars.realtime_fmt,dfltfmt,gVars.realtime_fmt_len);
90 	gVars.realtime_delimiter=DEFAULT_DELIMITER;
91 	gVars.realtime_eor=DEFAULT_EOR;
92 
93         gVars.stats_fmt_len=sizeof(dfltfmt);
94         gVars.stats_fmt=(char *) calloc(gVars.stats_fmt_len,1);
95         memcpy(gVars.stats_fmt,dfltfmt,gVars.stats_fmt_len);
96 	gVars.stats_delimiter=DEFAULT_DELIMITER;
97 	gVars.stats_eor=DEFAULT_EOR;
98 
99         gVars.stdout_fmt_len=sizeof(dfltfmt);
100         gVars.stdout_fmt=(char *) calloc(gVars.stdout_fmt_len,1);
101         memcpy(gVars.stdout_fmt,dfltfmt,gVars.stdout_fmt_len);
102 	gVars.stdout_delimiter=DEFAULT_DELIMITER;
103 	gVars.stdout_eor=DEFAULT_EOR;
104 
105 	for(cKey=0; cKey<HASH_KEYS; cKey++)
106 	{
107 		gVars.cnx_head[cKey]=NULL;
108 		gVars.cnx_tail[cKey]=NULL;
109 	}
110 
111 	/* Intialize the default syslog mode (Log to system console, stderr and to syslog) */
112 
113 	openlog(NAME,LOG_CONS+LOG_PERROR,gVars.log_facility);
114 
115 	/* These would be nice to have right now */
116 
117 	parse_args(argc, argv);
118 
119 	if(gVars.human_readable){
120              if(gVars.realtime_fmt_len!=sizeof(dfltfmt_human_readable)){
121         	free(gVars.realtime_fmt);
122         	gVars.realtime_fmt_len=sizeof(dfltfmt_human_readable);
123         	gVars.realtime_fmt=(char *) calloc(gVars.realtime_fmt_len,1);
124 	     }
125              memcpy(gVars.realtime_fmt,dfltfmt_human_readable,gVars.realtime_fmt_len);
126              if(gVars.stats_fmt_len!=sizeof(dfltfmt_human_readable)){
127         	free(gVars.stats_fmt);
128         	gVars.stats_fmt_len=sizeof(dfltfmt_human_readable);
129 	        gVars.stats_fmt=(char *) calloc(gVars.stats_fmt_len,1);
130 	     }
131       	     memcpy(gVars.stats_fmt,dfltfmt_human_readable,gVars.stats_fmt_len);
132 	}
133 
134     if(gVars.daemon_mode==1){
135     	if(getppid() != 1)
136 	{
137            pid = fork();
138 
139            if(pid > 0){
140 		 printf("(%d) sancp daemonized successfully!\n",pid);
141                exit(0);                /* parent */
142 	   }
143 
144            setsid();
145         }
146      }
147 	/* Retrieve the last cnxid from cache file if we haven't already in parse_args() */
148 
149 	if(!gVars.cnx_id)
150 		manage_cid(0);
151 
152 	/* Do we have a default device set yet? If not, we will read from all network devices. */
153 
154 	if(!gVars.default_device)
155 	{
156 		if((gVars.default_device = (char *)calloc(strlen("any")+1,1))==NULL){
157 			syslog(LOG_ERR,"Unable to allocate memory for -u option\n");
158 			exit(0);
159 		}
160 		bcopy("any",gVars.default_device,strlen("any"));
161 	}
162 
163 
164 	/* We should decide on a log directory now */
165 
166 	if(!gVars.log_directory)
167 	{
168 		if( (gVars.log_directory = (char *)calloc(strlen(LOG_DIR)+1,1) ) ==NULL){
169 			syslog(LOG_ERR,"Unable to allocate memory for -u option\n");
170 			exit(0);
171 		}
172 		bcopy(LOG_DIR,gVars.log_directory,strlen(LOG_DIR));
173 	}
174 
175 
176 	/* Set an initial default pcap output filename */
177 
178 	gVars.pcap_fname=(char *) calloc(1,strlen(PCAP_FNAME)+1);
179 	strncpy(gVars.pcap_fname,PCAP_FNAME,strlen(PCAP_FNAME));
180 
181 	/* Set an initial default stats output filename */
182 
183 	gVars.stats_fname=(char *) calloc(1,strlen(STATS_FNAME)+1);
184 	strncpy(gVars.stats_fname,STATS_FNAME,strlen(STATS_FNAME));
185 
186 	/* Set an initial default realtime output filename */
187 
188 	gVars.realtime_fname=(char *) calloc(1,strlen(REALTIME_FNAME)+1);
189 	strncpy(gVars.realtime_fname,REALTIME_FNAME,strlen(REALTIME_FNAME));
190 
191 
192 	/* Create the default output files for stats, pcap, and realtime (and debug_pcap_raw) */
193 
194 	open_files();
195 
196 	/* Read default collection mode settings and the rules */
197 
198 	build_config(1);
199 
200 	/* Open files for output */
201 	/* Be r3al l33t h3r3 */
202 
203 	if(gVars.print_schemas){
204 
205 		SChangeUserGroup();
206 		print_schemas();
207 		exit_all(0);
208 	}
209 
210 #ifdef DEBUG
211 	fprintf(stdout,"built the acls\n");
212 #endif
213 	if(gVars.input_filename)
214 	{
215 		/* Read from a pcap file */
216 
217 		gVars.ph=open_pcap_file(gVars.bpf_filter,gVars.input_filename);
218 
219 		if(gVars.ph==0){
220 			perror("open_pcap_file");
221 			exit_all(0);
222 		}
223 
224 	}else{
225 		/* Read from an interface */
226 		if(gVars.bpf_filter!=0)
227 			syslog(LOG_INFO,"Opening with filter: '%s'\n",gVars.bpf_filter);
228 
229 		gVars.ph=open_pcap_live(gVars.bpf_filter,gVars.default_device);
230 		if(gVars.ph==0){
231 			perror("open_pcap_live");
232 			exit_all(0);
233 		}
234 	}
235 	SChangeUserGroup();
236 
237 	/* If we read from a file or 'any' then we expect two extra bytes prefixing each packet */
238 
239 	if(gVars.shift) {
240 		    gVars.pcap_shift=2;
241 	}
242 
243 	/* Setup the signal handling routines */
244 	set_signals();
245         alarm(gVars.default_flush_interval);
246 	syslog(LOG_INFO,"started normally");
247 	/* Call our C function to call pcap_loop() */
248 	start_pcap_loop(gVars.ph);
249 	/* We should exit if we make it this far */
250 	exit_all(0);
251 
252  return 1;
253 
254 }
255 
256 /**************
257  * End of Main*
258  **************/
259 
260 #ifdef DEBUG
261 
262 /* Dummy function
263  * Used for debugging
264  */
notify()265 void notify(){
266 	return;
267 }
268 
269 #endif
270 
271 /*******************************************************************
272  * Function for C code to call C++ code (used by pcap_functions.c) *
273  *******************************************************************/
274 
ProcessMyPacket(char * user,struct pcap_pkthdr * pkthdr,u_char * pkt)275 extern "C" void ProcessMyPacket(char *user, struct pcap_pkthdr * pkthdr, u_char * pkt)
276 {
277 	struct gvars gVars;
278 	CBuffer *buffer;
279 	struct cnx *new_cnx=0;
280         gVars.timeptr.tv_sec=pkthdr->ts.tv_sec;
281         gVars.timeptr.tv_usec=pkthdr->ts.tv_usec;
282 
283         /* Strip the 80211 header off */
284 
285         if( gVars.strip_80211 && (*(u_int16_t*)(pkt + 12 + gVars.pcap_shift)==ETHPROTO_8021Q)){
286 #ifdef DEBUG
287                 printf("Have 8021Q, %.4x\n",*(u_int32_t*)(pkt + 12 + gVars.pcap_shift));
288 #endif
289                 /* shift packet data over 4 bytes to access encapsulated packet */
290 		/* this works even regardless of pcap_shift !!! NEED TO FIX THIS !!!*/
291                 memmove(pkt+4,pkt,4);
292                 pkthdr->caplen-=4;
293                 pkt+=4;
294         }
295 
296         if(gVars.pcap_raw){
297 		if(gVars.rpfH){
298 			gVars.rpfH->write((char *)pkt+gVars.pcap_shift,pkthdr->caplen,&gVars.timeptr);
299 		}
300         }
301 
302 /*	Copy the complete packet into an ethernet header structure for easy access */
303 
304 
305 	if((buffer=gVars.cnx_pool->Alloc())==NULL){ syslog(LOG_CRIT,"Out of Memory?\n"); return; }
306 
307 	new_cnx = (struct cnx *) buffer->GetBuffer();
308 
309         bzero((char *) new_cnx,sizeof(struct cnx));
310 
311 	new_cnx->CBufferPtr = buffer;
312 
313 #ifdef DEBUG
314 	if(gVars.cnx_pool->GetFreeBuffers() + gVars.cnx_pool->GetUsedBuffers() != gVars.cnx_pool->GetTotalBuffers())
315 	{
316 		/* We should notify someone that we have an inconsistency in our memory pool */
317 		notify(); // dummy function
318 	}
319 #endif
320 
321 /*
322  *	Decode Packet
323  */
324 	decode(new_cnx,pkthdr->caplen,pkt+gVars.pcap_shift);
325 
326 #ifdef DEBUG
327 	notify(); // dummy function
328         //pktcnt++;
329 #endif
330 
331 /*
332  * 	Now we have something to work with...
333  */
334 	process(new_cnx,pkthdr->caplen,pkt+gVars.pcap_shift);
335 
336 
337 
338         if((gVars.timeptr.tv_sec - gVars.lastrun)>gVars.default_expire_interval){
339 		/*
340 		 *  If we are configured to use the timestamp in the packets
341 		 *  to determine when to flush a file, then we should handle that here
342 		 */
343 		if(gVars.use_pcap_time && ((gVars.timeptr.tv_sec - gVars.lastrun)>gVars.default_flush_interval))
344 			erase_idle(2); // This function will call expire_conections() for us
345 		else
346 			expire_connections();
347 
348                 gVars.lastrun=gVars.timeptr.tv_sec;
349         }
350 }
351