ipmon.c revision 161357
1/*	$FreeBSD: head/contrib/ipfilter/tools/ipmon.c 161357 2006-08-16 12:23:02Z guido $	*/
2
3/*
4 * Copyright (C) 1993-2001, 2003 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.15 2006/03/18 06:59:39 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
756		sprintf(t, "Type: %d ", nl->nl_type);
757	t += strlen(t);
758
759	proto = getproto(nl->nl_p);
760
761	(void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip),
762		portname(res, proto, (u_int)nl->nl_inport));
763	t += strlen(t);
764	(void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip),
765		portname(res, proto, (u_int)nl->nl_outport));
766	t += strlen(t);
767	(void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip),
768		portname(res, proto, (u_int)nl->nl_origport));
769	t += strlen(t);
770	if (nl->nl_type == NL_EXPIRE) {
771#ifdef	USE_QUAD_T
772		(void) sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd",
773				(long long)nl->nl_pkts[0],
774				(long long)nl->nl_pkts[1],
775				(long long)nl->nl_bytes[0],
776				(long long)nl->nl_bytes[1]);
777#else
778		(void) sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld",
779				nl->nl_pkts[0], nl->nl_pkts[1],
780				nl->nl_bytes[0], nl->nl_bytes[1]);
781#endif
782		t += strlen(t);
783	}
784
785	*t++ = '\n';
786	*t++ = '\0';
787	if (opts & OPT_SYSLOG)
788		syslog(LOG_INFO, "%s", line);
789	else if (log != NULL)
790		(void) fprintf(log, "%s", line);
791}
792
793
794static	void	print_statelog(log, buf, blen)
795FILE	*log;
796char	*buf;
797int	blen;
798{
799	struct	ipslog *sl;
800	iplog_t	*ipl = (iplog_t *)buf;
801	char	*t = line, *proto;
802	struct	tm	*tm;
803	int	res, i, len;
804
805	sl = (struct ipslog *)((char *)ipl + sizeof(*ipl));
806	res = (opts & OPT_RESOLVE) ? 1 : 0;
807	tm = get_tm(ipl->ipl_sec);
808	len = sizeof(line);
809	if (!(opts & OPT_SYSLOG)) {
810		(void) strftime(t, len, "%d/%m/%Y ", tm);
811		i = strlen(t);
812		len -= i;
813		t += i;
814	}
815	(void) strftime(t, len, "%T", tm);
816	t += strlen(t);
817	(void) sprintf(t, ".%-.6ld ", ipl->ipl_usec);
818	t += strlen(t);
819
820	if (sl->isl_type == ISL_NEW)
821		strcpy(t, "STATE:NEW ");
822	else if (sl->isl_type == ISL_CLONE)
823		strcpy(t, "STATE:CLONED ");
824	else if (sl->isl_type == ISL_EXPIRE) {
825		if ((sl->isl_p == IPPROTO_TCP) &&
826		    (sl->isl_state[0] > IPF_TCPS_ESTABLISHED ||
827		     sl->isl_state[1] > IPF_TCPS_ESTABLISHED))
828			strcpy(t, "STATE:CLOSE ");
829		else
830			strcpy(t, "STATE:EXPIRE ");
831	} else if (sl->isl_type == ISL_FLUSH)
832		strcpy(t, "STATE:FLUSH ");
833	else if (sl->isl_type == ISL_INTERMEDIATE)
834		strcpy(t, "STATE:INTERMEDIATE ");
835	else if (sl->isl_type == ISL_REMOVE)
836		strcpy(t, "STATE:REMOVE ");
837	else if (sl->isl_type == ISL_KILLED)
838		strcpy(t, "STATE:KILLED ");
839	else
840		sprintf(t, "Type: %d ", sl->isl_type);
841	t += strlen(t);
842
843	proto = getproto(sl->isl_p);
844
845	if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) {
846		(void) sprintf(t, "%s,%s -> ",
847			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src),
848			portname(res, proto, (u_int)sl->isl_sport));
849		t += strlen(t);
850		(void) sprintf(t, "%s,%s PR %s",
851			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
852			portname(res, proto, (u_int)sl->isl_dport), proto);
853	} else if (sl->isl_p == IPPROTO_ICMP) {
854		(void) sprintf(t, "%s -> ", hostname(res, sl->isl_v,
855						     (u_32_t *)&sl->isl_src));
856		t += strlen(t);
857		(void) sprintf(t, "%s PR icmp %d",
858			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
859			sl->isl_itype);
860	} else if (sl->isl_p == IPPROTO_ICMPV6) {
861		(void) sprintf(t, "%s -> ", hostname(res, sl->isl_v,
862						     (u_32_t *)&sl->isl_src));
863		t += strlen(t);
864		(void) sprintf(t, "%s PR icmpv6 %d",
865			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
866			sl->isl_itype);
867	} else {
868		(void) sprintf(t, "%s -> ",
869			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src));
870		t += strlen(t);
871		(void) sprintf(t, "%s PR %s",
872			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
873			proto);
874	}
875	t += strlen(t);
876	if (sl->isl_tag != FR_NOLOGTAG) {
877		(void) sprintf(t, " tag %u", sl->isl_tag);
878		t += strlen(t);
879	}
880	if (sl->isl_type != ISL_NEW) {
881		sprintf(t,
882#ifdef	USE_QUAD_T
883#ifdef	PRId64
884			" Forward: Pkts in %" PRId64 " Bytes in %" PRId64
885			" Pkts out %" PRId64 " Bytes out %" PRId64
886			" Backward: Pkts in %" PRId64 " Bytes in %" PRId64
887			" Pkts out %" PRId64 " Bytes out %" PRId64,
888#else
889			" 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",
890#endif /* PRId64 */
891#else
892			" 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",
893#endif
894			sl->isl_pkts[0], sl->isl_bytes[0],
895			sl->isl_pkts[1], sl->isl_bytes[1],
896			sl->isl_pkts[2], sl->isl_bytes[2],
897			sl->isl_pkts[3], sl->isl_bytes[3]);
898
899		t += strlen(t);
900	}
901
902	*t++ = '\n';
903	*t++ = '\0';
904	if (opts & OPT_SYSLOG)
905		syslog(LOG_INFO, "%s", line);
906	else if (log != NULL)
907		(void) fprintf(log, "%s", line);
908}
909
910
911static	void	print_log(logtype, log, buf, blen)
912FILE	*log;
913char	*buf;
914int	logtype, blen;
915{
916	iplog_t	*ipl;
917	char *bp = NULL, *bpo = NULL;
918	int psize;
919
920	while (blen > 0) {
921		ipl = (iplog_t *)buf;
922		if ((u_long)ipl & (sizeof(long)-1)) {
923			if (bp)
924				bpo = bp;
925			bp = (char *)malloc(blen);
926			bcopy((char *)ipl, bp, blen);
927			if (bpo) {
928				free(bpo);
929				bpo = NULL;
930			}
931			buf = bp;
932			continue;
933		}
934
935		psize = ipl->ipl_dsize;
936		if (psize > blen)
937			break;
938
939		if (binarylog) {
940			fwrite(buf, psize, 1, binarylog);
941			fflush(binarylog);
942		}
943
944		if (logtype == IPL_LOGIPF) {
945			if (ipl->ipl_magic == IPL_MAGIC)
946				print_ipflog(log, buf, psize);
947
948		} else if (logtype == IPL_LOGNAT) {
949			if (ipl->ipl_magic == IPL_MAGIC_NAT)
950				print_natlog(log, buf, psize);
951
952		} else if (logtype == IPL_LOGSTATE) {
953			if (ipl->ipl_magic == IPL_MAGIC_STATE)
954				print_statelog(log, buf, psize);
955		}
956
957		blen -= psize;
958		buf += psize;
959	}
960	if (bp)
961		free(bp);
962	return;
963}
964
965
966static	void	print_ipflog(log, buf, blen)
967FILE	*log;
968char	*buf;
969int	blen;
970{
971	tcphdr_t	*tp;
972	struct	icmp	*ic;
973	struct	icmp	*icmp;
974	struct	tm	*tm;
975	char	*t, *proto;
976	int	i, v, lvl, res, len, off, plen, ipoff, defaction;
977	ip_t	*ipc, *ip;
978	u_32_t	*s, *d;
979	u_short	hl, p;
980	ipflog_t *ipf;
981	iplog_t	*ipl;
982#ifdef	USE_INET6
983	ip6_t *ip6;
984#endif
985
986	ipl = (iplog_t *)buf;
987	ipf = (ipflog_t *)((char *)buf + sizeof(*ipl));
988	ip = (ip_t *)((char *)ipf + sizeof(*ipf));
989	v = IP_V(ip);
990	res = (opts & OPT_RESOLVE) ? 1 : 0;
991	t = line;
992	*t = '\0';
993	tm = get_tm(ipl->ipl_sec);
994
995	len = sizeof(line);
996	if (!(opts & OPT_SYSLOG)) {
997		(void) strftime(t, len, "%d/%m/%Y ", tm);
998		i = strlen(t);
999		len -= i;
1000		t += i;
1001	}
1002	(void) strftime(t, len, "%T", tm);
1003	t += strlen(t);
1004	(void) sprintf(t, ".%-.6ld ", ipl->ipl_usec);
1005	t += strlen(t);
1006	if (ipl->ipl_count > 1) {
1007		(void) sprintf(t, "%dx ", ipl->ipl_count);
1008		t += strlen(t);
1009	}
1010#if (defined(MENTAT) || \
1011	(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
1012	(defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \
1013	(defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux)
1014	{
1015	char	ifname[sizeof(ipf->fl_ifname) + 1];
1016
1017	strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname));
1018	ifname[sizeof(ipf->fl_ifname)] = '\0';
1019	(void) sprintf(t, "%s", ifname);
1020	t += strlen(t);
1021# if defined(MENTAT) || defined(linux)
1022	if (ISALPHA(*(t - 1))) {
1023		sprintf(t, "%d", ipf->fl_unit);
1024		t += strlen(t);
1025	}
1026# endif
1027	}
1028#else
1029	for (len = 0; len < 3; len++)
1030		if (ipf->fl_ifname[len] == '\0')
1031			break;
1032	if (ipf->fl_ifname[len])
1033		len++;
1034	(void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit);
1035	t += strlen(t);
1036#endif
1037	if ((ipf->fl_group[0] == (char)~0) && (ipf->fl_group[1] == '\0'))
1038		strcat(t, " @-1:");
1039	else if (ipf->fl_group[0] == '\0')
1040		(void) strcpy(t, " @0:");
1041	else
1042		(void) sprintf(t, " @%s:", ipf->fl_group);
1043	t += strlen(t);
1044	if (ipf->fl_rule == 0xffffffff)
1045		strcat(t, "-1 ");
1046	else
1047		(void) sprintf(t, "%u ", ipf->fl_rule + 1);
1048	t += strlen(t);
1049
1050	lvl = LOG_NOTICE;
1051
1052 	if (ipf->fl_lflags & FI_SHORT) {
1053		*t++ = 'S';
1054		lvl = LOG_ERR;
1055	}
1056
1057	if (FR_ISPASS(ipf->fl_flags)) {
1058		if (ipf->fl_flags & FR_LOGP)
1059			*t++ = 'p';
1060		else
1061			*t++ = 'P';
1062	} else if (FR_ISBLOCK(ipf->fl_flags)) {
1063		if (ipf->fl_flags & FR_LOGB)
1064			*t++ = 'b';
1065		else
1066			*t++ = 'B';
1067		lvl = LOG_WARNING;
1068	} else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) {
1069		*t++ = 'L';
1070		lvl = LOG_INFO;
1071	} else if (ipf->fl_flags & FF_LOGNOMATCH) {
1072		*t++ = 'n';
1073	} else {
1074		*t++ = '?';
1075		lvl = LOG_EMERG;
1076	}
1077	if (ipf->fl_loglevel != 0xffff)
1078		lvl = ipf->fl_loglevel;
1079	*t++ = ' ';
1080	*t = '\0';
1081
1082	if (v == 6) {
1083#ifdef	USE_INET6
1084		off = 0;
1085		ipoff = 0;
1086		hl = sizeof(ip6_t);
1087		ip6 = (ip6_t *)ip;
1088		p = (u_short)ip6->ip6_nxt;
1089		s = (u_32_t *)&ip6->ip6_src;
1090		d = (u_32_t *)&ip6->ip6_dst;
1091		plen = hl + ntohs(ip6->ip6_plen);
1092#else
1093		sprintf(t, "ipv6");
1094		goto printipflog;
1095#endif
1096	} else if (v == 4) {
1097		hl = IP_HL(ip) << 2;
1098		ipoff = ip->ip_off;
1099		off = ipoff & IP_OFFMASK;
1100		p = (u_short)ip->ip_p;
1101		s = (u_32_t *)&ip->ip_src;
1102		d = (u_32_t *)&ip->ip_dst;
1103		plen = ip->ip_len;
1104	} else {
1105		goto printipflog;
1106	}
1107	proto = getproto(p);
1108
1109	if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) {
1110		tp = (tcphdr_t *)((char *)ip + hl);
1111		if (!(ipf->fl_lflags & FI_SHORT)) {
1112			(void) sprintf(t, "%s,%s -> ", hostname(res, v, s),
1113				portname(res, proto, (u_int)tp->th_sport));
1114			t += strlen(t);
1115			(void) sprintf(t, "%s,%s PR %s len %hu %hu",
1116				hostname(res, v, d),
1117				portname(res, proto, (u_int)tp->th_dport),
1118				proto, hl, plen);
1119			t += strlen(t);
1120
1121			if (p == IPPROTO_TCP) {
1122				*t++ = ' ';
1123				*t++ = '-';
1124				for (i = 0; tcpfl[i].value; i++)
1125					if (tp->th_flags & tcpfl[i].value)
1126						*t++ = tcpfl[i].flag;
1127				if (opts & OPT_VERBOSE) {
1128					(void) sprintf(t, " %lu %lu %hu",
1129						(u_long)(ntohl(tp->th_seq)),
1130						(u_long)(ntohl(tp->th_ack)),
1131						ntohs(tp->th_win));
1132					t += strlen(t);
1133				}
1134			}
1135			*t = '\0';
1136		} else {
1137			(void) sprintf(t, "%s -> ", hostname(res, v, s));
1138			t += strlen(t);
1139			(void) sprintf(t, "%s PR %s len %hu %hu",
1140				hostname(res, v, d), proto, hl, plen);
1141		}
1142	} else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) {
1143		ic = (struct icmp *)((char *)ip + hl);
1144		(void) sprintf(t, "%s -> ", hostname(res, v, s));
1145		t += strlen(t);
1146		(void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s",
1147			hostname(res, v, d), hl, plen,
1148			icmpname6(ic->icmp_type, ic->icmp_code));
1149	} else if ((p == IPPROTO_ICMP) && !off && (v == 4)) {
1150		ic = (struct icmp *)((char *)ip + hl);
1151		(void) sprintf(t, "%s -> ", hostname(res, v, s));
1152		t += strlen(t);
1153		(void) sprintf(t, "%s PR icmp len %hu %hu icmp %s",
1154			hostname(res, v, d), hl, plen,
1155			icmpname(ic->icmp_type, ic->icmp_code));
1156		if (ic->icmp_type == ICMP_UNREACH ||
1157		    ic->icmp_type == ICMP_SOURCEQUENCH ||
1158		    ic->icmp_type == ICMP_PARAMPROB ||
1159		    ic->icmp_type == ICMP_REDIRECT ||
1160		    ic->icmp_type == ICMP_TIMXCEED) {
1161			ipc = &ic->icmp_ip;
1162			i = ntohs(ipc->ip_len);
1163			/*
1164			 * XXX - try to guess endian of ip_len in ICMP
1165			 * returned data.
1166			 */
1167			if (i > 1500)
1168				i = ipc->ip_len;
1169			ipoff = ntohs(ipc->ip_off);
1170			proto = getproto(ipc->ip_p);
1171
1172			if (!(ipoff & IP_OFFMASK) &&
1173			    ((ipc->ip_p == IPPROTO_TCP) ||
1174			     (ipc->ip_p == IPPROTO_UDP))) {
1175				tp = (tcphdr_t *)((char *)ipc + hl);
1176				t += strlen(t);
1177				(void) sprintf(t, " for %s,%s -",
1178					HOSTNAME_V4(res, ipc->ip_src),
1179					portname(res, proto,
1180						 (u_int)tp->th_sport));
1181				t += strlen(t);
1182				(void) sprintf(t, " %s,%s PR %s len %hu %hu",
1183					HOSTNAME_V4(res, ipc->ip_dst),
1184					portname(res, proto,
1185						 (u_int)tp->th_dport),
1186					proto, IP_HL(ipc) << 2, i);
1187			} else if (!(ipoff & IP_OFFMASK) &&
1188				   (ipc->ip_p == IPPROTO_ICMP)) {
1189				icmp = (icmphdr_t *)((char *)ipc + hl);
1190
1191				t += strlen(t);
1192				(void) sprintf(t, " for %s -",
1193					HOSTNAME_V4(res, ipc->ip_src));
1194				t += strlen(t);
1195				(void) sprintf(t,
1196					" %s PR icmp len %hu %hu icmp %d/%d",
1197					HOSTNAME_V4(res, ipc->ip_dst),
1198					IP_HL(ipc) << 2, i,
1199					icmp->icmp_type, icmp->icmp_code);
1200			} else {
1201				t += strlen(t);
1202				(void) sprintf(t, " for %s -",
1203						HOSTNAME_V4(res, ipc->ip_src));
1204				t += strlen(t);
1205				(void) sprintf(t, " %s PR %s len %hu (%hu)",
1206					HOSTNAME_V4(res, ipc->ip_dst), proto,
1207					IP_HL(ipc) << 2, i);
1208				t += strlen(t);
1209				if (ipoff & IP_OFFMASK) {
1210					(void) sprintf(t,
1211						"(frag %d:%hu@%hu%s%s)",
1212						ntohs(ipc->ip_id),
1213						i - (IP_HL(ipc) << 2),
1214						(ipoff & IP_OFFMASK) << 3,
1215						ipoff & IP_MF ? "+" : "",
1216						ipoff & IP_DF ? "-" : "");
1217				}
1218			}
1219
1220		}
1221	} else {
1222		(void) sprintf(t, "%s -> ", hostname(res, v, s));
1223		t += strlen(t);
1224		(void) sprintf(t, "%s PR %s len %hu (%hu)",
1225			hostname(res, v, d), proto, hl, plen);
1226		t += strlen(t);
1227		if (off & IP_OFFMASK)
1228			(void) sprintf(t, " (frag %d:%hu@%hu%s%s)",
1229				ntohs(ip->ip_id),
1230				plen - hl, (off & IP_OFFMASK) << 3,
1231				ipoff & IP_MF ? "+" : "",
1232				ipoff & IP_DF ? "-" : "");
1233	}
1234	t += strlen(t);
1235
1236printipflog:
1237	if (ipf->fl_flags & FR_KEEPSTATE) {
1238		(void) strcpy(t, " K-S");
1239		t += strlen(t);
1240	}
1241
1242	if (ipf->fl_flags & FR_KEEPFRAG) {
1243		(void) strcpy(t, " K-F");
1244		t += strlen(t);
1245	}
1246
1247	if (ipf->fl_dir == 0)
1248		strcpy(t, " IN");
1249	else if (ipf->fl_dir == 1)
1250		strcpy(t, " OUT");
1251	t += strlen(t);
1252	if (ipf->fl_logtag != 0) {
1253		sprintf(t, " log-tag %d", ipf->fl_logtag);
1254		t += strlen(t);
1255	}
1256	if (ipf->fl_nattag.ipt_num[0] != 0) {
1257		strcpy(t, " nat-tag ");
1258		t += strlen(t);
1259		strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag));
1260		t += strlen(t);
1261	}
1262	if ((ipf->fl_lflags & FI_LOWTTL) != 0) {
1263			strcpy(t, " low-ttl");
1264			t += 8;
1265	}
1266	if ((ipf->fl_lflags & FI_OOW) != 0) {
1267			strcpy(t, " OOW");
1268			t += 4;
1269	}
1270	if ((ipf->fl_lflags & FI_BAD) != 0) {
1271			strcpy(t, " bad");
1272			t += 4;
1273	}
1274	if ((ipf->fl_lflags & FI_NATED) != 0) {
1275			strcpy(t, " NAT");
1276			t += 4;
1277	}
1278	if ((ipf->fl_lflags & FI_BADNAT) != 0) {
1279			strcpy(t, " bad-NAT");
1280			t += 8;
1281	}
1282	if ((ipf->fl_lflags & FI_BADSRC) != 0) {
1283			strcpy(t, " bad-src");
1284			t += 8;
1285	}
1286	if ((ipf->fl_lflags & FI_MULTICAST) != 0) {
1287			strcpy(t, " multicast");
1288			t += 10;
1289	}
1290	if ((ipf->fl_lflags & FI_BROADCAST) != 0) {
1291			strcpy(t, " broadcast");
1292			t += 10;
1293	}
1294	if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) ==
1295	    FI_MBCAST) {
1296			strcpy(t, " mbcast");
1297			t += 7;
1298	}
1299	*t++ = '\n';
1300	*t++ = '\0';
1301	defaction = 0;
1302	if (conf_file != NULL)
1303		defaction = check_action(buf, line, opts, lvl);
1304	if (defaction == 0) {
1305		if (opts & OPT_SYSLOG)
1306			syslog(lvl, "%s", line);
1307		else if (log != NULL)
1308			(void) fprintf(log, "%s", line);
1309
1310		if (opts & OPT_HEXHDR)
1311			dumphex(log, opts, buf,
1312				sizeof(iplog_t) + sizeof(*ipf));
1313		if (opts & OPT_HEXBODY)
1314			dumphex(log, opts, (char *)ip,
1315				ipf->fl_plen + ipf->fl_hlen);
1316		else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY))
1317			dumphex(log, opts, (char *)ip + ipf->fl_hlen,
1318				ipf->fl_plen);
1319	}
1320}
1321
1322
1323static void usage(prog)
1324char *prog;
1325{
1326	fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog);
1327	exit(1);
1328}
1329
1330
1331static void write_pid(file)
1332char *file;
1333{
1334	FILE *fp = NULL;
1335	int fd;
1336
1337	if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) {
1338		fp = fdopen(fd, "w");
1339		if (fp == NULL) {
1340			close(fd);
1341			fprintf(stderr,
1342				"unable to open/create pid file: %s\n", file);
1343			return;
1344		}
1345		fprintf(fp, "%d", getpid());
1346		fclose(fp);
1347	}
1348}
1349
1350
1351static void flushlogs(file, log)
1352char *file;
1353FILE *log;
1354{
1355	int	fd, flushed = 0;
1356
1357	if ((fd = open(file, O_RDWR)) == -1) {
1358		(void) fprintf(stderr, "%s: open: %s\n",
1359			       file, STRERROR(errno));
1360		exit(1);
1361	}
1362
1363	if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
1364		printf("%d bytes flushed from log buffer\n",
1365			flushed);
1366		fflush(stdout);
1367	} else
1368		perror("SIOCIPFFB");
1369	(void) close(fd);
1370
1371	if (flushed) {
1372		if (opts & OPT_SYSLOG) {
1373			syslog(LOG_INFO, "%d bytes flushed from log\n",
1374				flushed);
1375		} else if ((log != stdout) && (log != NULL)) {
1376			fprintf(log, "%d bytes flushed from log\n", flushed);
1377		}
1378	}
1379}
1380
1381
1382static void logopts(turnon, options)
1383int turnon;
1384char *options;
1385{
1386	int flags = 0;
1387	char *s;
1388
1389	for (s = options; *s; s++)
1390	{
1391		switch (*s)
1392		{
1393		case 'N' :
1394			flags |= OPT_NAT;
1395			break;
1396		case 'S' :
1397			flags |= OPT_STATE;
1398			break;
1399		case 'I' :
1400			flags |= OPT_FILTER;
1401			break;
1402		default :
1403			fprintf(stderr, "Unknown log option %c\n", *s);
1404			exit(1);
1405		}
1406	}
1407
1408	if (turnon)
1409		opts |= flags;
1410	else
1411		opts &= ~(flags);
1412}
1413
1414
1415int main(argc, argv)
1416int argc;
1417char *argv[];
1418{
1419	struct	stat	sb;
1420	FILE	*log = stdout;
1421	FILE	*fp;
1422	int	fd[3], doread, n, i;
1423	int	tr, nr, regular[3], c;
1424	int	fdt[3], devices = 0, make_daemon = 0;
1425	char	buf[DEFAULT_IPFLOGSIZE], *iplfile[3], *s;
1426	extern	int	optind;
1427	extern	char	*optarg;
1428
1429	fd[0] = fd[1] = fd[2] = -1;
1430	fdt[0] = fdt[1] = fdt[2] = -1;
1431	iplfile[0] = IPL_NAME;
1432	iplfile[1] = IPNAT_NAME;
1433	iplfile[2] = IPSTATE_NAME;
1434
1435	while ((c = getopt(argc, argv,
1436			   "?abB:C:Df:FhL:nN:o:O:pP:sS:tvxX")) != -1)
1437		switch (c)
1438		{
1439		case 'a' :
1440			opts |= OPT_LOGALL;
1441			fdt[0] = IPL_LOGIPF;
1442			fdt[1] = IPL_LOGNAT;
1443			fdt[2] = IPL_LOGSTATE;
1444			break;
1445		case 'b' :
1446			opts |= OPT_LOGBODY;
1447			break;
1448		case 'B' :
1449			binarylogfile = optarg;
1450			binarylog = fopen(optarg, "a");
1451			break;
1452		case 'C' :
1453			conf_file = optarg;
1454			break;
1455		case 'D' :
1456			make_daemon = 1;
1457			break;
1458		case 'f' : case 'I' :
1459			opts |= OPT_FILTER;
1460			fdt[0] = IPL_LOGIPF;
1461			iplfile[0] = optarg;
1462			break;
1463		case 'F' :
1464			flushlogs(iplfile[0], log);
1465			flushlogs(iplfile[1], log);
1466			flushlogs(iplfile[2], log);
1467			break;
1468		case 'L' :
1469			logfac = fac_findname(optarg);
1470			if (logfac == -1) {
1471				fprintf(stderr,
1472					"Unknown syslog facility '%s'\n",
1473					 optarg);
1474				exit(1);
1475			}
1476			break;
1477		case 'n' :
1478			opts |= OPT_RESOLVE;
1479			break;
1480		case 'N' :
1481			opts |= OPT_NAT;
1482			fdt[1] = IPL_LOGNAT;
1483			iplfile[1] = optarg;
1484			break;
1485		case 'o' : case 'O' :
1486			logopts(c == 'o', optarg);
1487			fdt[0] = fdt[1] = fdt[2] = -1;
1488			if (opts & OPT_FILTER)
1489				fdt[0] = IPL_LOGIPF;
1490			if (opts & OPT_NAT)
1491				fdt[1] = IPL_LOGNAT;
1492			if (opts & OPT_STATE)
1493				fdt[2] = IPL_LOGSTATE;
1494			break;
1495		case 'p' :
1496			opts |= OPT_PORTNUM;
1497			break;
1498		case 'P' :
1499			pidfile = optarg;
1500			break;
1501		case 's' :
1502			s = strrchr(argv[0], '/');
1503			if (s == NULL)
1504				s = argv[0];
1505			else
1506				s++;
1507			openlog(s, LOG_NDELAY|LOG_PID, logfac);
1508			s = NULL;
1509			opts |= OPT_SYSLOG;
1510			log = NULL;
1511			break;
1512		case 'S' :
1513			opts |= OPT_STATE;
1514			fdt[2] = IPL_LOGSTATE;
1515			iplfile[2] = optarg;
1516			break;
1517		case 't' :
1518			opts |= OPT_TAIL;
1519			break;
1520		case 'v' :
1521			opts |= OPT_VERBOSE;
1522			break;
1523		case 'x' :
1524			opts |= OPT_HEXBODY;
1525			break;
1526		case 'X' :
1527			opts |= OPT_HEXHDR;
1528			break;
1529		default :
1530		case 'h' :
1531		case '?' :
1532			usage(argv[0]);
1533		}
1534
1535	init_tabs();
1536	if (conf_file)
1537		if (load_config(conf_file) == -1)
1538			exit(1);
1539
1540	/*
1541	 * Default action is to only open the filter log file.
1542	 */
1543	if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1))
1544		fdt[0] = IPL_LOGIPF;
1545
1546	for (i = 0; i < 3; i++) {
1547		if (fdt[i] == -1)
1548			continue;
1549		if (!strcmp(iplfile[i], "-"))
1550			fd[i] = 0;
1551		else {
1552			if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) {
1553				(void) fprintf(stderr,
1554					       "%s: open: %s\n", iplfile[i],
1555					       STRERROR(errno));
1556				exit(1);
1557				/* NOTREACHED */
1558			}
1559			if (fstat(fd[i], &sb) == -1) {
1560				(void) fprintf(stderr, "%d: fstat: %s\n",
1561					       fd[i], STRERROR(errno));
1562				exit(1);
1563				/* NOTREACHED */
1564			}
1565			if (!(regular[i] = !S_ISCHR(sb.st_mode)))
1566				devices++;
1567		}
1568	}
1569
1570	if (!(opts & OPT_SYSLOG)) {
1571		logfile = argv[optind];
1572		log = logfile ? fopen(logfile, "a") : stdout;
1573		if (log == NULL) {
1574			(void) fprintf(stderr, "%s: fopen: %s\n",
1575				       argv[optind], STRERROR(errno));
1576			exit(1);
1577			/* NOTREACHED */
1578		}
1579		setvbuf(log, NULL, _IONBF, 0);
1580	} else
1581		log = NULL;
1582
1583	if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) {
1584#if BSD >= 199306
1585		daemon(0, !(opts & OPT_SYSLOG));
1586#else
1587		int pid;
1588		if ((pid = fork()) > 0)
1589			exit(0);
1590		if (pid < 0) {
1591			(void) fprintf(stderr, "%s: fork() failed: %s\n",
1592				       argv[0], STRERROR(errno));
1593			exit(1);
1594			/* NOTREACHED */
1595		}
1596		setsid();
1597		if ((opts & OPT_SYSLOG))
1598			close(2);
1599#endif /* !BSD */
1600		close(0);
1601		close(1);
1602		write_pid(pidfile);
1603	}
1604
1605	signal(SIGHUP, handlehup);
1606
1607	for (doread = 1; doread; ) {
1608		nr = 0;
1609
1610		for (i = 0; i < 3; i++) {
1611			tr = 0;
1612			if (fdt[i] == -1)
1613				continue;
1614			if (!regular[i]) {
1615				if (ioctl(fd[i], FIONREAD, &tr) == -1) {
1616					if (opts & OPT_SYSLOG)
1617						syslog(LOG_CRIT,
1618						       "ioctl(FIONREAD): %m");
1619					else
1620						perror("ioctl(FIONREAD)");
1621					exit(1);
1622					/* NOTREACHED */
1623				}
1624			} else {
1625				tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size);
1626				if (!tr && !(opts & OPT_TAIL))
1627					doread = 0;
1628			}
1629			if (!tr)
1630				continue;
1631			nr += tr;
1632
1633			tr = read_log(fd[i], &n, buf, sizeof(buf));
1634			if (donehup) {
1635				if (logfile && (fp = fopen(logfile, "a"))) {
1636					fclose(log);
1637					log = fp;
1638				}
1639				if (binarylogfile &&
1640				    (fp = fopen(binarylogfile, "a"))) {
1641					fclose(binarylog);
1642					binarylog = fp;
1643				}
1644				init_tabs();
1645				if (conf_file != NULL)
1646					load_config(conf_file);
1647				donehup = 0;
1648			}
1649
1650			switch (tr)
1651			{
1652			case -1 :
1653				if (opts & OPT_SYSLOG)
1654					syslog(LOG_CRIT, "read: %m\n");
1655				else
1656					perror("read");
1657				doread = 0;
1658				break;
1659			case 1 :
1660				if (opts & OPT_SYSLOG)
1661					syslog(LOG_CRIT, "aborting logging\n");
1662				else if (log != NULL)
1663					fprintf(log, "aborting logging\n");
1664				doread = 0;
1665				break;
1666			case 2 :
1667				break;
1668			case 0 :
1669				if (n > 0) {
1670					print_log(fdt[i], log, buf, n);
1671					if (!(opts & OPT_SYSLOG))
1672						fflush(log);
1673				}
1674				break;
1675			}
1676		}
1677		if (!nr && ((opts & OPT_TAIL) || devices))
1678			sleep(1);
1679	}
1680	return(0);
1681	/* NOTREACHED */
1682}
1683