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