1 /*
2 * Copyright (c) 1999 RISS-Telecom Networking Center
3 *
4 * Copyright (c) 1993 The CAD lab of the
5 * Novosibirsk Institute of Broadcasting and Telecommunication
6 *
7 * BPFT $Id: main.c,v 1.9 2004/05/05 18:06:51 stas_degteff Exp $
8 *
9 *
10 * Redistribution and use in source forms, with and without modification,
11 * are permitted provided that this entire comment appears intact.
12 * Redistribution in binary form may occur without any restrictions.
13 *
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
15 */
16
17 /* main.c - tcp/udp data traffic collector daemon */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <syslog.h>
25 #include <paths.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30 #ifndef __linux__
31 #include <sys/syslimits.h>
32 #endif
33 #include <sys/stat.h>
34 #include <netinet/in.h>
35 #include <net/bpf.h>
36 #include <pcap.h>
37
38 #include "../include/interface.h"
39 #include "../include/pathnames.h"
40 #include "../include/traffic.h"
41 #include "../include/addrtoname.h"
42 #include "trafd.h"
43
44 #define USE_EXIT 0 /* Use exit() function or use return operator
45 in the 'main' function */
46
47 /*
48 * Command line switches.
49 * Left - default value, right - action, if switch has been used.
50 */
51 int dflag = 0; /* dump to compiled packet-matching code to stdout and stop */
52 int Oflag = 1; /* don't run the packet-matching code optimizer if have bug */
53 int pflag = 0; /* don't put the interface into promiscuous mode */
54 int rflag = 0; /* attempt to resume data from safe file if exist */
55 int nflag = 0;
56 int Nflag = 0;
57 int fflag = 0;
58 int Xflag = 1; /* collect 'extended' traffic info (hosts-protocol-ports) */
59
60 /* Global interrupts flags */
61 int flag_hup; /* SIGHUP - drop collected data to tempfile */
62 int flag_int; /* SIGINT - append collected data to savefile */
63 int flag_usr1;
64
65 /* Global variables */
66 char *program_name; /* myself */
67 char *device_name = 0; /* interface name */
68 char file_pid[PATH_MAX]; /* pid file */
69 char file_dump[PATH_MAX]; /* dump file */
70 char file_save[PATH_MAX]; /* save file */
71 char file_tmp[PATH_MAX]; /* temp file */
72 char file_fifo[PATH_MAX]; /* fifo file */
73 unsigned long minsize=MIN_SIZE_TO_SAVE;
74
75 /* Block of the interrupt drivers */
76 static void cleanup();
77 static void onhup();
78 static void onint();
79 static void onusr1();
80 static void onusr2();
81 static void onalarm();
82 static void onchld();
83
84 int is_symlink(const char*);
85 void check_stats();
86 char *version();
87
88 /* Length of saved portion of packet */
89 int snaplen = DEFAULT_SNAPLEN;
90
91 /*static*/ pcap_t *pd;
92
93 int
main(argc,argv)94 main(argc, argv)
95 int argc;
96 char **argv;
97 {
98 struct bpf_program *parse();
99 void bpf_dump(), usage(), printver(), check_stats();
100
101 register int op, cnt = -1, i;
102 struct bpf_program fcode;
103 register char *cp, *infile = NULL, *cmdbuf, *DevFileName = NULL;
104 FILE *fd;
105 pcap_handler printer;
106 u_char *pcap_userdata;
107 char ebuf[PCAP_ERRBUF_SIZE];
108 extern char *optarg;
109 extern int optind, opterr;
110 bpf_u_int32 localnet, netmask;
111
112 if ((cp = strrchr(argv[0], '/')) != NULL)
113 program_name = cp + 1;
114 else
115 program_name = argv[0];
116
117 opterr = 0;
118 while ((op = getopt(argc, argv, "c:df:F:i:OprVXm:")) != EOF)
119 switch (op) {
120 case 'c':
121 cnt = atoi(optarg);
122 break;
123 case 'd':
124 ++dflag;
125 break;
126 case 'f':
127 DevFileName = optarg;
128 break;
129 case 'F':
130 infile = optarg;
131 break;
132 case 'i':
133 device_name = optarg;
134 break;
135 case 'm':
136 minsize = strtoul(optarg, NULL,10);
137 break;
138 case 'O':
139 Oflag = 0;
140 break;
141 case 'p':
142 ++pflag;
143 break;
144 case 'r':
145 ++rflag;
146 break;
147 case 'X':
148 Xflag=0;
149 break;
150 case 'V':
151 printver();
152 return 0;
153 break;
154 default:
155 usage();
156 }
157
158 if (access(_PATH_VARRUN, R_OK|W_OK|X_OK) < 0) { /* ITS4: ignore */
159 snprintf(file_pid, PATH_MAX,"%s: access to %s", program_name,
160 _PATH_VARRUN);
161 perror(file_pid);
162 exit(1);
163 }
164 if (access(PATH_TOSAVE, R_OK|W_OK|X_OK) < 0) { /* ITS4: ignore */
165 snprintf(file_save, PATH_MAX, "%s: access to %s", program_name,
166 PATH_TOSAVE);
167 perror(file_save);
168 exit(1);
169 }
170 if (device_name == 0)
171 if ((device_name = getenv("IFF_LISTEN")) == NULL)
172 if ((device_name = pcap_lookupdev(ebuf)) == 0)
173 error("%s", ebuf);
174 if (DevFileName == NULL)
175 DevFileName = device_name;
176
177 /* Attach bpf interface to network interface */
178 pd = pcap_open_live(device_name, snaplen, !pflag, 1000, ebuf);
179 if (pd == NULL)
180 error("%s", ebuf);
181
182 i = pcap_snapshot(pd);
183 if (snaplen < i) {
184 warning("snaplen raised from %d to %d", snaplen, i);
185 snaplen = i;
186 }
187
188 if (pcap_lookupnet(device_name, &localnet, &netmask, ebuf) < 0) {
189 localnet = 0;
190 netmask = 0;
191 warning("%s", ebuf);
192 }
193
194 if (infile!=NULL)
195 cmdbuf = read_infile(infile);
196 else
197 cmdbuf = copy_argv(&argv[optind]);
198
199 if(pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
200 error("%s", pcap_geterr(pd));
201
202 if (dflag) {
203 bpf_dump(&fcode, dflag);
204 #if USE_EXIT
205 exit(0);
206 #else
207 return 0;
208 #endif
209 }
210 init_addrtoname(localnet, netmask);
211
212 /* Catch signals */
213 flag_int = flag_hup = flag_usr1 = 0;
214 (void)signal(SIGTERM, cleanup);
215 (void)signal(SIGQUIT, cleanup);
216 (void)signal(SIGPIPE, SIG_IGN);
217 (void)signal(SIGINT, onint);
218 (void)signal(SIGHUP, onhup);
219 (void)signal(SIGUSR1, onusr1);
220 (void)signal(SIGUSR2, onusr2);
221 (void)signal(SIGALRM, onalarm);
222 (void)signal(SIGCHLD, onchld);
223
224 /* Initialize file names */
225 snprintf(file_pid, PATH_MAX, "%s%s.%s", _PATH_VARRUN, program_name, device_name);
226 snprintf(file_dump, PATH_MAX, "%s%s.%s", _PATH_VARTMP, program_name, DevFileName);
227 snprintf(file_save, PATH_MAX, "%s%s.%s", PATH_TOSAVE, program_name, DevFileName);
228 snprintf(file_tmp, PATH_MAX, "%stmp.%s", PATH_TOSAVE, DevFileName);
229 snprintf(file_fifo, PATH_MAX, "%s%s.%s", _PATH_TMP, program_name, device_name);
230
231 /* Check for symlinks */
232 if( access(file_dump,F_OK) ){
233 /* create file & set access mask */
234 /* fd = fopen(file_dump,"w");
235 fchmod(fd,TMP_UMASK);
236 fclose(fd);
237 */ }
238 else if( is_symlink(file_dump) ) /*ITS4: ignore*/
239 error("%s is symlink", file_dump);
240 if( !access(file_save,F_OK) && is_symlink(file_save) ) /*ITS4: ignore*/
241 error("%s is symlink", file_save);
242 if( !access(file_fifo,F_OK) && is_symlink(file_fifo) ) /*ITS4: ignore*/
243 error("%s is symlink", file_fifo);
244
245 /* Todo: Need check for old pidfile */
246 if (access(file_pid, F_OK) == 0) /* ITS4: ignore */
247 error("unexpected pidfile, probable interface '%s' already listen",
248 device_name);
249
250 check_stats();
251
252 /* Jump to background */
253 daemon(1, 0);
254 if ((fd = fopen(file_pid, "w")) == NULL) /* ITS4: ignore */
255 #if USE_EXIT
256 exit(1);
257 #else
258 return 1;
259 #endif
260
261 fprintf(fd,"%d\n", getpid()); /* ITS4: ignore */
262 fclose(fd);
263
264 /* openlog(program_name, LOG_PID|LOG_CONS, LOG_DAEMON);*/
265 openlog(program_name, LOG_PID|LOG_CONS, SYSLOG_FACILITY); /*ITS4: ignore*/
266 syslog(LOG_NOTICE, "(%s) traffic collector started", device_name); /* ITS4: ignore */
267
268 if (pcap_setfilter(pd, &fcode) < 0)
269 error("%s", pcap_geterr(pd));
270
271 printer = lookup_printer(pcap_datalink(pd));
272 pcap_userdata = 0;
273 /* Start read from bpf */
274 if (!traf_init(rflag)) {
275 if (pcap_loop(pd, cnt, printer, pcap_userdata))
276 /* Clear exit */
277 cleanup();
278 } else
279 errno = ENOMEM;
280
281 pcap_close(pd);
282 /* Abnormal termination */
283 (void)syslog(LOG_ERR, "(%s) traffic collector aborted: %m", /* ITS4: ignore */
284 device_name);
285 #if USE_EXIT
286 exit(1);
287 #endif
288 return 1;
289 }
290
291 /* make a clean exit on interrupts */
292 static void
cleanup()293 cleanup()
294 {
295
296 struct pcap_stat stat;
297
298 traf_save(file_dump, "w");
299 if (!pcap_stats(pd, &stat))
300 (void)syslog(LOG_INFO, "(%s) packets: received %d, dropped %d", /* ITS4: ignore */
301 device_name, stat.ps_recv, stat.ps_drop);
302 pcap_close(pd);
303 unlink(file_pid); /* ITS4: ignore */
304 pd = NULL;
305 (void)syslog(LOG_NOTICE, "(%s) traffic collector stopped", device_name); /* ITS4: ignore */
306 exit(0);
307 }
308
309 #define WAIT_ACTION 5
310
311 static void
onhup()312 onhup()
313 {
314 alarm(WAIT_ACTION);
315 flag_hup++;
316 }
317
318 static void
onint()319 onint()
320 {
321 alarm(WAIT_ACTION);
322 flag_int++;
323 }
324
325 static void
onusr1()326 onusr1()
327 {
328 flag_usr1++;
329 }
330
331 static void
onusr2()332 onusr2()
333 {
334 flag_usr1 = 0;
335 traf_pipe();
336 }
337
338 static void
onalarm()339 onalarm()
340 {
341 alarm(0);
342 if (flag_hup) {
343 flag_hup = 0;
344 traf_save(file_dump, "w");
345 }
346 if (flag_int) {
347 flag_int = 0;
348 traf_save(file_save, "a");
349 traf_clear();
350 }
351 }
352
353 static void
onchld()354 onchld()
355 {
356 if (wait(0) == -1)
357 (void)syslog(LOG_WARNING, "(%s) wait: %m", device_name); /* ITS4: ignore */
358 }
359
360
361 void
printver()362 printver()
363 {
364
365 fprintf(stderr, /* ITS4: ignore */
366 "trafd v%s - tcp/udp data traffic collector daemon (BPFT project)\n\n",
367 version() );
368 }
369
370 void
usage()371 usage()
372 {
373 printver();
374 fprintf(stderr, /* ITS4: ignore */
375 "Usage: %s [-dOprVX] [-c count] [-i iface] [-f ext] [-m minsize] [-F file | expr]\n", program_name);
376 exit(-1);
377 }
378
379
380 /* Check status of the interface and print warnings if needed */
check_stats()381 void check_stats()
382 { struct pcap_stat pcap_status={0,0,0};
383
384 if( pcap_stats(pd, &pcap_status) )
385 warning("(%s) packets dropping checks not avaiable (pcap_stats(): %s)",
386 device_name, pcap_geterr(pd) );
387 else if( pcap_status.ps_ifdrop )
388 warning("(%d) drops by interface %s not yet supported, data loss is possible",
389 pcap_status.ps_ifdrop, device_name );
390 }
391
is_symlink(path)392 int is_symlink(path)
393 const char *path;
394 {
395 struct stat st,lst;
396
397 lstat( path, &lst ); /*ITS4: ignore*/
398 stat( path, &st ); /*ITS4: ignore*/
399 return ( lst.st_dev!=st.st_dev || lst.st_ino!=st.st_ino );
400 }
401