1 /* $NetBSD: ipmon.c,v 1.9 2019/10/05 23:32:20 mrg Exp $ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 #include "ipf.h"
9 #include "ipmon.h"
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <syslog.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include <err.h>
17
18 #if !defined(lint)
19 static __attribute__((__used__)) const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed";
20 static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipmon.c,v 1.1.1.2 2012/07/22 13:44:56 darrenr Exp ";
21 #endif
22
23
24 #if defined(sun) && !defined(SOLARIS2)
25 #define STRERROR(x) sys_errlist[x]
26 extern char *sys_errlist[];
27 #else
28 #define STRERROR(x) strerror(x)
29 #endif
30
31 extern int optind;
32 extern char *optarg;
33
34 extern ipmon_saver_t executesaver;
35 extern ipmon_saver_t filesaver;
36 extern ipmon_saver_t nothingsaver;
37 extern ipmon_saver_t snmpv1saver;
38 extern ipmon_saver_t snmpv2saver;
39 extern ipmon_saver_t syslogsaver;
40
41
42 struct flags {
43 int value;
44 char flag;
45 };
46
47 typedef struct logsource {
48 int fd;
49 int logtype;
50 char *file;
51 int regular;
52 size_t size;
53 } logsource_t;
54
55 typedef struct config {
56 int opts;
57 int maxfd;
58 logsource_t logsrc[3];
59 fd_set fdmr;
60 FILE *blog;
61 char *bfile;
62 FILE *log;
63 char *file;
64 char *cfile;
65 } config_t;
66
67 typedef struct icmp_subtype {
68 int ist_val;
69 char *ist_name;
70 } icmp_subtype_t;
71
72 typedef struct icmp_type {
73 int it_val;
74 struct icmp_subtype *it_subtable;
75 size_t it_stsize;
76 char *it_name;
77 } icmp_type_t;
78
79
80 #define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t))
81
82
83 struct flags tcpfl[] = {
84 { TH_ACK, 'A' },
85 { TH_RST, 'R' },
86 { TH_SYN, 'S' },
87 { TH_FIN, 'F' },
88 { TH_URG, 'U' },
89 { TH_PUSH,'P' },
90 { TH_ECN, 'E' },
91 { TH_CWR, 'C' },
92 { 0, '\0' }
93 };
94
95 const char *reasons[] = {
96 "filter-rule",
97 "log-or-block_1",
98 "pps-rate",
99 "jumbogram",
100 "makefrip-fail",
101 "state_add-fail",
102 "updateipid-fail",
103 "log-or-block_2",
104 "decap-fail",
105 "auth_new-fail",
106 "auth_captured",
107 "coalesce-fail",
108 "pullup-fail",
109 "auth-feedback",
110 "bad-frag",
111 "natv4_out-fail",
112 "natv4_in-fail",
113 "natv6_out-fail",
114 "natv6_in-fail",
115 };
116
117 #ifdef MENTAT
118 static char *pidfile = "/etc/opt/ipf/ipmon.pid";
119 #else
120 # if BSD >= 199306
121 static char *pidfile = "/var/run/ipmon.pid";
122 # else
123 static char *pidfile = "/etc/ipmon.pid";
124 # endif
125 #endif
126
127 static char line[2048];
128 static int donehup = 0;
129 static void usage(const char *);
130 static void handlehup(int);
131 static void flushlogs(const char *, FILE *);
132 static void print_log(config_t *, logsource_t *, const void *, size_t);
133 static void print_ipflog(config_t *, const iplog_t *, const void *, size_t);
134 static void print_natlog(config_t *, const iplog_t *, const void *, size_t);
135 static void print_statelog(config_t *, const iplog_t *, const void *, size_t);
136 static int read_log(int, size_t *, void *, size_t);
137 static void write_pid(const char *);
138 static char *icmpname(u_int, u_int);
139 static char *icmpname6(u_int, u_int);
140 static icmp_type_t *find_icmptype(int, icmp_type_t *, size_t);
141 static icmp_subtype_t *find_icmpsubtype(int, icmp_subtype_t *, size_t);
142 #ifdef __hpux
143 static struct tm *get_tm(u_32_t);
144 #else
145 static struct tm *get_tm(time_t);
146 #endif
147
148 char *portlocalname(int, char *, u_int);
149
150 static void logopts(int, const char *);
151 static void init_tabs(void);
152 static char *getlocalproto(u_int);
153 static void openlogs(config_t *);
154 static int read_loginfo(config_t *);
155 static void initconfig(config_t *);
156
157 static char **protocols = NULL;
158 static char **udp_ports = NULL;
159 static char **tcp_ports = NULL;
160
161
162 #define HOSTNAMEV4(b) hostname(AF_INET, (const void *)&(b))
163
164 #ifndef LOGFAC
165 #define LOGFAC LOG_LOCAL0
166 #endif
167 int logfac = LOGFAC;
168 int ipmonopts = 0;
169 int opts = OPT_NORESOLVE;
170 int use_inet6 = 0;
171
172
173 static icmp_subtype_t icmpunreachnames[] = {
174 { ICMP_UNREACH_NET, "net" },
175 { ICMP_UNREACH_HOST, "host" },
176 { ICMP_UNREACH_PROTOCOL, "protocol" },
177 { ICMP_UNREACH_PORT, "port" },
178 { ICMP_UNREACH_NEEDFRAG, "needfrag" },
179 { ICMP_UNREACH_SRCFAIL, "srcfail" },
180 { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" },
181 { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" },
182 { ICMP_UNREACH_NET, "isolated" },
183 { ICMP_UNREACH_NET_PROHIB, "net_prohib" },
184 { ICMP_UNREACH_NET_PROHIB, "host_prohib" },
185 { ICMP_UNREACH_TOSNET, "tosnet" },
186 { ICMP_UNREACH_TOSHOST, "toshost" },
187 { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" },
188 { -2, NULL }
189 };
190
191 static icmp_subtype_t redirectnames[] = {
192 { ICMP_REDIRECT_NET, "net" },
193 { ICMP_REDIRECT_HOST, "host" },
194 { ICMP_REDIRECT_TOSNET, "tosnet" },
195 { ICMP_REDIRECT_TOSHOST, "toshost" },
196 { -2, NULL }
197 };
198
199 static icmp_subtype_t timxceednames[] = {
200 { ICMP_TIMXCEED_INTRANS, "transit" },
201 { ICMP_TIMXCEED_REASS, "reassem" },
202 { -2, NULL }
203 };
204
205 static icmp_subtype_t paramnames[] = {
206 { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" },
207 { ICMP_PARAMPROB_OPTABSENT, "optmissing" },
208 { ICMP_PARAMPROB_LENGTH, "length" },
209 { -2, NULL }
210 };
211
212 static icmp_type_t icmptypes4[] = {
213 { ICMP_ECHOREPLY, NULL, 0, "echoreply" },
214 { -1, NULL, 0, NULL },
215 { -1, NULL, 0, NULL },
216 { ICMP_UNREACH, icmpunreachnames,
217 IST_SZ(icmpunreachnames),"unreach" },
218 { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" },
219 { ICMP_REDIRECT, redirectnames,
220 IST_SZ(redirectnames), "redirect" },
221 { -1, NULL, 0, NULL },
222 { -1, NULL, 0, NULL },
223 { ICMP_ECHO, NULL, 0, "echo" },
224 { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" },
225 { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" },
226 { ICMP_TIMXCEED, timxceednames,
227 IST_SZ(timxceednames), "timxceed" },
228 { ICMP_PARAMPROB, paramnames,
229 IST_SZ(paramnames), "paramprob" },
230 { ICMP_TSTAMP, NULL, 0, "timestamp" },
231 { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" },
232 { ICMP_IREQ, NULL, 0, "inforeq" },
233 { ICMP_IREQREPLY, NULL, 0, "inforeply" },
234 { ICMP_MASKREQ, NULL, 0, "maskreq" },
235 { ICMP_MASKREPLY, NULL, 0, "maskreply" },
236 { -2, NULL, 0, NULL }
237 };
238
239 static icmp_subtype_t icmpredirect6[] = {
240 { ICMP6_DST_UNREACH_NOROUTE, "noroute" },
241 { ICMP6_DST_UNREACH_ADMIN, "admin" },
242 { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" },
243 { ICMP6_DST_UNREACH_ADDR, "address" },
244 { ICMP6_DST_UNREACH_NOPORT, "noport" },
245 { -2, NULL }
246 };
247
248 static icmp_subtype_t icmptimexceed6[] = {
249 { ICMP6_TIME_EXCEED_TRANSIT, "intransit" },
250 { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" },
251 { -2, NULL }
252 };
253
254 static icmp_subtype_t icmpparamprob6[] = {
255 { ICMP6_PARAMPROB_HEADER, "header" },
256 { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" },
257 { ICMP6_PARAMPROB_OPTION, "option" },
258 { -2, NULL }
259 };
260
261 static icmp_subtype_t icmpquerysubject6[] = {
262 { ICMP6_NI_SUBJ_IPV6, "ipv6" },
263 { ICMP6_NI_SUBJ_FQDN, "fqdn" },
264 { ICMP6_NI_SUBJ_IPV4, "ipv4" },
265 { -2, NULL },
266 };
267
268 static icmp_subtype_t icmpnodeinfo6[] = {
269 { ICMP6_NI_SUCCESS, "success" },
270 { ICMP6_NI_REFUSED, "refused" },
271 { ICMP6_NI_UNKNOWN, "unknown" },
272 { -2, NULL }
273 };
274
275 static icmp_subtype_t icmprenumber6[] = {
276 { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" },
277 { ICMP6_ROUTER_RENUMBERING_RESULT, "result" },
278 { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" },
279 { -2, NULL }
280 };
281
282 static icmp_type_t icmptypes6[] = {
283 { 0, NULL, 0, NULL },
284 { ICMP6_DST_UNREACH, icmpredirect6,
285 IST_SZ(icmpredirect6), "unreach" },
286 { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" },
287 { ICMP6_TIME_EXCEEDED, icmptimexceed6,
288 IST_SZ(icmptimexceed6), "timxceed" },
289 { ICMP6_PARAM_PROB, icmpparamprob6,
290 IST_SZ(icmpparamprob6), "paramprob" },
291 { ICMP6_ECHO_REQUEST, NULL, 0, "echo" },
292 { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" },
293 { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6,
294 IST_SZ(icmpquerysubject6), "groupmemberquery" },
295 { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" },
296 { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" },
297 { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" },
298 { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" },
299 { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" },
300 { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" },
301 { ND_REDIRECT, NULL, 0, "redirect" },
302 { ICMP6_ROUTER_RENUMBERING, icmprenumber6,
303 IST_SZ(icmprenumber6), "routerrenumber" },
304 { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" },
305 { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" },
306 { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" },
307 { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" },
308 { ICMP6_NI_QUERY, icmpnodeinfo6,
309 IST_SZ(icmpnodeinfo6), "nodeinforequest" },
310 { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" },
311 { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" },
312 { MLD6_MTRACE, NULL, 0, "mtracerequest" },
313 { -2, NULL, 0, NULL }
314 };
315
316 static icmp_subtype_t *
find_icmpsubtype(int type,icmp_subtype_t * table,size_t tablesz)317 find_icmpsubtype(int type, icmp_subtype_t *table, size_t tablesz)
318 {
319 icmp_subtype_t *ist;
320 int i;
321
322 if (tablesz < 2)
323 return NULL;
324
325 if ((type < 0) || (type > table[tablesz - 2].ist_val))
326 return NULL;
327
328 i = type;
329 if (table[type].ist_val == type)
330 return table + type;
331
332 for (i = 0, ist = table; ist->ist_val != -2; i++, ist++)
333 if (ist->ist_val == type)
334 return ist;
335 return NULL;
336 }
337
338
339 static icmp_type_t *
find_icmptype(int type,icmp_type_t * table,size_t tablesz)340 find_icmptype(int type, icmp_type_t *table, size_t tablesz)
341 {
342 icmp_type_t *it;
343 int i;
344
345 if (tablesz < 2)
346 return NULL;
347
348 if ((type < 0) || (type > table[tablesz - 2].it_val))
349 return NULL;
350
351 i = type;
352 if (table[type].it_val == type)
353 return table + type;
354
355 for (i = 0, it = table; it->it_val != -2; i++, it++)
356 if (it->it_val == type)
357 return it;
358 return NULL;
359 }
360
361
362 static void
handlehup(int sig)363 handlehup(int sig)
364 {
365 signal(SIGHUP, handlehup);
366 donehup = 1;
367 }
368
369
370 static void
init_tabs(void)371 init_tabs(void)
372 {
373 struct protoent *p;
374 struct servent *s;
375 char *name, **tab;
376 int port, i;
377
378 if (protocols != NULL) {
379 for (i = 0; i < 256; i++)
380 if (protocols[i] != NULL) {
381 free(protocols[i]);
382 protocols[i] = NULL;
383 }
384 free(protocols);
385 protocols = NULL;
386 }
387 protocols = (char **)malloc(256 * sizeof(*protocols));
388 if (protocols != NULL) {
389 bzero((char *)protocols, 256 * sizeof(*protocols));
390
391 setprotoent(1);
392 while ((p = getprotoent()) != NULL)
393 if (p->p_proto >= 0 && p->p_proto <= 255 &&
394 p->p_name != NULL && protocols[p->p_proto] == NULL)
395 protocols[p->p_proto] = strdup(p->p_name);
396 endprotoent();
397 if (protocols[0])
398 free(protocols[0]);
399 protocols[0] = strdup("ip");
400 #if defined(_AIX51)
401 if (protocols[252])
402 free(protocols[252]);
403 protocols[252] = NULL;
404 #endif
405 }
406
407 if (udp_ports != NULL) {
408 for (i = 0; i < 65536; i++)
409 if (udp_ports[i] != NULL) {
410 free(udp_ports[i]);
411 udp_ports[i] = NULL;
412 }
413 free(udp_ports);
414 udp_ports = NULL;
415 }
416 udp_ports = (char **)malloc(65536 * sizeof(*udp_ports));
417 if (udp_ports != NULL)
418 bzero((char *)udp_ports, 65536 * sizeof(*udp_ports));
419
420 if (tcp_ports != NULL) {
421 for (i = 0; i < 65536; i++)
422 if (tcp_ports[i] != NULL) {
423 free(tcp_ports[i]);
424 tcp_ports[i] = NULL;
425 }
426 free(tcp_ports);
427 tcp_ports = NULL;
428 }
429 tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports));
430 if (tcp_ports != NULL)
431 bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports));
432
433 setservent(1);
434 while ((s = getservent()) != NULL) {
435 if (s->s_proto == NULL)
436 continue;
437 else if (!strcmp(s->s_proto, "tcp")) {
438 port = ntohs(s->s_port);
439 name = s->s_name;
440 tab = tcp_ports;
441 } else if (!strcmp(s->s_proto, "udp")) {
442 port = ntohs(s->s_port);
443 name = s->s_name;
444 tab = udp_ports;
445 } else
446 continue;
447 if ((port < 0 || port > 65535) || (name == NULL))
448 continue;
449 if (tab != NULL)
450 tab[port] = strdup(name);
451 }
452 endservent();
453 }
454
455
456 static char *
getlocalproto(u_int p)457 getlocalproto(u_int p)
458 {
459 static char pnum[4];
460 char *s;
461
462 p &= 0xff;
463 s = protocols ? protocols[p] : NULL;
464 if (s == NULL) {
465 sprintf(pnum, "%u", p);
466 s = pnum;
467 }
468 return s;
469 }
470
471
472 static int
read_log(int fd,size_t * lenp,void * buf,size_t bufsize)473 read_log(int fd, size_t *lenp, void *buf, size_t bufsize)
474 {
475 ssize_t nr;
476
477 if (bufsize > IPFILTER_LOGSIZE)
478 bufsize = IPFILTER_LOGSIZE;
479
480 nr = read(fd, buf, bufsize);
481 if (!nr)
482 return 2;
483 if ((nr < 0) && (errno != EINTR))
484 return -1;
485 *lenp = nr;
486 return 0;
487 }
488
489
490 char *
portlocalname(int res,char * proto,u_int port)491 portlocalname(int res, char *proto, u_int port)
492 {
493 static char pname[8];
494 char *s;
495
496 port = ntohs(port);
497 port &= 0xffff;
498 sprintf(pname, "%u", port);
499 if (!res || (ipmonopts & IPMON_PORTNUM))
500 return pname;
501 s = NULL;
502 if (!strcmp(proto, "tcp"))
503 s = tcp_ports[port];
504 else if (!strcmp(proto, "udp"))
505 s = udp_ports[port];
506 if (s == NULL)
507 s = pname;
508 return s;
509 }
510
511
512 static char *
icmpname(u_int type,u_int code)513 icmpname(u_int type, u_int code)
514 {
515 static char name[80];
516 icmp_subtype_t *ist;
517 icmp_type_t *it;
518 char *s;
519
520 s = NULL;
521 it = find_icmptype(type, icmptypes4, sizeof(icmptypes4) / sizeof(*it));
522 if (it != NULL)
523 s = it->it_name;
524
525 if (s == NULL)
526 sprintf(name, "icmptype(%d)/", type);
527 else
528 sprintf(name, "%s/", s);
529
530 ist = NULL;
531 if (it != NULL && it->it_subtable != NULL)
532 ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize);
533
534 if (ist != NULL && ist->ist_name != NULL)
535 strcat(name, ist->ist_name);
536 else
537 sprintf(name + strlen(name), "%d", code);
538
539 return name;
540 }
541
542 static char *
icmpname6(u_int type,u_int code)543 icmpname6(u_int type, u_int code)
544 {
545 static char name[80];
546 icmp_subtype_t *ist;
547 icmp_type_t *it;
548 char *s;
549
550 s = NULL;
551 it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it));
552 if (it != NULL)
553 s = it->it_name;
554
555 if (s == NULL)
556 sprintf(name, "icmpv6type(%d)/", type);
557 else
558 sprintf(name, "%s/", s);
559
560 ist = NULL;
561 if (it != NULL && it->it_subtable != NULL)
562 ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize);
563
564 if (ist != NULL && ist->ist_name != NULL)
565 strcat(name, ist->ist_name);
566 else
567 sprintf(name + strlen(name), "%d", code);
568
569 return name;
570 }
571
572
573 void
dumphex(FILE * log,int dopts,const void * buf,size_t len)574 dumphex(FILE *log, int dopts, const void *buf, size_t len)
575 {
576 char hline[80];
577 int i, j, k;
578 u_char *s = (u_char *)buf, *t = (u_char *)hline;
579
580 if (buf == NULL || len == 0)
581 return;
582
583 *hline = '\0';
584
585 for (i = len, j = 0; i; i--, j++, s++) {
586 if (j && !(j & 0xf)) {
587 *t++ = '\n';
588 *t = '\0';
589 if ((dopts & IPMON_SYSLOG))
590 syslog(LOG_INFO, "%s", hline);
591 else if (log != NULL)
592 fputs(hline, log);
593 t = (u_char *)hline;
594 *t = '\0';
595 }
596 sprintf((char *)t, "%02x", *s & 0xff);
597 t += 2;
598 if (!((j + 1) & 0xf)) {
599 s -= 15;
600 sprintf((char *)t, " ");
601 t += 8;
602 for (k = 16; k; k--, s++)
603 *t++ = (isprint(*s) ? *s : '.');
604 s--;
605 }
606
607 if ((j + 1) & 0xf)
608 *t++ = ' ';;
609 }
610
611 if (j & 0xf) {
612 for (k = 16 - (j & 0xf); k; k--) {
613 *t++ = ' ';
614 *t++ = ' ';
615 *t++ = ' ';
616 }
617 sprintf((char *)t, " ");
618 t += 7;
619 s -= j & 0xf;
620 for (k = j & 0xf; k; k--, s++)
621 *t++ = (isprint(*s) ? *s : '.');
622 *t++ = '\n';
623 *t = '\0';
624 }
625 if ((dopts & IPMON_SYSLOG) != 0)
626 syslog(LOG_INFO, "%s", hline);
627 else if (log != NULL) {
628 fputs(hline, log);
629 fflush(log);
630 }
631 }
632
633
634 static struct tm *
get_tm(u_32_t sec)635 get_tm(
636 #ifdef __hpux
637 u_32_t sec
638 #else
639 time_t sec
640 #endif
641 )
642 {
643 struct tm *tm;
644 time_t t;
645
646 t = sec;
647 tm = localtime(&t);
648 return tm;
649 }
650
651 static void
print_natlog(config_t * conf,const iplog_t * ipl,const void * buf,size_t blen)652 print_natlog(config_t *conf, const iplog_t *ipl, const void *buf, size_t blen)
653 {
654 static u_32_t seqnum = 0;
655 int res, i, len, family;
656 struct natlog nl;
657 struct tm *tm;
658 char *proto;
659 int simple;
660 char *t;
661
662 t = line;
663 simple = 0;
664 if (ipl->ipl_seqnum != seqnum) {
665 if ((ipmonopts & IPMON_SYSLOG) != 0) {
666 syslog(LOG_WARNING,
667 "missed %u NAT log entries: %u %u",
668 ipl->ipl_seqnum - seqnum, seqnum,
669 ipl->ipl_seqnum);
670 } else {
671 (void) fprintf(conf->log,
672 "missed %u NAT log entries: %u %u\n",
673 ipl->ipl_seqnum - seqnum, seqnum,
674 ipl->ipl_seqnum);
675 }
676 }
677 seqnum = ipl->ipl_seqnum + ipl->ipl_count;
678
679 memcpy(&nl, (const char *)buf + sizeof(*ipl), sizeof(nl));
680 res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0;
681 tm = get_tm(ipl->ipl_sec);
682 len = sizeof(line);
683
684 if (!(ipmonopts & IPMON_SYSLOG)) {
685 (void) strftime(t, len, "%d/%m/%Y ", tm);
686 i = strlen(t);
687 len -= i;
688 t += i;
689 }
690 (void) strftime(t, len, "%T", tm);
691 t += strlen(t);
692 (void) sprintf(t, ".%-.6ld @%hd ", (long)ipl->ipl_usec,
693 nl.nl_rule + 1);
694 t += strlen(t);
695
696 switch (nl.nl_action)
697 {
698 case NL_NEW :
699 strcpy(t, "NAT:NEW");
700 break;
701
702 case NL_FLUSH :
703 strcpy(t, "NAT:FLUSH");
704 break;
705
706 case NL_CLONE :
707 strcpy(t, "NAT:CLONE");
708 break;
709
710 case NL_EXPIRE :
711 strcpy(t, "NAT:EXPIRE");
712 break;
713
714 case NL_DESTROY :
715 strcpy(t, "NAT:DESTROY");
716 break;
717
718 case NL_PURGE :
719 strcpy(t, "NAT:PURGE");
720 break;
721
722 default :
723 sprintf(t, "NAT:Action(%d)", nl.nl_action);
724 break;
725 }
726 t += strlen(t);
727
728
729 switch (nl.nl_type)
730 {
731 case NAT_MAP :
732 strcpy(t, "-MAP ");
733 simple = 1;
734 break;
735
736 case NAT_REDIRECT :
737 strcpy(t, "-RDR ");
738 simple = 1;
739 break;
740
741 case NAT_BIMAP :
742 strcpy(t, "-BIMAP ");
743 simple = 1;
744 break;
745
746 case NAT_MAPBLK :
747 strcpy(t, "-MAPBLOCK ");
748 simple = 1;
749 break;
750
751 case NAT_REWRITE|NAT_MAP :
752 strcpy(t, "-RWR_MAP ");
753 break;
754
755 case NAT_REWRITE|NAT_REDIRECT :
756 strcpy(t, "-RWR_RDR ");
757 break;
758
759 case NAT_ENCAP|NAT_MAP :
760 strcpy(t, "-ENC_MAP ");
761 break;
762
763 case NAT_ENCAP|NAT_REDIRECT :
764 strcpy(t, "-ENC_RDR ");
765 break;
766
767 case NAT_DIVERTUDP|NAT_MAP :
768 strcpy(t, "-DIV_MAP ");
769 break;
770
771 case NAT_DIVERTUDP|NAT_REDIRECT :
772 strcpy(t, "-DIV_RDR ");
773 break;
774
775 default :
776 sprintf(t, "-Type(%d) ", nl.nl_type);
777 break;
778 }
779 t += strlen(t);
780
781 proto = getlocalproto(nl.nl_p[0]);
782
783 family = vtof(nl.nl_v[0]);
784
785 if (simple == 1) {
786 sprintf(t, "%s,%s <- -> ", hostname(family, nl.nl_osrcip.i6),
787 portlocalname(res, proto, (u_int)nl.nl_osrcport));
788 t += strlen(t);
789 sprintf(t, "%s,%s ", hostname(family, nl.nl_nsrcip.i6),
790 portlocalname(res, proto, (u_int)nl.nl_nsrcport));
791 t += strlen(t);
792 sprintf(t, "[%s,%s] ", hostname(family, nl.nl_odstip.i6),
793 portlocalname(res, proto, (u_int)nl.nl_odstport));
794 } else {
795 sprintf(t, "%s,%s ", hostname(family, nl.nl_osrcip.i6),
796 portlocalname(res, proto, (u_int)nl.nl_osrcport));
797 t += strlen(t);
798 sprintf(t, "%s,%s <- -> ", hostname(family, nl.nl_odstip.i6),
799 portlocalname(res, proto, (u_int)nl.nl_odstport));
800 t += strlen(t);
801 sprintf(t, "%s,%s ", hostname(family, nl.nl_nsrcip.i6),
802 portlocalname(res, proto, (u_int)nl.nl_nsrcport));
803 t += strlen(t);
804 sprintf(t, "%s,%s ", hostname(family, nl.nl_ndstip.i6),
805 portlocalname(res, proto, (u_int)nl.nl_ndstport));
806 }
807 t += strlen(t);
808
809 strcpy(t, getlocalproto(nl.nl_p[0]));
810 t += strlen(t);
811
812 if (nl.nl_action == NL_EXPIRE || nl.nl_action == NL_FLUSH) {
813 #ifdef USE_QUAD_T
814 # ifdef PRId64
815 sprintf(t, " Pkts %" PRId64 "/%" PRId64 " Bytes %" PRId64 "/%"
816 PRId64,
817 # else
818 sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd",
819 # endif
820 #else
821 sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld",
822 #endif
823 nl.nl_pkts[0], nl.nl_pkts[1],
824 nl.nl_bytes[0], nl.nl_bytes[1]);
825 t += strlen(t);
826 }
827
828 *t++ = '\n';
829 *t++ = '\0';
830 if (ipmonopts & IPMON_SYSLOG)
831 syslog(LOG_INFO, "%s", line);
832 else if (conf->log != NULL)
833 (void) fprintf(conf->log, "%s", line);
834 }
835
836
837 static void
print_statelog(config_t * conf,const iplog_t * ipl,const void * buf,size_t blen)838 print_statelog(config_t *conf, const iplog_t *ipl, const void *buf, size_t blen)
839 {
840 static u_32_t seqnum = 0;
841 int res, i, len, family;
842 struct ipslog sl;
843 char *t, *proto;
844 struct tm *tm;
845
846 t = line;
847 if (ipl->ipl_seqnum != seqnum) {
848 if ((ipmonopts & IPMON_SYSLOG) != 0) {
849 syslog(LOG_WARNING,
850 "missed %u state log entries: %u %u",
851 ipl->ipl_seqnum - seqnum, seqnum,
852 ipl->ipl_seqnum);
853 } else {
854 (void) fprintf(conf->log,
855 "missed %u state log entries: %u %u\n",
856 ipl->ipl_seqnum - seqnum, seqnum,
857 ipl->ipl_seqnum);
858 }
859 }
860 seqnum = ipl->ipl_seqnum + ipl->ipl_count;
861
862 memcpy(&sl, (const char *)buf + sizeof(*ipl), sizeof(sl));
863 res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0;
864 tm = get_tm(ipl->ipl_sec);
865 len = sizeof(line);
866 if (!(ipmonopts & IPMON_SYSLOG)) {
867 (void) strftime(t, len, "%d/%m/%Y ", tm);
868 i = strlen(t);
869 len -= i;
870 t += i;
871 }
872 (void) strftime(t, len, "%T", tm);
873 t += strlen(t);
874 (void) sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec);
875 t += strlen(t);
876
877 family = vtof(sl.isl_v);
878
879 switch (sl.isl_type)
880 {
881 case ISL_NEW :
882 strcpy(t, "STATE:NEW ");
883 break;
884
885 case ISL_CLONE :
886 strcpy(t, "STATE:CLONED ");
887 break;
888
889 case ISL_EXPIRE :
890 if ((sl.isl_p == IPPROTO_TCP) &&
891 (sl.isl_state[0] > IPF_TCPS_ESTABLISHED ||
892 sl.isl_state[1] > IPF_TCPS_ESTABLISHED))
893 strcpy(t, "STATE:CLOSE ");
894 else
895 strcpy(t, "STATE:EXPIRE ");
896 break;
897
898 case ISL_FLUSH :
899 strcpy(t, "STATE:FLUSH ");
900 break;
901
902 case ISL_INTERMEDIATE :
903 strcpy(t, "STATE:INTERMEDIATE ");
904 break;
905
906 case ISL_REMOVE :
907 strcpy(t, "STATE:REMOVE ");
908 break;
909
910 case ISL_KILLED :
911 strcpy(t, "STATE:KILLED ");
912 break;
913
914 case ISL_UNLOAD :
915 strcpy(t, "STATE:UNLOAD ");
916 break;
917
918 default :
919 sprintf(t, "Type: %d ", sl.isl_type);
920 break;
921 }
922 t += strlen(t);
923
924 proto = getlocalproto(sl.isl_p);
925
926 if (sl.isl_p == IPPROTO_TCP || sl.isl_p == IPPROTO_UDP) {
927 sprintf(t, "%s,%s -> ",
928 hostname(family, (u_32_t *)&sl.isl_src),
929 portlocalname(res, proto, (u_int)sl.isl_sport));
930 t += strlen(t);
931 sprintf(t, "%s,%s PR %s",
932 hostname(family, (u_32_t *)&sl.isl_dst),
933 portlocalname(res, proto, (u_int)sl.isl_dport), proto);
934 } else if (sl.isl_p == IPPROTO_ICMP) {
935 sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl.isl_src));
936 t += strlen(t);
937 sprintf(t, "%s PR icmp %d",
938 hostname(family, (u_32_t *)&sl.isl_dst),
939 sl.isl_itype);
940 } else if (sl.isl_p == IPPROTO_ICMPV6) {
941 sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl.isl_src));
942 t += strlen(t);
943 sprintf(t, "%s PR icmpv6 %d",
944 hostname(family, (u_32_t *)&sl.isl_dst),
945 sl.isl_itype);
946 } else {
947 sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl.isl_src));
948 t += strlen(t);
949 sprintf(t, "%s PR %s",
950 hostname(family, (u_32_t *)&sl.isl_dst), proto);
951 }
952 t += strlen(t);
953 if (sl.isl_tag != FR_NOLOGTAG) {
954 sprintf(t, " tag %u", sl.isl_tag);
955 t += strlen(t);
956 }
957 if (sl.isl_type != ISL_NEW) {
958 static const char fmt[] =
959 #ifdef USE_QUAD_T
960 #ifdef PRId64
961 " Forward: Pkts in %" PRId64 " Bytes in %" PRId64
962 " Pkts out %" PRId64 " Bytes out %" PRId64
963 " Backward: Pkts in %" PRId64 " Bytes in %" PRId64
964 " Pkts out %" PRId64 " Bytes out %" PRId64;
965 #else
966 " Forward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd Backward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd";
967 #endif /* PRId64 */
968 #else
969 " Forward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld Backward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld";
970 #endif
971 sprintf(t, fmt,
972 sl.isl_pkts[0], sl.isl_bytes[0],
973 sl.isl_pkts[1], sl.isl_bytes[1],
974 sl.isl_pkts[2], sl.isl_bytes[2],
975 sl.isl_pkts[3], sl.isl_bytes[3]);
976
977 t += strlen(t);
978 }
979
980 *t++ = '\n';
981 *t++ = '\0';
982 if (ipmonopts & IPMON_SYSLOG)
983 syslog(LOG_INFO, "%s", line);
984 else if (conf->log != NULL)
985 (void) fprintf(conf->log, "%s", line);
986 }
987
988
989 static void
print_log(config_t * conf,logsource_t * log,const void * buf,size_t blen)990 print_log(config_t *conf, logsource_t *log, const void *buf, size_t blen)
991 {
992 iplog_t ipl;
993 int psize;
994
995 while (blen > 0) {
996 if (sizeof(ipl) > blen)
997 return;
998
999 memcpy(&ipl, buf, sizeof(ipl));
1000 psize = ipl.ipl_dsize;
1001 if (psize > blen)
1002 return;
1003
1004 if (conf->blog != NULL) {
1005 fwrite(buf, psize, 1, conf->blog);
1006 fflush(conf->blog);
1007 }
1008
1009 switch (log->logtype) {
1010 case IPL_LOGIPF:
1011 if (ipl.ipl_magic == IPL_MAGIC)
1012 print_ipflog(conf, &ipl, buf, psize);
1013 break;
1014 case IPL_LOGNAT:
1015 if (ipl.ipl_magic == IPL_MAGIC_NAT)
1016 print_natlog(conf, &ipl, buf, psize);
1017 break;
1018
1019 case IPL_LOGSTATE:
1020 if (ipl.ipl_magic == IPL_MAGIC_STATE)
1021 print_statelog(conf, &ipl, buf, psize);
1022 break;
1023 }
1024
1025 blen -= psize;
1026 buf = (const char *)buf + psize;
1027 }
1028 }
1029
1030
1031 static void
print_ipflog(config_t * conf,const iplog_t * ipl,const void * buf,size_t blen)1032 print_ipflog(config_t *conf, const iplog_t *ipl, const void *buf, size_t blen)
1033 {
1034 static u_32_t seqnum = 0;
1035 int i, f, lvl, res, len, off, plen, ipoff, defaction;
1036 struct icmp icmp;
1037 struct icmp ic;
1038 char *t, *proto;
1039 ip_t ipc, ip;
1040 struct tm *tm;
1041 u_32_t *s, *d;
1042 u_short hl, p;
1043 ipflog_t ipf;
1044 const void *pac;
1045 tcphdr_t tp;
1046 #ifdef USE_INET6
1047 struct ip6_ext eh;
1048 const void *ehp;
1049 u_short ehl;
1050 ip6_t ip6;
1051 int go;
1052 #endif
1053
1054 if (ipl->ipl_seqnum != seqnum) {
1055 if ((ipmonopts & IPMON_SYSLOG) != 0) {
1056 syslog(LOG_WARNING,
1057 "missed %u ipf log entries: %u %u",
1058 ipl->ipl_seqnum - seqnum, seqnum,
1059 ipl->ipl_seqnum);
1060 } else {
1061 (void) fprintf(conf->log,
1062 "missed %u ipf log entries: %u %u\n",
1063 ipl->ipl_seqnum - seqnum, seqnum,
1064 ipl->ipl_seqnum);
1065 }
1066 }
1067 seqnum = ipl->ipl_seqnum + ipl->ipl_count;
1068
1069 memcpy(&ipf, (const char *)buf + sizeof(*ipl), sizeof(ipf));
1070 pac = (const char *)buf + sizeof(*ipl) + sizeof(ipf);
1071 memcpy(&ip, pac, sizeof(ip));
1072 f = ipf.fl_family;
1073 res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0;
1074 t = line;
1075 *t = '\0';
1076 tm = get_tm(ipl->ipl_sec);
1077
1078 len = sizeof(line);
1079 if (!(ipmonopts & IPMON_SYSLOG)) {
1080 (void) strftime(t, len, "%d/%m/%Y ", tm);
1081 i = strlen(t);
1082 len -= i;
1083 t += i;
1084 }
1085 (void) strftime(t, len, "%T", tm);
1086 t += strlen(t);
1087 (void) sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec);
1088 t += strlen(t);
1089 if (ipl->ipl_count > 1) {
1090 sprintf(t, "%dx ", ipl->ipl_count);
1091 t += strlen(t);
1092 }
1093 #if (defined(MENTAT) || \
1094 (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
1095 (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \
1096 (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux)
1097 {
1098 char ifname[sizeof(ipf.fl_ifname) + 1];
1099
1100 strncpy(ifname, ipf.fl_ifname, sizeof(ifname)-1);
1101 ifname[sizeof(ipf.fl_ifname)] = '\0';
1102 sprintf(t, "%s", ifname);
1103 t += strlen(t);
1104 # if defined(MENTAT) || defined(linux)
1105 # if defined(linux)
1106 /*
1107 * On Linux, the loopback interface is just "lo", not "lo0".
1108 */
1109 if (strcmp(ifname, "lo") != 0)
1110 # endif
1111 if (ISALPHA(*(t - 1))) {
1112 sprintf(t, "%d", ipf.fl_unit);
1113 t += strlen(t);
1114 }
1115 # endif
1116 }
1117 #else
1118 for (len = 0; len < 3; len++)
1119 if (ipf.fl_ifname[len] == '\0')
1120 break;
1121 if (ipf.fl_ifname[len])
1122 len++;
1123 sprintf(t, "%*.*s%u", len, len, ipf.fl_ifname, ipf.fl_unit);
1124 t += strlen(t);
1125 #endif
1126 if ((ipf.fl_group[0] == (char)~0) && (ipf.fl_group[1] == '\0'))
1127 strcat(t, " @-1:");
1128 else if (ipf.fl_group[0] == '\0')
1129 (void) strcpy(t, " @0:");
1130 else
1131 sprintf(t, " @%s:", ipf.fl_group);
1132 t += strlen(t);
1133 if (ipf.fl_rule == 0xffffffff)
1134 strcat(t, "-1 ");
1135 else
1136 sprintf(t, "%u ", ipf.fl_rule + 1);
1137 t += strlen(t);
1138
1139 lvl = LOG_NOTICE;
1140
1141 if (ipf.fl_lflags & FI_SHORT) {
1142 *t++ = 'S';
1143 lvl = LOG_ERR;
1144 }
1145
1146 if (FR_ISPASS(ipf.fl_flags)) {
1147 if (ipf.fl_flags & FR_LOGP)
1148 *t++ = 'p';
1149 else
1150 *t++ = 'P';
1151 } else if (FR_ISBLOCK(ipf.fl_flags)) {
1152 if (ipf.fl_flags & FR_LOGB)
1153 *t++ = 'b';
1154 else
1155 *t++ = 'B';
1156 lvl = LOG_WARNING;
1157 } else if ((ipf.fl_flags & FR_LOGMASK) == FR_LOG) {
1158 *t++ = 'L';
1159 lvl = LOG_INFO;
1160 } else if (ipf.fl_flags & FF_LOGNOMATCH) {
1161 *t++ = 'n';
1162 } else {
1163 *t++ = '?';
1164 lvl = LOG_EMERG;
1165 }
1166 if (ipf.fl_loglevel != 0xffff)
1167 lvl = ipf.fl_loglevel;
1168 *t++ = ' ';
1169 *t = '\0';
1170
1171 if (f == AF_INET) {
1172 hl = IP_HL(&ip) << 2;
1173 ipoff = ntohs(ip.ip_off);
1174 off = ipoff & IP_OFFMASK;
1175 p = (u_short)ip.ip_p;
1176 s = (u_32_t *)&ip.ip_src;
1177 d = (u_32_t *)&ip.ip_dst;
1178 plen = ntohs(ip.ip_len);
1179 } else
1180 #ifdef USE_INET6
1181 if (f == AF_INET6) {
1182 off = 0;
1183 ipoff = 0;
1184 hl = sizeof(ip6_t);
1185 memcpy(&ip6, pac, sizeof(ip6));
1186 p = (u_short)ip6.ip6_nxt;
1187 s = (u_32_t *)&ip6.ip6_src;
1188 d = (u_32_t *)&ip6.ip6_dst;
1189 plen = hl + ntohs(ip6.ip6_plen);
1190 ehp = (const char *)pac + hl;
1191 go = 1;
1192 while (go == 1) {
1193 memcpy(&eh, ehp, sizeof(eh));
1194 switch (p)
1195 {
1196 case IPPROTO_HOPOPTS :
1197 case IPPROTO_MOBILITY :
1198 case IPPROTO_DSTOPTS :
1199 case IPPROTO_ROUTING :
1200 case IPPROTO_AH :
1201 p = eh.ip6e_nxt;
1202 ehl = 8 + (eh.ip6e_len << 3);
1203 hl += ehl;
1204 ehp = (const char *)ehp + ehl;
1205 break;
1206 case IPPROTO_FRAGMENT :
1207 hl += sizeof(struct ip6_frag);
1208 /* FALLTHROUGH */
1209 default :
1210 go = 0;
1211 break;
1212 }
1213 }
1214 } else
1215 #endif
1216 {
1217 goto printipflog;
1218 }
1219 proto = getlocalproto(p);
1220
1221 if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) {
1222 memcpy(&tp, (const char *)pac + hl, sizeof(tp));
1223 if (!(ipf.fl_lflags & FI_SHORT)) {
1224 sprintf(t, "%s,%s -> ", hostname(f, s),
1225 portlocalname(res, proto, (u_int)tp.th_sport));
1226 t += strlen(t);
1227 sprintf(t, "%s,%s PR %s len %hu %hu",
1228 hostname(f, d),
1229 portlocalname(res, proto, (u_int)tp.th_dport),
1230 proto, hl, plen);
1231 t += strlen(t);
1232
1233 if (p == IPPROTO_TCP) {
1234 *t++ = ' ';
1235 *t++ = '-';
1236 for (i = 0; tcpfl[i].value; i++)
1237 if (tp.th_flags & tcpfl[i].value)
1238 *t++ = tcpfl[i].flag;
1239 if (ipmonopts & IPMON_VERBOSE) {
1240 sprintf(t, " %lu %lu %hu",
1241 (u_long)(ntohl(tp.th_seq)),
1242 (u_long)(ntohl(tp.th_ack)),
1243 ntohs(tp.th_win));
1244 t += strlen(t);
1245 }
1246 }
1247 *t = '\0';
1248 } else {
1249 sprintf(t, "%s -> ", hostname(f, s));
1250 t += strlen(t);
1251 sprintf(t, "%s PR %s len %hu %hu",
1252 hostname(f, d), proto, hl, plen);
1253 }
1254 #if defined(AF_INET6) && defined(IPPROTO_ICMPV6)
1255 } else if ((p == IPPROTO_ICMPV6) && !off && (f == AF_INET6)) {
1256 memcpy(&ic, (const char *)pac + hl, sizeof(ic));
1257 sprintf(t, "%s -> ", hostname(f, s));
1258 t += strlen(t);
1259 sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s",
1260 hostname(f, d), hl, plen,
1261 icmpname6(ic.icmp_type, ic.icmp_code));
1262 #endif
1263 } else if ((p == IPPROTO_ICMP) && !off && (f == AF_INET)) {
1264 memcpy(&ic, (const char *)pac + hl, sizeof(ic));
1265 sprintf(t, "%s -> ", hostname(f, s));
1266 t += strlen(t);
1267 sprintf(t, "%s PR icmp len %hu %hu icmp %s",
1268 hostname(f, d), hl, plen,
1269 icmpname(ic.icmp_type, ic.icmp_code));
1270 if (ic.icmp_type == ICMP_UNREACH ||
1271 ic.icmp_type == ICMP_SOURCEQUENCH ||
1272 ic.icmp_type == ICMP_PARAMPROB ||
1273 ic.icmp_type == ICMP_REDIRECT ||
1274 ic.icmp_type == ICMP_TIMXCEED) {
1275 const void *ipcp = (const char *)pac + 2 * hl + offsetof(struct icmp, icmp_ip);
1276 memcpy(&ipc, &ic.icmp_ip, sizeof(ipc));
1277 i = ntohs(ipc.ip_len);
1278 /*
1279 * XXX - try to guess endian of ip_len in ICMP
1280 * returned data.
1281 */
1282 if (i > 1500)
1283 i = ipc.ip_len;
1284 ipoff = ntohs(ipc.ip_off);
1285 proto = getlocalproto(ipc.ip_p);
1286
1287 if (!(ipoff & IP_OFFMASK) &&
1288 ((ipc.ip_p == IPPROTO_TCP) ||
1289 (ipc.ip_p == IPPROTO_UDP))) {
1290 memcpy(&tp, ipcp, sizeof(tp));
1291 t += strlen(t);
1292 sprintf(t, " for %s,%s -",
1293 HOSTNAMEV4(ipc.ip_src),
1294 portlocalname(res, proto,
1295 (u_int)tp.th_sport));
1296 t += strlen(t);
1297 sprintf(t, " %s,%s PR %s len %hu %hu",
1298 HOSTNAMEV4(ipc.ip_dst),
1299 portlocalname(res, proto,
1300 (u_int)tp.th_dport),
1301 proto, IP_HL(&ipc) << 2, i);
1302 } else if (!(ipoff & IP_OFFMASK) &&
1303 (ipc.ip_p == IPPROTO_ICMP)) {
1304 memcpy(&icmp, ipcp, sizeof(icmp));
1305
1306 t += strlen(t);
1307 sprintf(t, " for %s -",
1308 HOSTNAMEV4(ipc.ip_src));
1309 t += strlen(t);
1310 sprintf(t,
1311 " %s PR icmp len %hu %hu icmp %d/%d",
1312 HOSTNAMEV4(ipc.ip_dst),
1313 IP_HL(&ipc) << 2, i,
1314 icmp.icmp_type, icmp.icmp_code);
1315 } else {
1316 t += strlen(t);
1317 sprintf(t, " for %s -",
1318 HOSTNAMEV4(ipc.ip_src));
1319 t += strlen(t);
1320 sprintf(t, " %s PR %s len %hu (%hu)",
1321 HOSTNAMEV4(ipc.ip_dst), proto,
1322 IP_HL(&ipc) << 2, i);
1323 t += strlen(t);
1324 if (ipoff & IP_OFFMASK) {
1325 sprintf(t, "(frag %d:%hu@%hu%s%s)",
1326 ntohs(ipc.ip_id),
1327 i - (IP_HL(&ipc) << 2),
1328 (ipoff & IP_OFFMASK) << 3,
1329 ipoff & IP_MF ? "+" : "",
1330 ipoff & IP_DF ? "-" : "");
1331 }
1332 }
1333
1334 }
1335 } else {
1336 sprintf(t, "%s -> ", hostname(f, s));
1337 t += strlen(t);
1338 sprintf(t, "%s PR %s len %hu (%hu)",
1339 hostname(f, d), proto, hl, plen);
1340 t += strlen(t);
1341 if (off & IP_OFFMASK)
1342 sprintf(t, " (frag %d:%hu@%hu%s%s)",
1343 ntohs(ip.ip_id),
1344 plen - hl, (off & IP_OFFMASK) << 3,
1345 ipoff & IP_MF ? "+" : "",
1346 ipoff & IP_DF ? "-" : "");
1347 }
1348 t += strlen(t);
1349
1350 printipflog:
1351 if (ipf.fl_flags & FR_KEEPSTATE) {
1352 (void) strcpy(t, " K-S");
1353 t += strlen(t);
1354 }
1355
1356 if (ipf.fl_flags & FR_KEEPFRAG) {
1357 (void) strcpy(t, " K-F");
1358 t += strlen(t);
1359 }
1360
1361 if (ipf.fl_dir == 0)
1362 strcpy(t, " IN");
1363 else if (ipf.fl_dir == 1)
1364 strcpy(t, " OUT");
1365 t += strlen(t);
1366 if (ipf.fl_logtag != 0) {
1367 sprintf(t, " log-tag %d", ipf.fl_logtag);
1368 t += strlen(t);
1369 }
1370 if (ipf.fl_nattag.ipt_num[0] != 0) {
1371 strcpy(t, " nat-tag ");
1372 t += strlen(t);
1373 strncpy(t, ipf.fl_nattag.ipt_tag, sizeof(ipf.fl_nattag));
1374 t += strlen(t);
1375 }
1376 if ((ipf.fl_lflags & FI_LOWTTL) != 0) {
1377 strcpy(t, " low-ttl");
1378 t += 8;
1379 }
1380 if ((ipf.fl_lflags & FI_OOW) != 0) {
1381 strcpy(t, " OOW");
1382 t += 4;
1383 }
1384 if ((ipf.fl_lflags & FI_BAD) != 0) {
1385 strcpy(t, " bad");
1386 t += 4;
1387 }
1388 if ((ipf.fl_lflags & FI_NATED) != 0) {
1389 strcpy(t, " NAT");
1390 t += 4;
1391 }
1392 if ((ipf.fl_lflags & FI_BADNAT) != 0) {
1393 strcpy(t, " bad-NAT");
1394 t += 8;
1395 }
1396 if ((ipf.fl_lflags & FI_BADSRC) != 0) {
1397 strcpy(t, " bad-src");
1398 t += 8;
1399 }
1400 if ((ipf.fl_lflags & FI_MULTICAST) != 0) {
1401 strcpy(t, " multicast");
1402 t += 10;
1403 }
1404 if ((ipf.fl_lflags & FI_BROADCAST) != 0) {
1405 strcpy(t, " broadcast");
1406 t += 10;
1407 }
1408 if ((ipf.fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) ==
1409 FI_MBCAST) {
1410 strcpy(t, " mbcast");
1411 t += 7;
1412 }
1413 if (ipf.fl_breason != 0) {
1414 strcpy(t, " reason:");
1415 t += 8;
1416 strcpy(t, reasons[ipf.fl_breason]);
1417 t += strlen(reasons[ipf.fl_breason]);
1418 }
1419 *t++ = '\n';
1420 *t++ = '\0';
1421 defaction = 0;
1422 if (conf->cfile != NULL)
1423 defaction = check_action(buf, line, ipmonopts, lvl);
1424
1425 if (defaction == 0) {
1426 if (ipmonopts & IPMON_SYSLOG) {
1427 syslog(lvl, "%s", line);
1428 } else if (conf->log != NULL) {
1429 (void) fprintf(conf->log, "%s", line);
1430 }
1431
1432 if (ipmonopts & IPMON_HEXHDR) {
1433 dumphex(conf->log, ipmonopts, buf,
1434 sizeof(*ipl) + sizeof(ipf));
1435 }
1436 if (ipmonopts & IPMON_HEXBODY) {
1437 dumphex(conf->log, ipmonopts, (char *)pac,
1438 ipf.fl_plen + ipf.fl_hlen);
1439 } else if ((ipmonopts & IPMON_LOGBODY) &&
1440 (ipf.fl_flags & FR_LOGBODY)) {
1441 dumphex(conf->log, ipmonopts, (char *)pac + ipf.fl_hlen,
1442 ipf.fl_plen);
1443 }
1444 }
1445 }
1446
1447
1448 static void
usage(const char * prog)1449 usage(const char *prog)
1450 {
1451 fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog);
1452 exit(1);
1453 }
1454
1455
1456 static void
write_pid(const char * file)1457 write_pid(const char *file)
1458 {
1459 FILE *fp = NULL;
1460 int fd;
1461
1462 if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) {
1463 fp = fdopen(fd, "w");
1464 if (fp == NULL) {
1465 close(fd);
1466 fprintf(stderr,
1467 "unable to open/create pid file: %s\n", file);
1468 return;
1469 }
1470 fprintf(fp, "%d", getpid());
1471 fclose(fp);
1472 }
1473 }
1474
1475
1476 static void
flushlogs(const char * file,FILE * log)1477 flushlogs(const char *file, FILE *log)
1478 {
1479 int fd, flushed = 0;
1480
1481 if ((fd = open(file, O_RDWR)) == -1) {
1482 (void) fprintf(stderr, "%s: open: %s\n",
1483 file, STRERROR(errno));
1484 exit(1);
1485 }
1486
1487 if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
1488 printf("%d bytes flushed from log buffer\n",
1489 flushed);
1490 fflush(stdout);
1491 } else
1492 ipferror(fd, "SIOCIPFFB");
1493 (void) close(fd);
1494
1495 if (flushed) {
1496 if (ipmonopts & IPMON_SYSLOG) {
1497 syslog(LOG_INFO, "%d bytes flushed from log\n",
1498 flushed);
1499 } else if ((log != stdout) && (log != NULL)) {
1500 fprintf(log, "%d bytes flushed from log\n", flushed);
1501 }
1502 }
1503 }
1504
1505
1506 static void
logopts(int turnon,const char * options)1507 logopts(int turnon, const char *options)
1508 {
1509 int flags = 0;
1510 const char *s;
1511
1512 for (s = options; *s; s++)
1513 {
1514 switch (*s)
1515 {
1516 case 'N' :
1517 flags |= IPMON_NAT;
1518 break;
1519 case 'S' :
1520 flags |= IPMON_STATE;
1521 break;
1522 case 'I' :
1523 flags |= IPMON_FILTER;
1524 break;
1525 default :
1526 fprintf(stderr, "Unknown log option %c\n", *s);
1527 exit(1);
1528 }
1529 }
1530
1531 if (turnon)
1532 ipmonopts |= flags;
1533 else
1534 ipmonopts &= ~(flags);
1535 }
1536
1537 static void
initconfig(config_t * conf)1538 initconfig(config_t *conf)
1539 {
1540 int i;
1541
1542 memset(conf, 0, sizeof(*conf));
1543
1544 conf->log = stdout;
1545 conf->maxfd = -1;
1546
1547 for (i = 0; i < 3; i++) {
1548 conf->logsrc[i].fd = -1;
1549 conf->logsrc[i].logtype = -1;
1550 conf->logsrc[i].regular = -1;
1551 }
1552
1553 conf->logsrc[0].file = IPL_NAME;
1554 conf->logsrc[1].file = IPNAT_NAME;
1555 conf->logsrc[2].file = IPSTATE_NAME;
1556
1557 add_doing(&executesaver);
1558 add_doing(&snmpv1saver);
1559 add_doing(&snmpv2saver);
1560 add_doing(&syslogsaver);
1561 add_doing(&filesaver);
1562 add_doing(¬hingsaver);
1563 }
1564
1565
1566 int
main(int argc,char * argv[])1567 main(int argc, char *argv[])
1568 {
1569 int doread, c, make_daemon = 0;
1570 char *prog;
1571 config_t config;
1572
1573 prog = strrchr(argv[0], '/');
1574 if (prog == NULL)
1575 prog = argv[0];
1576 else
1577 prog++;
1578
1579 initconfig(&config);
1580
1581 while ((c = getopt(argc, argv,
1582 "?abB:C:Df:FhL:nN:o:O:pP:sS:tvxX")) != -1)
1583 switch (c)
1584 {
1585 case 'a' :
1586 ipmonopts |= IPMON_LOGALL;
1587 config.logsrc[0].logtype = IPL_LOGIPF;
1588 config.logsrc[1].logtype = IPL_LOGNAT;
1589 config.logsrc[2].logtype = IPL_LOGSTATE;
1590 break;
1591 case 'b' :
1592 ipmonopts |= IPMON_LOGBODY;
1593 break;
1594 case 'B' :
1595 config.bfile = optarg;
1596 config.blog = fopen(optarg, "a");
1597 break;
1598 case 'C' :
1599 config.cfile = optarg;
1600 break;
1601 case 'D' :
1602 make_daemon = 1;
1603 break;
1604 case 'f' : case 'I' :
1605 ipmonopts |= IPMON_FILTER;
1606 config.logsrc[0].logtype = IPL_LOGIPF;
1607 config.logsrc[0].file = optarg;
1608 break;
1609 case 'F' :
1610 flushlogs(config.logsrc[0].file, config.log);
1611 flushlogs(config.logsrc[1].file, config.log);
1612 flushlogs(config.logsrc[2].file, config.log);
1613 break;
1614 case 'L' :
1615 logfac = fac_findname(optarg);
1616 if (logfac == -1) {
1617 fprintf(stderr,
1618 "Unknown syslog facility '%s'\n",
1619 optarg);
1620 exit(1);
1621 }
1622 break;
1623 case 'n' :
1624 ipmonopts |= IPMON_RESOLVE;
1625 opts &= ~OPT_NORESOLVE;
1626 break;
1627 case 'N' :
1628 ipmonopts |= IPMON_NAT;
1629 config.logsrc[1].logtype = IPL_LOGNAT;
1630 config.logsrc[1].file = optarg;
1631 break;
1632 case 'o' : case 'O' :
1633 logopts(c == 'o', optarg);
1634 if (ipmonopts & IPMON_FILTER)
1635 config.logsrc[0].logtype = IPL_LOGIPF;
1636 if (ipmonopts & IPMON_NAT)
1637 config.logsrc[1].logtype = IPL_LOGNAT;
1638 if (ipmonopts & IPMON_STATE)
1639 config.logsrc[2].logtype = IPL_LOGSTATE;
1640 break;
1641 case 'p' :
1642 ipmonopts |= IPMON_PORTNUM;
1643 break;
1644 case 'P' :
1645 pidfile = optarg;
1646 break;
1647 case 's' :
1648 ipmonopts |= IPMON_SYSLOG;
1649 config.log = NULL;
1650 break;
1651 case 'S' :
1652 ipmonopts |= IPMON_STATE;
1653 config.logsrc[2].logtype = IPL_LOGSTATE;
1654 config.logsrc[2].file = optarg;
1655 break;
1656 case 't' :
1657 ipmonopts |= IPMON_TAIL;
1658 break;
1659 case 'v' :
1660 ipmonopts |= IPMON_VERBOSE;
1661 break;
1662 case 'x' :
1663 ipmonopts |= IPMON_HEXBODY;
1664 break;
1665 case 'X' :
1666 ipmonopts |= IPMON_HEXHDR;
1667 break;
1668 default :
1669 case 'h' :
1670 case '?' :
1671 usage(argv[0]);
1672 }
1673
1674 if (ipmonopts & IPMON_SYSLOG)
1675 openlog(prog, LOG_NDELAY|LOG_PID, logfac);
1676
1677 init_tabs();
1678 if (config.cfile)
1679 if (load_config(config.cfile) == -1) {
1680 unload_config();
1681 exit(1);
1682 }
1683
1684 /*
1685 * Default action is to only open the filter log file.
1686 */
1687 if ((config.logsrc[0].logtype == -1) &&
1688 (config.logsrc[0].logtype == -1) &&
1689 (config.logsrc[0].logtype == -1))
1690 config.logsrc[0].logtype = IPL_LOGIPF;
1691
1692 openlogs(&config);
1693
1694 if (!(ipmonopts & IPMON_SYSLOG)) {
1695 config.file = argv[optind];
1696 config.log = config.file ? fopen(config.file, "a") : stdout;
1697 if (config.log == NULL) {
1698 (void) fprintf(stderr, "%s: fopen: %s\n",
1699 argv[optind], STRERROR(errno));
1700 exit(1);
1701 /* NOTREACHED */
1702 }
1703 setvbuf(config.log, NULL, _IONBF, 0);
1704 } else {
1705 config.log = NULL;
1706 }
1707
1708 if (make_daemon &&
1709 ((config.log != stdout) || (ipmonopts & IPMON_SYSLOG))) {
1710 #if BSD >= 199306
1711 daemon(0, !(ipmonopts & IPMON_SYSLOG));
1712 #else
1713 int pid;
1714
1715 switch (fork())
1716 {
1717 case -1 :
1718 (void) fprintf(stderr, "%s: fork() failed: %s\n",
1719 argv[0], STRERROR(errno));
1720 exit(1);
1721 /* NOTREACHED */
1722 case 0 :
1723 break;
1724 default :
1725 exit(0);
1726 }
1727
1728 setsid();
1729 if ((ipmonopts & IPMON_SYSLOG))
1730 close(2);
1731 #endif /* !BSD */
1732 close(0);
1733 close(1);
1734 write_pid(pidfile);
1735 }
1736
1737 signal(SIGHUP, handlehup);
1738
1739 for (doread = 1; doread; )
1740 doread = read_loginfo(&config);
1741
1742 unload_config();
1743
1744 return(0);
1745 /* NOTREACHED */
1746 }
1747
1748
1749 static void
openlogs(config_t * conf)1750 openlogs(config_t *conf)
1751 {
1752 logsource_t *l;
1753 struct stat sb;
1754 int i;
1755
1756 for (i = 0; i < 3; i++) {
1757 l = &conf->logsrc[i];
1758 if (l->logtype == -1)
1759 continue;
1760 if (!strcmp(l->file, "-"))
1761 l->fd = 0;
1762 else {
1763 if ((l->fd= open(l->file, O_RDONLY)) == -1) {
1764 (void) fprintf(stderr,
1765 "%s: open: %s\n", l->file,
1766 STRERROR(errno));
1767 exit(1);
1768 /* NOTREACHED */
1769 }
1770
1771 if (fstat(l->fd, &sb) == -1) {
1772 (void) fprintf(stderr, "%d: fstat: %s\n",
1773 l->fd, STRERROR(errno));
1774 exit(1);
1775 /* NOTREACHED */
1776 }
1777
1778 l->regular = !S_ISCHR(sb.st_mode);
1779 if (l->regular)
1780 l->size = sb.st_size;
1781
1782 FD_SET(l->fd, &conf->fdmr);
1783 if (l->fd > conf->maxfd)
1784 conf->maxfd = l->fd;
1785 }
1786 }
1787 }
1788
1789
1790 static int
read_loginfo(config_t * conf)1791 read_loginfo(config_t *conf)
1792 {
1793 iplog_t buf[DEFAULT_IPFLOGSIZE/sizeof(iplog_t)+1];
1794 size_t n, tr, nr, i;
1795 int nf;
1796 logsource_t *l;
1797 fd_set fdr;
1798
1799 fdr = conf->fdmr;
1800
1801 nf = select(conf->maxfd + 1, &fdr, NULL, NULL, NULL);
1802 if (nf == 0)
1803 return 1;
1804 if (nf == -1) {
1805 if (errno == EINTR)
1806 return 1;
1807 return -1;
1808 }
1809
1810 for (i = 0, nr = 0; i < 3; i++) {
1811 l = &conf->logsrc[i];
1812
1813 if ((l->logtype == -1) || !FD_ISSET(l->fd, &fdr))
1814 continue;
1815
1816 tr = 0;
1817 if (l->regular) {
1818 tr = (lseek(l->fd, 0, SEEK_CUR) < l->size);
1819 if (!tr && !(ipmonopts & IPMON_TAIL))
1820 return 0;
1821 }
1822
1823 n = 0;
1824 tr = read_log(l->fd, &n, (char *)buf, sizeof(buf));
1825 if (donehup) {
1826 if (conf->file != NULL) {
1827 if (conf->log != NULL) {
1828 fclose(conf->log);
1829 conf->log = NULL;
1830 }
1831 conf->log = fopen(conf->file, "a");
1832 }
1833
1834 if (conf->bfile != NULL) {
1835 if (conf->blog != NULL) {
1836 fclose(conf->blog);
1837 conf->blog = NULL;
1838 }
1839 conf->blog = fopen(conf->bfile, "a");
1840 }
1841
1842 init_tabs();
1843 if (conf->cfile != NULL)
1844 load_config(conf->cfile);
1845 donehup = 0;
1846 }
1847
1848 switch (tr)
1849 {
1850 case -1 :
1851 if (ipmonopts & IPMON_SYSLOG)
1852 syslog(LOG_CRIT, "read: %m\n");
1853 else {
1854 ipferror(l->fd, "read");
1855 }
1856 return 0;
1857 case 1 :
1858 if (ipmonopts & IPMON_SYSLOG)
1859 syslog(LOG_CRIT, "aborting logging\n");
1860 else if (conf->log != NULL)
1861 fprintf(conf->log, "aborting logging\n");
1862 return 0;
1863 case 2 :
1864 break;
1865 case 0 :
1866 nr += tr;
1867 if (n > 0) {
1868 print_log(conf, l, (char *)buf, n);
1869 if (!(ipmonopts & IPMON_SYSLOG))
1870 fflush(conf->log);
1871 }
1872 break;
1873 }
1874 }
1875
1876 if (!nr && (ipmonopts & IPMON_TAIL))
1877 sleep(1);
1878
1879 return 1;
1880 }
1881