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