1 /*
2 * Copyleft (c) 2001 Grumbler <g@grumbler.org>
3 *
4 * Copyright (c) 1999 RISS-Telecom Networking Center
5 *
6 * Copyright (c) 1993 The CAD lab of the
7 * Novosibirsk Institute of Broadcasting and Telecommunication
8 *
9 * BPFT $Id: main.c,v 1.12 2003/12/30 12:59:05 stas_degteff Exp $
10 *
11 *
12 * Redistribution and use in source forms, with and without modification,
13 * are permitted provided that this entire comment appears intact.
14 * Redistribution in binary form may occur without any restrictions.
15 *
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
17 */
18
19 /* main.c - tcp/udp data traffic log manager */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <paths.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <sys/stat.h>
32 #include <sys/param.h>
33 #include <pcap.h>
34 #if defined(__linux__)
35 #include <time.h>
36 #endif
37 #include "../include/interface.h"
38 #include "../include/addrtoname.h"
39 #include "../include/pathnames.h"
40 #include "traflog.h"
41
42 int aflag=0; /* display all records, default last */
43 int fflag=0; /* convert addresses to names only for local hosts */
44 int lflag=0; /* output list of log file records */
45 int nflag=0; /* don't convert addresses to host names */
46 int Nflag=0; /* output host names without domain */
47 int rflag=0; /* only return number of records or KB */
48 int sflag=0; /* summary traffic */
49 unsigned short order=ORDER_TO; /* sorting order */
50
51 #define LASTOFFSET ((unsigned)-1) /* max unsigned value */
52 unsigned begin = 0, endin = LASTOFFSET;
53 int tbflag = 0, teflag = 0;
54 struct timeval tb, te;
55
56 char *device_name = NULL;
57 char *program_name, *f_end;
58
59 static time_t tval;
60
61 int fvnum = 0;
62 struct fmt_var *fv = NULL;
63
64 char *version();
65 static void setthetime(register char *,struct timeval *);
66 static int get_format(char *);
67 static int iskey(char *);
68
69 int
main(argc,argv)70 main(argc, argv)
71 int argc;
72 char **argv;
73 {
74 register FILE *fd;
75 FILE *fdw = NULL;
76 register int op;
77 int dflag = 0; /* dump pattern */
78 char buf[PATH_MAX], *cmdbuf, *infile = NULL;
79 char ebuf[PCAP_ERRBUF_SIZE];
80 extern char *optarg;
81 extern int optind, opterr;
82 bpf_u_int32 localnet, netmask;
83 void usage(), onpipe(), printver();
84
85 program_name = stripdir(argv[0]);
86
87 if (time(&tval) == -1)
88 error("error in function 'time'");
89
90 opterr = 0;
91 while ((op = getopt(argc, argv, "ab:de:fF:i:lnNo:rsw:S:V")) != EOF)
92 switch (op) {
93 case 'a':
94 ++aflag;
95 break;
96 case 'b':
97 if( optarg[0]=='#' )
98 { if( !(begin = atoi(optarg+1)) )
99 usage();
100 }
101 else if( (begin = atoi(optarg))>0 )
102 {
103 setthetime(optarg, &tb);
104 ++tbflag;
105 }
106 else usage();
107 break;
108 case 'd':
109 ++dflag;
110 break;
111 case 'e':
112 if( optarg[0]=='#' )
113 { if (!(endin = atoi(optarg+1)))
114 usage();
115 }
116 else if ( (endin=atoi(optarg)) > 0 ) {
117 setthetime(optarg, &te);
118 ++teflag;
119 }
120 break;
121 case 'f':
122 ++fflag;
123 break;
124 case 'F':
125 infile = optarg;
126 break;
127 case 'i':
128 device_name = optarg;
129 break;
130 case 'l':
131 if (sflag)
132 usage();
133 ++lflag;
134 break;
135 case 'n':
136 ++nflag;
137 break;
138 case 'N':
139 ++Nflag;
140 break;
141 case 'o':
142 if (!get_format(optarg))
143 error("output format '%s' not found", optarg);
144 break;
145 case 'r':
146 ++rflag;
147 break;
148 case 's':
149 if (lflag)
150 usage();
151 ++sflag;
152 break;
153 case 'w':
154 if ((fdw = fopen(optarg, "w")) == NULL)
155 error("can't write to %s", optarg);
156 break;
157 case 'S':
158 if( !*optarg )
159 usage();
160 switch (*optarg){
161 case 't': order = ORDER_TO; break;
162 case 'f': order = ORDER_FROM; break;
163 case 'b': order = ORDER_SIZE; break;
164 #if LAYOUT!=OLD
165 case 'd': order = ORDER_DPORT; break;
166 #endif
167 case 's': order = ORDER_SPORT; break;
168 default:
169 fprintf( stderr, "\n\tIllegal sort order parameter!\n\n" );
170 usage();
171 }
172 break;
173 case 'V':
174 printver();
175 break;
176 default:
177 usage();
178 }
179
180 signal(SIGPIPE, onpipe);
181
182 if (infile) {
183 if ((cmdbuf = getenv("PATTERNPATH")) != NULL) {
184 infile = stripdir(infile);
185 snprintf(buf, sizeof(buf), "%s/%s", cmdbuf, infile);
186 infile = buf;
187 }
188 cmdbuf = read_infile(infile);
189 } else
190 cmdbuf = copy_argv(&argv[optind]);
191
192 pattern(cmdbuf);
193 if (dflag)
194 exit(pat_print());
195
196 if (device_name == 0) {
197 if ((device_name = getenv("IFF_LISTEN")) == NULL)
198 if ((device_name = pcap_lookupdev(ebuf)) == 0)
199 error("%s", ebuf);
200 } else {
201 struct stat st;
202 if ( !stat(device_name, &st) && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
203 localnet = netmask = 0;
204 else {
205 if (pcap_lookupnet(device_name, &localnet, &netmask, ebuf) < 0) {
206 localnet = netmask = 0;
207 warning("%s", ebuf);
208 }
209 }
210 }
211
212 init_addrtoname(localnet, netmask);
213
214 if ( !(localnet || netmask) ) { /* device_name is the file name */
215 strncpy(buf, device_name, sizeof(buf));
216 buf[sizeof(buf)]=0;
217 } else /* device_name is the device name */
218 snprintf(buf, sizeof(buf), "%strafd.%s", PATH_TOSAVE, device_name);
219
220 if ((fd = fopen(buf, "r")) == NULL)
221 error("can't open %s", buf);
222
223 log_loop(fd, fdw);
224 fclose(fd);
225 if(fdw) fclose(fdw);
226 exit(0);
227 }
228
229 static int
get_format(f_name)230 get_format(f_name)
231 char *f_name;
232 {
233 int cmnt, f_len = strlen(f_name);
234 static char *dflt = PATH_TRAFLOG_FMT;
235 char *f_fmt;
236 register char *ptr;
237 struct stat st;
238
239 if ((f_fmt = getenv("FORMATPATH")) == NULL)
240 f_fmt = dflt;
241 if ((cmnt = open(f_fmt, O_RDONLY)) < 0)
242 error("can't open %s", f_fmt);
243 if (fstat(cmnt, &st) < 0)
244 error("can't fstat %s", f_fmt);
245 if ((f_fmt = malloc(st.st_size)) == NULL)
246 error("can't allocate memory");
247 if (read(cmnt, f_fmt, st.st_size) != st.st_size)
248 error("can't read format file");
249 close(cmnt);
250 cmnt = 0;
251 f_end = f_fmt + st.st_size;
252 for (ptr = f_fmt; ptr < f_end; ptr++) {
253 if (*ptr == '\n') {
254 cmnt = 0;
255 continue;
256 }
257 if (*ptr == '#') {
258 cmnt++;
259 continue;
260 }
261 if (cmnt)
262 continue;
263 if (f_len) {
264 if (!strncmp(ptr, f_name, f_len))
265 f_len = 0;
266 continue;
267 }
268 if (*ptr == '}' && (*(ptr+1) == ';' || *(ptr+2) == ';'))
269 break;
270 ptr += iskey(ptr);
271 }
272 return fvnum;
273 }
274
275 static int
isformat(fmt)276 isformat(fmt)
277 char *fmt;
278 {
279 int i;
280 char *ptr;
281 char *str[2];
282
283 ptr = fmt;
284 for (i = 0; i < 2; i++)
285 if ((ptr = memchr(ptr, '"', f_end - ptr)) != NULL) {
286 str[i] = ptr;
287 ptr += 3;
288 } else
289 return 0;
290 ++str[0];
291 *str[1] = 0;
292 if (strchr(str[0], '%') == NULL)
293 return 0;
294 while ((ptr = strrchr(str[0], '\\')) != NULL) {
295 switch (*(ptr+1)) {
296 case 'a':
297 *ptr = 0x07; /* BEL */
298 break;
299 case 'b':
300 *ptr = 0x08; /* BS */
301 break;
302 case 'f':
303 *ptr = 0x0c; /* FF */
304 break;
305 case 'n':
306 *ptr = 0x0a; /* LF */
307 break;
308 case 'r':
309 *ptr = 0x0d; /* CR */
310 break;
311 case 't':
312 *ptr = 0x09; /* HT */
313 break;
314 case 'v':
315 *ptr = 0x0b; /* VT */
316 break;
317 default:
318 return 0;
319 }
320 bcopy(ptr+2, ptr+1,strlen(ptr+1)); /* only bcopy pass strings overlap */
321 }
322 if ((fv = realloc(fv, ++fvnum * sizeof(struct fmt_var))) == NULL)
323 error("can't reallocate memory");
324 fv[fvnum-1].format = str[0];
325
326 return (str[1] - fmt);
327 }
328
329 static int
iskey(token)330 iskey(token)
331 char *token;
332 {
333 int i;
334
335 if (!strncmp(token, "from", 4)) {
336 if ((i = isformat(token + 4)))
337 fv[fvnum-1].cmd = FROM;
338 return i+4;
339 }
340 if (!strncmp(token, "to", 2)) {
341 if ((i = isformat(token + 2)))
342 fv[fvnum-1].cmd = TO;
343 return i+2;
344 }
345 if (!strncmp(token, "sport", 5)) {
346 if ((i = isformat(token + 5)))
347 fv[fvnum-1].cmd = SPORT;
348 return i+5;
349 }
350 if (!strncmp(token, "dport", 5)) {
351 if ((i = isformat(token + 5)))
352 fv[fvnum-1].cmd = DPORT;
353 return i+5;
354 }
355 if (!strncmp(token, "proto", 5)) {
356 if ((i = isformat(token + 5)))
357 fv[fvnum-1].cmd = PROTO;
358 return i+5;
359 }
360 if (!strncmp(token, "bytes", 5)) {
361 if ((i = isformat(token + 5)))
362 fv[fvnum-1].cmd = BYTES;
363 return i+5;
364 }
365 if (!strncmp(token, "psize", 5)) {
366 if ((i = isformat(token + 5)))
367 fv[fvnum-1].cmd = PSIZE;
368 return i+5;
369 }
370 if (!strncmp(token, "ftime", 5)) {
371 if ((i = isformat(token + 5)))
372 fv[fvnum-1].cmd = FTIME;
373 return i+5;
374 }
375 if (!strncmp(token, "ltime", 5)) {
376 if ((i = isformat(token + 5)))
377 fv[fvnum-1].cmd = LTIME;
378 return i+5;
379 }
380 return 0;
381 }
382
badformat()383 static void badformat()
384 {
385 error("illegal time format");
386 }
387
388 static int days_in_month[12] =
389 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
390
391 #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
setthetime(p,tv)392 static void setthetime(p, tv)
393 register char *p;
394 struct timeval *tv;
395 {
396 register struct tm *lt;
397 int dot;
398 char *t;
399
400 for (t = p, dot = 0; *t; ++t)
401 if (!isdigit(*t) && (*t != '.' || dot++))
402 badformat();
403
404 lt = localtime(&tval);
405
406 if ((t = index(p, '.'))) { /* .ss */
407 *t++ = '\0';
408 lt->tm_sec = ATOI2(t);
409 if (lt->tm_sec >= 60)
410 badformat();
411 } else
412 lt->tm_sec = 0;
413
414 for (t = p; *t; ++t)
415 if (!isdigit(*t))
416 badformat();
417
418 switch (strlen(p)) {
419 case 10: /* yy */
420 lt->tm_year = ATOI2(p);
421 if (lt->tm_year <= 69) /* hack for 2000 ;-} */
422 lt->tm_year += 100;
423 /* FALLTHROUGH */
424 case 8: /* mm */
425 lt->tm_mon = ATOI2(p);
426 if (lt->tm_mon > 12)
427 badformat();
428 --lt->tm_mon; /* time struct is 0 - 11 */
429 /* FALLTHROUGH */
430 case 6: /* dd */
431 lt->tm_mday = ATOI2(p);
432 if (lt->tm_mday > days_in_month[lt->tm_mon]
433 && !(((lt->tm_year % 4 == 0 && lt->tm_year % 100 != 0)
434 || lt->tm_year % 400 == 0) && lt->tm_mon == 1
435 && lt->tm_mday == 29))
436 badformat();
437 /* FALLTHROUGH */
438 case 4: /* hh */
439 lt->tm_hour = ATOI2(p);
440 if (lt->tm_hour > 23)
441 badformat();
442 /* FALLTHROUGH */
443 case 2: /* mm */
444 lt->tm_min = ATOI2(p);
445 if (lt->tm_min > 59)
446 badformat();
447 break;
448 default:
449 badformat();
450 }
451
452 /* convert broken-down time to GMT clock time */
453 if ((tval = mktime(lt)) == -1)
454 badformat();
455
456 tv->tv_sec = tval;
457 tv->tv_usec = 0;
458 }
459
460
461 void
onpipe()462 onpipe()
463 {
464 exit(1);
465 }
466
467 void
printver()468 printver()
469 {
470 fprintf(stderr,
471 "traflog v%s - tcp/udp data traffic log manager (BPFT project)\n\n",
472 version() );
473 }
474
475 void
usage()476 usage()
477 {
478 printver();
479 fprintf(stderr,
480 "Usage:\t%s -l [-i iface] [-b #] [-e #] [-rV]\n\
481 \t%s -d [-fnNV] [-F file | pattern]\n\
482 \t%s [-i iface|file] [-b #] [-e #] [-afnNrsV] [-S sortorder] [-o format] \\\n\
483 \t\t[-w file] [-F file | pattern]\n\
484 where sortorder: (from|to|bytes|srcport|dstport) or (f|t|b|s|d)\n\
485 #: (#nnn | yymmddHHMM.ss)\n",
486 program_name, program_name, program_name);
487 exit(-1);
488 }
489
490