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