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