xref: /netbsd/external/bsd/ipf/dist/tools/ipmon.c (revision ec8120b1)
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