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