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: traflog.c,v 1.12 2003/10/27 13:28:17 bartosh 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 /* traflog.c - tcp/udp data traffic log manager */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <time.h>
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netdb.h>
35 #include <pcap.h>
36
37 #include "interface.h"
38 #include "addrtoname.h"
39 #include "traffic.h"
40 #include "traflog.h"
41
42 static unsigned no = 0;
43 static int n_call = 0;
44 static int n_pat = 0;
45
46 static struct t_entry *sum = NULL;
47
48 static struct pat_mask {
49 struct in_addr in_ip, out_ip;
50 struct in_addr in_mask, out_mask;
51 u_char ip_protocol;
52 u_short p_port;
53 } *pat = NULL;
54
55 /* struct t_header defined in the traffic.h */
56 static struct t_header s;
57
58 u_long
addrmask(addr)59 addrmask(addr)
60 u_long addr;
61 {
62 register u_long m = INADDR_NONE;
63
64 if (addr)
65 while (!(addr & IN_CLASSA_NET))
66 addr <<= IN_CLASSC_NSHIFT, m >>= IN_CLASSC_NSHIFT;
67 else
68 m = INADDR_ANY;
69
70 return m;
71 }
72
73 char *
hostnetstr(in,mask)74 hostnetstr(in, mask)
75 struct in_addr in;
76 u_long mask;
77 {
78 char *cp = NULL;
79 static char line[MAXHOSTNAMELEN + 1];
80 register u_long i;
81
82 i = ntohl(in.s_addr);
83 NTOHL(mask);
84 i &= mask;
85 if (!i) {
86 strcpy(line, "all");
87 return line;
88 }
89 if (!(htonl(i) ^ in.s_addr) && addrmask(in.s_addr) == INADDR_NONE) {
90 strncpy(line, ipaddr_string(&in), sizeof(line));
91 line[sizeof(line)]=0;
92 return line;
93 }
94 if (!nflag) {
95 register u_long net = i;
96 struct netent *np = NULL;
97
98 while ((mask & 1) == 0)
99 mask >>= 1, net >>= 1;
100 if ((np = getnetbyaddr(net, AF_INET)) != NULL)
101 cp = np->n_name;
102 }
103 #define C(x) (unsigned)((x) & 0xff)
104 if (cp) {
105 strncpy(line, cp, sizeof(line) - 1);
106 line[sizeof(line)]=0;
107 }
108 else if ((i & 0xffffff) == 0)
109 sprintf(line, "%u", C(i >> 24));
110 else if ((i & 0xffff) == 0)
111 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16));
112 else if ((i & 0xff) == 0)
113 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
114 else
115 sprintf(line, "%u.%u.%u.%u", C(i >> 24),
116 C(i >> 16), C(i >> 8), C(i));
117 return line;
118 }
119
120 int
pat_print()121 pat_print()
122 {
123 register int i;
124 char port[16], proto[16];
125 struct servent *svc;
126
127 printf("%-24s %-24s %-10s %s\n", "From", "To", "Port", "Protocol");
128 for (i = 0; i < n_pat; i++) {
129 printf("%-24.24s ", hostnetstr(pat[i].in_ip,
130 pat[i].in_mask.s_addr));
131 printf("%-24.24s ", hostnetstr(pat[i].out_ip,
132 pat[i].out_mask.s_addr));
133 port[0] = proto[0] = 0;
134 if (pat[i].p_port) {
135 register int p = htons(pat[i].p_port);
136 if (pat[i].ip_protocol != IPPROTO_UDP)
137 if ((svc = getservbyport(p, "tcp")) != NULL) {
138 strncpy(port, svc->s_name, sizeof(port));
139 port[sizeof(port)]=0;
140 strcpy(proto, "tcp ");
141 }
142 if (pat[i].ip_protocol != IPPROTO_TCP)
143 if ((svc = getservbyport(p, "udp")) != NULL) {
144 if (!port[0]) {
145 strncpy(port, svc->s_name, sizeof(port));
146 port[sizeof(port)]=0;
147 }
148 strcpy(proto, "udp");
149 }
150 if (port[0] && !nflag)
151 printf("%-10.10s ", port);
152 else
153 printf("%-10d ", pat[i].p_port);
154 } else {
155 printf("%-10.10s ", "all");
156 if (pat[i].ip_protocol == IPPROTO_TCP)
157 strcpy(proto, "tcp");
158 if (pat[i].ip_protocol == IPPROTO_UDP)
159 strcpy(proto, "udp");
160 }
161 printf("%s\n", proto[0] ? proto : "tcp udp");
162 }
163 return 0;
164 }
165
166 u_long
strhostnet(cmdarg,mask)167 strhostnet(cmdarg, mask)
168 char *cmdarg;
169 u_long *mask;
170 {
171 struct in_addr in;
172 struct netent *np;
173 struct hostent *hp;
174
175 if ((in.s_addr = inet_network(cmdarg)) != INADDR_NONE) {
176 net_mask(&in.s_addr);
177 HTONL(in.s_addr);
178 *mask = addrmask(in.s_addr);
179 return in.s_addr;
180 }
181 if (!strcasecmp(cmdarg, "all")) {
182 *mask = INADDR_ANY;
183 return INADDR_ANY;
184 }
185 if ((np = getnetbyname(cmdarg)) != NULL) {
186 in.s_addr = np->n_net;
187 *mask = htonl(net_mask(&in.s_addr));
188 return htonl(in.s_addr);
189 }
190 if ((hp = gethostbyname(cmdarg)) != NULL) {
191 in.s_addr = *(u_long *)*hp->h_addr_list;
192 *mask = addrmask(in.s_addr);
193 return in.s_addr;
194 }
195 error("unknown host or network '%s'", cmdarg);
196 }
197
198 int
iscmd(token)199 iscmd(token)
200 register char *token;
201 {
202 if (!strcasecmp(token, "from"))
203 return FROM;
204 if (!strcasecmp(token, "to"))
205 return TO;
206 if (!strcasecmp(token, "port"))
207 return PORT;
208 if (!strcasecmp(token, "proto"))
209 return PROTO;
210 if (!strcasecmp(token, "mask"))
211 return MASK;
212 return NOCMD;
213 }
214
215 void
alloc_pat()216 alloc_pat()
217 {
218 if ((pat = realloc(pat, ++n_pat * sizeof(struct pat_mask))) == NULL)
219 error("can't reallocate memory");
220 if (n_pat > 1)
221 bcopy(pat + n_pat-2, pat + n_pat-1, sizeof(struct pat_mask));
222 else
223 bzero(pat, sizeof(struct pat_mask));
224 }
225
226 /* Decode command line parameters */
227 void
pattern(cmdbuf)228 pattern(cmdbuf)
229 char *cmdbuf;
230 {
231 register int cmd, cmdp = MASK;
232 register char *cmdarg;
233 char *token;
234 struct servent *svc;
235
236 if (cmdbuf)
237 while ((token = strtok(cmdbuf, " \t\r\n")) != NULL) {
238 if (*token == '#' || *token == ';')
239 continue;
240 if ((cmd = iscmd(token)) == NOCMD)
241 error("unknown keyword '%s'", token);
242 if (!(cmdarg = strtok(NULL, " \t\r\n")))
243 error("keyword '%s': missing argument", token);
244 if (cmd <= cmdp)
245 alloc_pat();
246 switch (cmd) {
247 case FROM:
248 pat[n_pat-1].in_ip.s_addr = strhostnet(cmdarg,
249 &pat[n_pat-1].in_mask.s_addr);
250 break;
251 case TO:
252 pat[n_pat-1].out_ip.s_addr = strhostnet(cmdarg,
253 &pat[n_pat-1].out_mask.s_addr);
254 break;
255 case MASK:
256 switch(cmdp) {
257 case FROM:
258 pat[n_pat-1].in_mask.s_addr = inet_addr(cmdarg);
259 break;
260 case TO:
261 pat[n_pat-1].out_mask.s_addr = inet_addr(cmdarg);
262 break;
263 default:
264 error("inconsistent usage '%s %s'", token, cmdarg);
265 }
266 cmd = cmdp;
267 break;
268 case PORT:
269 if (!(pat[n_pat-1].p_port = (u_short)atoi(cmdarg))) {
270 if (!strcasecmp(cmdarg, "all")) {
271 pat[n_pat-1].p_port = 0;
272 break;
273 }
274 if ((svc = getservbyname(cmdarg, "tcp")) != NULL)
275 pat[n_pat-1].p_port = ntohs(svc->s_port);
276 if ((svc = getservbyname(cmdarg, "udp")) != NULL)
277 pat[n_pat-1].p_port = ntohs(svc->s_port);
278 if (!pat[n_pat-1].p_port)
279 error("unknown port '%s'", cmdarg);
280 }
281 break;
282 case PROTO:
283 if (!strcasecmp(cmdarg, "udp")) {
284 pat[n_pat-1].ip_protocol = IPPROTO_UDP;
285 break;
286 }
287 if (!strcasecmp(cmdarg, "tcp")) {
288 pat[n_pat-1].ip_protocol = IPPROTO_TCP;
289 break;
290 }
291 error("unknown protocol '%s'", cmdarg);
292 default:
293 error("unknown keyword '%s'", token);
294 }
295 cmdp = cmd;
296 cmdbuf = NULL;
297 }
298 if (!n_pat)
299 alloc_pat();
300 }
301
302
303 /* Get header from trafd.log */
304 int
getheader(fd,header)305 getheader(fd, header)
306 register FILE *fd;
307 register struct t_header *header;
308 {
309 if (fread((struct t_header *)header, sizeof(struct t_header), 1, fd) != 1) {
310 if (!feof(fd))
311 warning("fread: can't read header (error: %s", strerror(errno) );
312 return 0;
313 }
314 if (header->t_size > MAX_TO_SAVE) {
315 warning("table too big to fit into memory");
316 return 0;
317 }
318 return 1;
319 }
320
321 /*
322 * Output contents list of daemon logfile.
323 */
324 int
contents(fd,h)325 contents(fd, h)
326 register FILE *fd;
327 register struct t_header *h;
328 {
329 register int i;
330 register u_int64_t bytes = 0, psize = 0;
331 struct t_entry t;
332
333 if (!n_call && !rflag)
334 printf("\
335 # Started Dumped Data All Recs\n");
336
337 for (i = 0; i < h->t_size; i++) {
338 if (fread((struct t_entry *)&t, sizeof(struct t_entry), 1, fd) != 1) {
339 warning("fread: can't read entry");
340 return 0;
341 }
342 bytes += t.n_bytes, psize += t.n_psize;
343 }
344 if (!rflag) {
345 printf("%03d %.15s", no, ctime((time_t *)&h->start) + 4);
346 printf("%18.15s %10qu %10qu %4d\n", ctime((time_t *)&h->stop)+4,
347 bytes, psize, h->t_size);
348 }
349 return 1;
350 }
351
352
353 /* Compare trafd.log records with pattern */
354 int
patmatch(e)355 patmatch(e)
356 register struct t_entry *e;
357 {
358 register int i = 0;
359
360 if (e->in_ip.s_addr == 0)
361 return 0;
362 for (i = 0; i < n_pat; i++) {
363 if ((e->in_ip.s_addr & pat[i].in_mask.s_addr) ^
364 pat[i].in_ip.s_addr)
365 continue;
366 if ((e->out_ip.s_addr & pat[i].out_mask.s_addr) ^
367 pat[i].out_ip.s_addr)
368 continue;
369 if (pat[i].ip_protocol && e->ip_protocol != pat[i].ip_protocol)
370 continue;
371 #if LAYOUT==OLD
372 if ( !pat[i].p_port || e->p_port == pat[i].p_port )
373 #else
374 if ( !pat[i].p_port || e->p_port == pat[i].p_port
375 || e->o_port == pat[i].p_port )
376 #endif
377 break;
378 }
379 return (n_pat - i);
380 }
381
382 /* Read one record from trafd.log, test it to pattern & add values to summary */
383 int
ioblock(fd,h)384 ioblock(fd, h)
385 FILE *fd;
386 register struct t_header *h;
387 {
388 register int i, j;
389 register struct t_entry *block;
390
391 if (!sflag || !n_call) {
392 bzero((struct t_header *)&s, sizeof(struct t_header));
393 if (sum != NULL)
394 free(sum);
395 sum = NULL;
396 }
397 block = (struct t_entry *) alloca(h->t_size * sizeof(struct t_entry));
398 if (block == NULL) {
399 warning("traflog.c:ioblock(): alloca: can't allocate memory");
400 return 0;
401 }
402 if (fread((struct t_entry *)block, sizeof(struct t_entry), h->t_size,
403 fd) != h->t_size) {
404 warning("traflog.c:ioblock(): fread: can't read table");
405 return 0;
406 }
407 for (i = 0; i < h->t_size; i++) {
408 if (!patmatch(block + i))
409 continue;
410 for (j = 0; j < s.t_size; j++) {
411 if (block[i].in_ip.s_addr == sum[j].in_ip.s_addr &&
412 block[i].out_ip.s_addr == sum[j].out_ip.s_addr &&
413 block[i].ip_protocol == sum[j].ip_protocol &&
414 #if LAYOUT==OLD
415 block[i].who_srv == sum[j].who_srv &&
416 #else
417 block[i].o_port == sum[j].o_port &&
418 #endif
419 block[i].p_port == sum[j].p_port) {
420 sum[j].n_bytes += block[i].n_bytes;
421 sum[j].n_psize += block[i].n_psize;
422 break;
423 }
424 }
425 if (j < s.t_size)
426 continue;
427 sum = (struct t_entry *) realloc(sum, ++s.t_size *
428 sizeof(struct t_entry));
429 if (sum == NULL) {
430 warning("traflog.c:ioblock(): realloc: can't reallocate memory");
431 return 0;
432 }
433 bcopy(block + i, sum + j, sizeof(struct t_entry));
434 }
435 if (!s.start.tv_sec)
436 s.start = h->start;
437 s.stop = h->stop;
438 return 1;
439 }
440
range(h)441 static int range(h)
442 register struct t_header *h;
443 {
444 register int true = 0;
445
446 if (tbflag) {
447 if (tb.tv_sec <= h->start.tv_sec)
448 ++true;
449 } else {
450 if (begin <= no)
451 ++true;
452 }
453 if (teflag) {
454 if (te.tv_sec >= h->stop.tv_sec)
455 ++true;
456 } else {
457 if (endin >= no)
458 ++true;
459 }
460 return true;
461 }
462
traf_write(fd)463 void traf_write(fd)
464 FILE *fd;
465 {
466 if (fwrite((struct t_header *)&s, sizeof(struct t_header), 1, fd) != 1)
467 error("write header error");
468 if (fwrite((struct t_entry *)sum, sizeof(struct t_entry), s.t_size, fd) != s.t_size)
469 error("write table error");
470 }
471
472
473 int
sortbyfrom(left,right)474 sortbyfrom(left, right)
475 register struct t_entry *left;
476 register struct t_entry *right;
477 {
478 if (htonl(left->in_ip.s_addr) < htonl(right->in_ip.s_addr))
479 return LESS;
480 if (htonl(left->in_ip.s_addr) > htonl(right->in_ip.s_addr))
481 return GREATER;
482 return EQUAL;
483 }
484
485 int
sortbyto(left,right)486 sortbyto(left, right)
487 register struct t_entry *left;
488 register struct t_entry *right;
489 {
490 if (htonl(left->out_ip.s_addr) < htonl(right->out_ip.s_addr))
491 return LESS;
492 if (htonl(left->out_ip.s_addr) > htonl(right->out_ip.s_addr))
493 return GREATER;
494 return EQUAL;
495 }
496
497 int
sortbypport(left,right)498 sortbypport(left, right)
499 register struct t_entry *left;
500 register struct t_entry *right;
501 {
502 if (htons(left->p_port) < htons(right->p_port))
503 return LESS;
504 if (htons(left->p_port) > htons(right->p_port))
505 return GREATER;
506 return EQUAL;
507 }
508
509 #if LAYOUT!=OLD
510 int
sortbyoport(left,right)511 sortbyoport(left, right)
512 register struct t_entry *left;
513 register struct t_entry *right;
514 {
515 if (htons(left->o_port) < htons(right->o_port))
516 return LESS;
517 if (htons(left->o_port) > htons(right->o_port))
518 return GREATER;
519 return EQUAL;
520 }
521 #endif
522
523 int
sortbysize(left,right)524 sortbysize(left, right)
525 register struct t_entry *left;
526 register struct t_entry *right;
527 {
528 if (left->n_psize < right->n_psize)
529 return GREATER;
530 if (left->n_psize > right->n_psize)
531 return LESS;
532 return EQUAL;
533 }
534
535
traf_print()536 void traf_print()
537 {
538 register int i, j;
539 u_int64_t abytes = 0, dbytes = 0;
540 struct protoent *protoent_p; /* for getprotobynumber() */
541
542 char buf[MAXHOSTNAMELEN + 1];
543 #if LAYOUT==OLD
544 char *port, *user, *proto;
545 #else
546 char *s_port, *d_port, *proto;
547 #endif
548 for (i = 0; i < s.t_size; i++)
549 abytes += sum[i].n_psize, dbytes += sum[i].n_bytes;
550 if (rflag) {
551 printf("%qu\n", abytes);
552 return;
553 }
554 qsort(sum, s.t_size, sizeof(struct t_entry), sortbysize);
555 switch ( order ){
556 case ORDER_TO:
557 qsort(sum, s.t_size, sizeof(struct t_entry), sortbyto);
558 break;
559 case ORDER_FROM:
560 qsort(sum, s.t_size, sizeof(struct t_entry), sortbyfrom);
561 break;
562 case ORDER_SIZE:
563 qsort(sum, s.t_size, sizeof(struct t_entry), sortbysize);
564 break;
565 case ORDER_DPORT:
566 qsort(sum, s.t_size, sizeof(struct t_entry), sortbypport);
567 break;
568 #if LAYOUT!=OLD
569 case ORDER_SPORT:
570 qsort(sum, s.t_size, sizeof(struct t_entry), sortbyoport);
571 break;
572 #endif
573 }
574 if (!fvnum) {
575 gethostname(buf, sizeof(buf));
576 printf("\n (%s) %s at", device_name, buf);
577 printf(" %.15s -", ctime((time_t *)&s.start) + 4);
578 printf(" %.15s\n", ctime((time_t *)&s.stop) + 4);
579 printf(" Summary: %qu data bytes, %qu all bytes, %u records\n",
580 dbytes, abytes, s.t_size);
581 printf("\
582 From Port To Port Proto Data All\n");
583 }
584 setprotoent(1);
585 for (i = 0; i < s.t_size; i++) {
586 #if LAYOUT==OLD
587 port = "undef";
588 #else
589 s_port = "";
590 d_port = "";
591 #endif
592 switch(sum[i].ip_protocol) {
593 case IPPROTO_TCP:
594 #if LAYOUT==OLD
595 if (sum[i].p_port)
596 port = tcpport_string(sum[i].p_port);
597 #else
598 if (sum[i].p_port || sum[i].o_port)
599 { s_port = tcpport_string(sum[i].o_port);
600 d_port = tcpport_string(sum[i].p_port);
601 }
602 #endif
603 /* proto = "tcp"; */
604 break;
605 case IPPROTO_UDP:
606 #if LAYOUT==OLD
607 if (sum[i].p_port)
608 port = udpport_string(sum[i].p_port);
609 #else
610 if (sum[i].p_port || sum[i].o_port)
611 { s_port = udpport_string(sum[i].o_port);
612 d_port = udpport_string(sum[i].p_port);
613 }
614 #endif
615 /* proto = "udp"; */
616 break;
617 /*
618 case IPPROTO_ICMP:
619 proto = "icmp";
620 break;
621 case IPPROTO_EGP:
622 proto = "egp";
623 break;
624 case IPPROTO_OSPF:
625 proto = "ospf";
626 break;
627 case IPPROTO_IGMP:
628 proto = "igmp";
629 break;
630 default:
631 proto = "unkn";
632 */
633 }
634 /* This run slowly, hoverer support all protocols, listed
635 * in /etc/protocols */
636 if( (protoent_p = getprotobynumber(sum[i].ip_protocol)) != NULL ){
637 proto = protoent_p->p_name;
638 }else{
639 proto = "unkn";
640 }
641
642 #if LAYOUT==OLD
643 if (sum[i].p_port) user = "client";
644 else user = "none";
645 #endif
646 if (fvnum) {
647 for (j = 0; j < fvnum; j++)
648 switch (fv[j].cmd) {
649 case FROM:
650 printf(fv[j].format, ipaddr_string(&sum[i].in_ip));
651 break;
652 case TO:
653 printf(fv[j].format, ipaddr_string(&sum[i].out_ip));
654 break;
655 #if LAYOUT==OLD
656 case SPORT:
657 printf(fv[j].format,
658 (sum[i].who_srv & 1) ? port : user);
659 break;
660 case DPORT:
661 printf(fv[j].format,
662 (sum[i].who_srv & 2) ? port : user);
663 break;
664 #else
665 case SPORT:
666 printf(fv[j].format,
667 s_port);
668 break;
669 case DPORT:
670 printf(fv[j].format,
671 d_port);
672 break;
673 #endif
674 case PROTO:
675 printf(fv[j].format, proto);
676 break;
677 case BYTES:
678 printf(fv[j].format, sum[i].n_bytes);
679 break;
680 case PSIZE:
681 printf(fv[j].format, sum[i].n_psize);
682 break;
683 case FTIME:
684 strftime(buf, sizeof(buf), fv[j].format,
685 localtime((time_t *)&s.start));
686 printf("%s", buf);
687 break;
688 case LTIME:
689 strftime(buf, sizeof(buf), fv[j].format,
690 localtime((time_t *)&s.stop));
691 printf("%s", buf);
692 break;
693 }
694 } else {
695 #if LAYOUT==OLD
696 printf("%-18.18s %-6.6s ", ipaddr_string(&sum[i].in_ip),
697 (sum[i].who_srv & 1) ? port : user);
698 printf("%-18.18s %-6.6s ", ipaddr_string(&sum[i].out_ip),
699 (sum[i].who_srv & 2) ? port : user);
700 printf("%-4.4s %9lu %10lu\n", proto, sum[i].n_bytes,
701 sum[i].n_psize);
702 #else
703 printf("%-18.18s %-6.6s ", ipaddr_string(&sum[i].in_ip),
704 s_port);
705 printf("%-18.18s %-6.6s ", ipaddr_string(&sum[i].out_ip),
706 d_port);
707 printf("%-4.4s %9lu %10lu\n", proto, sum[i].n_bytes,
708 sum[i].n_psize);
709 #endif
710 }
711 }
712 endprotoent();
713 }
714
715 /* Read trafd.log cycle */
716 void
log_loop(fd,fdw)717 log_loop(fd, fdw)
718 register FILE *fd;
719 FILE *fdw;
720 {
721 struct t_header h;
722 int retval;
723
724 while (getheader(fd, &h)) {
725 no++;
726 if (range(&h) == 2) {
727 if (lflag) retval = contents(fd, &h);
728 else retval = ioblock(fd, &h);
729 if (retval) n_call++;
730 else {
731 warning( "Error reading data file\n" );
732 break;
733 }
734 if (aflag && !sflag) {
735 if (fdw) traf_write(fdw);
736 else traf_print();
737 }
738 } else
739 fseek(fd, h.t_size * sizeof(struct t_entry), SEEK_CUR);
740 }
741 if (aflag && !sflag)
742 return;
743 if (lflag) {
744 if (rflag)
745 printf("%d\n", n_call);
746 return;
747 }
748 if (fdw) traf_write(fdw);
749 else traf_print();
750
751 return;
752 }
753