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)
90static const char sccsid[] = "@(#)ipmon.c	1.21 6/5/96 (C)1993-2000 Darren Reed";
91static 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]
97extern	char	*sys_errlist[];
98#else
99#define	STRERROR(x)	strerror(x)
100#endif
101
102
103struct	flags {
104	int	value;
105	char	flag;
106};
107
108
109typedef	struct	icmp_subtype {
110	int	ist_val;
111	char	*ist_name;
112} icmp_subtype_t;
113
114typedef	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
125struct	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))
138static	char	*pidfile = "/etc/ipf/ipmon.pid";
139#else
140# if (BSD >= 199306) || defined(SOLARIS)
141static	char	*pidfile = "/var/run/ipmon.pid";
142# else
143static	char	*pidfile = "/etc/ipmon.pid";
144# endif
145#endif
146
147static	char	line[2048];
148static	int	opts = 0;
149static	char	*logfile = NULL;
150static	FILE	*binarylog = NULL;
151static	char	*binarylogfile = NULL;
152static	int	donehup = 0;
153static	void	usage __P((char *));
154static	void	handlehup __P((int));
155static	void	flushlogs __P((char *, FILE *));
156static	void	print_log __P((int, FILE *, char *, int));
157static	void	print_ipflog __P((FILE *, char *, int));
158static	void	print_natlog __P((FILE *, char *, int));
159static	void	print_statelog __P((FILE *, char *, int));
160static	int	read_log __P((int, int *, char *, int));
161static	void	write_pid __P((char *));
162static	char	*icmpname __P((u_int, u_int));
163static	char	*icmpname6 __P((u_int, u_int));
164static	icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t));
165static	icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t));
166#ifdef __hpux
167static	struct	tm	*get_tm __P((u_32_t));
168#else
169static	struct	tm	*get_tm __P((time_t));
170#endif
171
172char	*hostname __P((int, int, u_32_t *));
173char	*portname __P((int, char *, u_int));
174int	main __P((int, char *[]));
175
176static	void	logopts __P((int, char *));
177static	void	init_tabs __P((void));
178static	char	*getproto __P((u_int));
179
180static	char	**protocols = NULL;
181static	char	**udp_ports = NULL;
182static	char	**tcp_ports = NULL;
183static	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
206static 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
224static 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
232static icmp_subtype_t timxceednames[] = {
233	{ ICMP_TIMXCEED_INTRANS,	"transit" },
234	{ ICMP_TIMXCEED_REASS,		"reassem" },
235	{ -2,				NULL }
236};
237
238static 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
245static 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
272static 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
281static icmp_subtype_t icmptimexceed6[] = {
282	{ ICMP6_TIME_EXCEED_TRANSIT,		"intransit" },
283	{ ICMP6_TIME_EXCEED_REASSEMBLY,		"reassem" },
284	{ -2,					NULL }
285};
286
287static icmp_subtype_t icmpparamprob6[] = {
288	{ ICMP6_PARAMPROB_HEADER,		"header" },
289	{ ICMP6_PARAMPROB_NEXTHEADER,		"nextheader" },
290	{ ICMP6_PARAMPROB_OPTION,		"option" },
291	{ -2,					NULL }
292};
293
294static 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
301static icmp_subtype_t icmpnodeinfo6[] = {
302	{ ICMP6_NI_SUCCESS,			"success" },
303	{ ICMP6_NI_REFUSED,			"refused" },
304	{ ICMP6_NI_UNKNOWN,			"unknown" },
305	{ -2,					NULL }
306};
307
308static 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
315static 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
349static icmp_subtype_t *find_icmpsubtype(type, table, tablesz)
350int type;
351icmp_subtype_t *table;
352size_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
374static icmp_type_t *find_icmptype(type, table, tablesz)
375int type;
376icmp_type_t *table;
377size_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
399static void handlehup(sig)
400int sig;
401{
402	signal(SIGHUP, handlehup);
403	donehup = 1;
404}
405
406
407static 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
492static char *getproto(p)
493u_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
508static int read_log(fd, lenp, buf, bufsize)
509int fd, bufsize, *lenp;
510char *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
524char	*hostname(res, v, ip)
525int	res, v;
526u_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
557char	*portname(res, proto, port)
558int	res;
559char	*proto;
560u_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
581static	char	*icmpname(type, code)
582u_int	type;
583u_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
612static	char	*icmpname6(type, code)
613u_int	type;
614u_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
644void	dumphex(log, dopts, buf, len)
645FILE	*log;
646int	dopts;
647char	*buf;
648int	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
707static	struct	tm	*get_tm(sec)
708#ifdef __hpux
709u_32_t	sec;
710#else
711time_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
722static	void	print_natlog(log, buf, blen)
723FILE	*log;
724char	*buf;
725int	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
805static	void	print_statelog(log, buf, blen)
806FILE	*log;
807char	*buf;
808int	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
922static	void	print_log(logtype, log, buf, blen)
923FILE	*log;
924char	*buf;
925int	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
981static	void	print_ipflog(log, buf, blen)
982FILE	*log;
983char	*buf;
984int	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
1256printipflog:
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
1347static void usage(prog)
1348char *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
1358static void write_pid(file)
1359char *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
1378static void flushlogs(file, log)
1379char *file;
1380FILE *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
1413static void logopts(turnon, options)
1414int turnon;
1415char *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
1446int main(argc, argv)
1447int argc;
1448char *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