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(&nothingsaver);
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