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