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