ipmon.c revision 145519
1/*	$FreeBSD: head/contrib/ipfilter/tools/ipmon.c 145519 2005-04-25 18:20:15Z darrenr $	*/
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.8 2004/12/09 19:41:26 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	}
424
425	if (udp_ports != NULL) {
426		for (i = 0; i < 65536; i++)
427			if (udp_ports[i] != NULL) {
428				free(udp_ports[i]);
429				udp_ports[i] = NULL;
430			}
431		free(udp_ports);
432		udp_ports = NULL;
433	}
434	udp_ports = (char **)malloc(65536 * sizeof(*udp_ports));
435	if (udp_ports != NULL)
436		bzero((char *)udp_ports, 65536 * sizeof(*udp_ports));
437
438	if (tcp_ports != NULL) {
439		for (i = 0; i < 65536; i++)
440			if (tcp_ports[i] != NULL) {
441				free(tcp_ports[i]);
442				tcp_ports[i] = NULL;
443			}
444		free(tcp_ports);
445		tcp_ports = NULL;
446	}
447	tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports));
448	if (tcp_ports != NULL)
449		bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports));
450
451	setservent(1);
452	while ((s = getservent()) != NULL) {
453		if (s->s_proto == NULL)
454			continue;
455		else if (!strcmp(s->s_proto, "tcp")) {
456			port = ntohs(s->s_port);
457			name = s->s_name;
458			tab = tcp_ports;
459		} else if (!strcmp(s->s_proto, "udp")) {
460			port = ntohs(s->s_port);
461			name = s->s_name;
462			tab = udp_ports;
463		} else
464			continue;
465		if ((port < 0 || port > 65535) || (name == NULL))
466			continue;
467		if (tab != NULL)
468			tab[port] = strdup(name);
469	}
470	endservent();
471}
472
473
474static char *getproto(p)
475u_int p;
476{
477	static char pnum[4];
478	char *s;
479
480	p &= 0xff;
481	s = protocols ? protocols[p] : NULL;
482	if (s == NULL) {
483		sprintf(pnum, "%u", p);
484		s = pnum;
485	}
486	return s;
487}
488
489
490static int read_log(fd, lenp, buf, bufsize)
491int fd, bufsize, *lenp;
492char *buf;
493{
494	int	nr;
495
496	nr = read(fd, buf, bufsize);
497	if (!nr)
498		return 2;
499	if ((nr < 0) && (errno != EINTR))
500		return -1;
501	*lenp = nr;
502	return 0;
503}
504
505
506char	*hostname(res, v, ip)
507int	res, v;
508u_32_t	*ip;
509{
510# define MAX_INETA	16
511	static char hname[MAXHOSTNAMELEN + MAX_INETA + 3];
512#ifdef	USE_INET6
513	static char hostbuf[MAXHOSTNAMELEN+1];
514#endif
515	struct hostent *hp;
516	struct in_addr ipa;
517
518	if (v == 4) {
519		ipa.s_addr = *ip;
520		if (!res)
521			return inet_ntoa(ipa);
522		hp = gethostbyaddr((char *)ip, sizeof(*ip), AF_INET);
523		if (!hp)
524			return inet_ntoa(ipa);
525		sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name,
526			inet_ntoa(ipa));
527		return hname;
528	}
529#ifdef	USE_INET6
530	(void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
531	hostbuf[MAXHOSTNAMELEN] = '\0';
532	return hostbuf;
533#else
534	return "IPv6";
535#endif
536}
537
538
539char	*portname(res, proto, port)
540int	res;
541char	*proto;
542u_int	port;
543{
544	static	char	pname[8];
545	char	*s;
546
547	port = ntohs(port);
548	port &= 0xffff;
549	(void) sprintf(pname, "%u", port);
550	if (!res || (opts & OPT_PORTNUM))
551		return pname;
552	s = NULL;
553	if (!strcmp(proto, "tcp"))
554		s = tcp_ports[port];
555	else if (!strcmp(proto, "udp"))
556		s = udp_ports[port];
557	if (s == NULL)
558		s = pname;
559	return s;
560}
561
562
563static	char	*icmpname(type, code)
564u_int	type;
565u_int	code;
566{
567	static char name[80];
568	icmp_subtype_t *ist;
569	icmp_type_t *it;
570	char *s;
571
572	s = NULL;
573	it = find_icmptype(type, icmptypes, sizeof(icmptypes) / sizeof(*it));
574	if (it != NULL)
575		s = it->it_name;
576
577	if (s == NULL)
578		sprintf(name, "icmptype(%d)/", type);
579	else
580		sprintf(name, "%s/", s);
581
582	ist = NULL;
583	if (it != NULL && it->it_subtable != NULL)
584		ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize);
585
586	if (ist != NULL && ist->ist_name != NULL)
587		strcat(name, ist->ist_name);
588	else
589		sprintf(name + strlen(name), "%d", code);
590
591	return name;
592}
593
594static	char	*icmpname6(type, code)
595u_int	type;
596u_int	code;
597{
598	static char name[80];
599	icmp_subtype_t *ist;
600	icmp_type_t *it;
601	char *s;
602
603	s = NULL;
604	it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it));
605	if (it != NULL)
606		s = it->it_name;
607
608	if (s == NULL)
609		sprintf(name, "icmpv6type(%d)/", type);
610	else
611		sprintf(name, "%s/", s);
612
613	ist = NULL;
614	if (it != NULL && it->it_subtable != NULL)
615		ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize);
616
617	if (ist != NULL && ist->ist_name != NULL)
618		strcat(name, ist->ist_name);
619	else
620		sprintf(name + strlen(name), "%d", code);
621
622	return name;
623}
624
625
626void	dumphex(log, dopts, buf, len)
627FILE	*log;
628int	dopts;
629char	*buf;
630int	len;
631{
632	char	hline[80];
633	int	i, j, k;
634	u_char	*s = (u_char *)buf, *t = (u_char *)hline;
635
636	if (buf == NULL || len == 0)
637		return;
638
639	*hline = '\0';
640
641	for (i = len, j = 0; i; i--, j++, s++) {
642		if (j && !(j & 0xf)) {
643			*t++ = '\n';
644			*t = '\0';
645			if (!(dopts & OPT_SYSLOG))
646				fputs(hline, log);
647			else
648				syslog(LOG_INFO, "%s", hline);
649			t = (u_char *)hline;
650			*t = '\0';
651		}
652		sprintf((char *)t, "%02x", *s & 0xff);
653		t += 2;
654		if (!((j + 1) & 0xf)) {
655			s -= 15;
656			sprintf((char *)t, "        ");
657			t += 8;
658			for (k = 16; k; k--, s++)
659				*t++ = (ISPRINT(*s) ? *s : '.');
660			s--;
661		}
662
663		if ((j + 1) & 0xf)
664			*t++ = ' ';;
665	}
666
667	if (j & 0xf) {
668		for (k = 16 - (j & 0xf); k; k--) {
669			*t++ = ' ';
670			*t++ = ' ';
671			*t++ = ' ';
672		}
673		sprintf((char *)t, "       ");
674		t += 7;
675		s -= j & 0xf;
676		for (k = j & 0xf; k; k--, s++)
677			*t++ = (ISPRINT(*s) ? *s : '.');
678		*t++ = '\n';
679		*t = '\0';
680	}
681	if (!(dopts & OPT_SYSLOG)) {
682		fputs(hline, log);
683		fflush(log);
684	} else
685		syslog(LOG_INFO, "%s", hline);
686}
687
688
689static	struct	tm	*get_tm(sec)
690#ifdef __hpux
691u_32_t	sec;
692#else
693time_t	sec;
694#endif
695{
696	struct tm *tm;
697	time_t t;
698
699	t = sec;
700	tm = localtime(&t);
701	return tm;
702}
703
704static	void	print_natlog(log, buf, blen)
705FILE	*log;
706char	*buf;
707int	blen;
708{
709	struct	natlog	*nl;
710	iplog_t	*ipl = (iplog_t *)buf;
711	char	*t = line;
712	struct	tm	*tm;
713	int	res, i, len;
714	char	*proto;
715
716	nl = (struct natlog *)((char *)ipl + sizeof(*ipl));
717	res = (opts & OPT_RESOLVE) ? 1 : 0;
718	tm = get_tm(ipl->ipl_sec);
719	len = sizeof(line);
720	if (!(opts & OPT_SYSLOG)) {
721		(void) strftime(t, len, "%d/%m/%Y ", tm);
722		i = strlen(t);
723		len -= i;
724		t += i;
725	}
726	(void) strftime(t, len, "%T", tm);
727	t += strlen(t);
728	(void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nl_rule + 1);
729	t += strlen(t);
730
731	if (nl->nl_type == NL_NEWMAP)
732		strcpy(t, "NAT:MAP ");
733	else if (nl->nl_type == NL_NEWRDR)
734		strcpy(t, "NAT:RDR ");
735	else if (nl->nl_type == NL_FLUSH)
736		strcpy(t, "NAT:FLUSH ");
737	else if (nl->nl_type == NL_EXPIRE)
738		strcpy(t, "NAT:EXPIRE ");
739	else if (nl->nl_type == NL_NEWBIMAP)
740		strcpy(t, "NAT:BIMAP ");
741	else if (nl->nl_type == NL_NEWBLOCK)
742		strcpy(t, "NAT:MAPBLOCK ");
743	else if (nl->nl_type == NL_CLONE)
744		strcpy(t, "NAT:CLONE ");
745	else
746		sprintf(t, "Type: %d ", nl->nl_type);
747	t += strlen(t);
748
749	proto = getproto(nl->nl_p);
750
751	(void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip),
752		portname(res, proto, (u_int)nl->nl_inport));
753	t += strlen(t);
754	(void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip),
755		portname(res, proto, (u_int)nl->nl_outport));
756	t += strlen(t);
757	(void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip),
758		portname(res, proto, (u_int)nl->nl_origport));
759	t += strlen(t);
760	if (nl->nl_type == NL_EXPIRE) {
761#ifdef	USE_QUAD_T
762		(void) sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd",
763				(long long)nl->nl_pkts[0],
764				(long long)nl->nl_pkts[1],
765				(long long)nl->nl_bytes[0],
766				(long long)nl->nl_bytes[1]);
767#else
768		(void) sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld",
769				nl->nl_pkts[0], nl->nl_pkts[1],
770				nl->nl_bytes[0], nl->nl_bytes[1]);
771#endif
772		t += strlen(t);
773	}
774
775	*t++ = '\n';
776	*t++ = '\0';
777	if (opts & OPT_SYSLOG)
778		syslog(LOG_INFO, "%s", line);
779	else
780		(void) fprintf(log, "%s", line);
781}
782
783
784static	void	print_statelog(log, buf, blen)
785FILE	*log;
786char	*buf;
787int	blen;
788{
789	struct	ipslog *sl;
790	iplog_t	*ipl = (iplog_t *)buf;
791	char	*t = line, *proto;
792	struct	tm	*tm;
793	int	res, i, len;
794
795	sl = (struct ipslog *)((char *)ipl + sizeof(*ipl));
796	res = (opts & OPT_RESOLVE) ? 1 : 0;
797	tm = get_tm(ipl->ipl_sec);
798	len = sizeof(line);
799	if (!(opts & OPT_SYSLOG)) {
800		(void) strftime(t, len, "%d/%m/%Y ", tm);
801		i = strlen(t);
802		len -= i;
803		t += i;
804	}
805	(void) strftime(t, len, "%T", tm);
806	t += strlen(t);
807	(void) sprintf(t, ".%-.6ld ", ipl->ipl_usec);
808	t += strlen(t);
809
810	if (sl->isl_type == ISL_NEW)
811		strcpy(t, "STATE:NEW ");
812	else if (sl->isl_type == ISL_CLONE)
813		strcpy(t, "STATE:CLONED ");
814	else if (sl->isl_type == ISL_EXPIRE) {
815		if ((sl->isl_p == IPPROTO_TCP) &&
816		    (sl->isl_state[0] > IPF_TCPS_ESTABLISHED ||
817		     sl->isl_state[1] > IPF_TCPS_ESTABLISHED))
818			strcpy(t, "STATE:CLOSE ");
819		else
820			strcpy(t, "STATE:EXPIRE ");
821	} else if (sl->isl_type == ISL_FLUSH)
822		strcpy(t, "STATE:FLUSH ");
823	else if (sl->isl_type == ISL_INTERMEDIATE)
824		strcpy(t, "STATE:INTERMEDIATE ");
825	else if (sl->isl_type == ISL_REMOVE)
826		strcpy(t, "STATE:REMOVE ");
827	else if (sl->isl_type == ISL_KILLED)
828		strcpy(t, "STATE:KILLED ");
829	else
830		sprintf(t, "Type: %d ", sl->isl_type);
831	t += strlen(t);
832
833	proto = getproto(sl->isl_p);
834
835	if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) {
836		(void) sprintf(t, "%s,%s -> ",
837			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src),
838			portname(res, proto, (u_int)sl->isl_sport));
839		t += strlen(t);
840		(void) sprintf(t, "%s,%s PR %s",
841			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
842			portname(res, proto, (u_int)sl->isl_dport), proto);
843	} else if (sl->isl_p == IPPROTO_ICMP) {
844		(void) sprintf(t, "%s -> ", hostname(res, sl->isl_v,
845						     (u_32_t *)&sl->isl_src));
846		t += strlen(t);
847		(void) sprintf(t, "%s PR icmp %d",
848			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
849			sl->isl_itype);
850	} else if (sl->isl_p == IPPROTO_ICMPV6) {
851		(void) sprintf(t, "%s -> ", hostname(res, sl->isl_v,
852						     (u_32_t *)&sl->isl_src));
853		t += strlen(t);
854		(void) sprintf(t, "%s PR icmpv6 %d",
855			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
856			sl->isl_itype);
857	} else {
858		(void) sprintf(t, "%s -> ",
859			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src));
860		t += strlen(t);
861		(void) sprintf(t, "%s PR %s",
862			hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst),
863			proto);
864	}
865	t += strlen(t);
866	if (sl->isl_tag != FR_NOLOGTAG) {
867		(void) sprintf(t, " tag %u", sl->isl_tag);
868		t += strlen(t);
869	}
870	if (sl->isl_type != ISL_NEW) {
871		sprintf(t,
872#ifdef	USE_QUAD_T
873#ifdef	PRId64
874			" Forward: Pkts in %" PRId64 " Bytes in %" PRId64
875			" Pkts out %" PRId64 " Bytes out %" PRId64
876			" Backward: Pkts in %" PRId64 " Bytes in %" PRId64
877			" Pkts out %" PRId64 " Bytes out %" PRId64,
878#else
879			" 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",
880#endif /* PRId64 */
881#else
882			" 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",
883#endif
884			sl->isl_pkts[0], sl->isl_bytes[0],
885			sl->isl_pkts[1], sl->isl_bytes[1],
886			sl->isl_pkts[2], sl->isl_bytes[2],
887			sl->isl_pkts[3], sl->isl_bytes[3]);
888
889		t += strlen(t);
890	}
891
892	*t++ = '\n';
893	*t++ = '\0';
894	if (opts & OPT_SYSLOG)
895		syslog(LOG_INFO, "%s", line);
896	else
897		(void) fprintf(log, "%s", line);
898}
899
900
901static	void	print_log(logtype, log, buf, blen)
902FILE	*log;
903char	*buf;
904int	logtype, blen;
905{
906	iplog_t	*ipl;
907	char *bp = NULL, *bpo = NULL;
908	int psize;
909
910	while (blen > 0) {
911		ipl = (iplog_t *)buf;
912		if ((u_long)ipl & (sizeof(long)-1)) {
913			if (bp)
914				bpo = bp;
915			bp = (char *)malloc(blen);
916			bcopy((char *)ipl, bp, blen);
917			if (bpo) {
918				free(bpo);
919				bpo = NULL;
920			}
921			buf = bp;
922			continue;
923		}
924
925		psize = ipl->ipl_dsize;
926		if (psize > blen)
927			break;
928
929		if (binarylog) {
930			fwrite(buf, psize, 1, binarylog);
931			fflush(binarylog);
932		}
933
934		if (logtype == IPL_LOGIPF) {
935			if (ipl->ipl_magic == IPL_MAGIC)
936				print_ipflog(log, buf, psize);
937
938		} else if (logtype == IPL_LOGNAT) {
939			if (ipl->ipl_magic == IPL_MAGIC_NAT)
940				print_natlog(log, buf, psize);
941
942		} else if (logtype == IPL_LOGSTATE) {
943			if (ipl->ipl_magic == IPL_MAGIC_STATE)
944				print_statelog(log, buf, psize);
945		}
946
947		blen -= psize;
948		buf += psize;
949	}
950	if (bp)
951		free(bp);
952	return;
953}
954
955
956static	void	print_ipflog(log, buf, blen)
957FILE	*log;
958char	*buf;
959int	blen;
960{
961	tcphdr_t	*tp;
962	struct	icmp	*ic;
963	struct	icmp	*icmp;
964	struct	tm	*tm;
965	char	*t, *proto;
966	int	i, v, lvl, res, len, off, plen, ipoff, defaction;
967	ip_t	*ipc, *ip;
968	u_32_t	*s, *d;
969	u_short	hl, p;
970	ipflog_t *ipf;
971	iplog_t	*ipl;
972#ifdef	USE_INET6
973	ip6_t *ip6;
974#endif
975
976	ipl = (iplog_t *)buf;
977	ipf = (ipflog_t *)((char *)buf + sizeof(*ipl));
978	ip = (ip_t *)((char *)ipf + sizeof(*ipf));
979	v = IP_V(ip);
980	res = (opts & OPT_RESOLVE) ? 1 : 0;
981	t = line;
982	*t = '\0';
983	tm = get_tm(ipl->ipl_sec);
984
985	len = sizeof(line);
986	if (!(opts & OPT_SYSLOG)) {
987		(void) strftime(t, len, "%d/%m/%Y ", tm);
988		i = strlen(t);
989		len -= i;
990		t += i;
991	}
992	(void) strftime(t, len, "%T", tm);
993	t += strlen(t);
994	(void) sprintf(t, ".%-.6ld ", ipl->ipl_usec);
995	t += strlen(t);
996	if (ipl->ipl_count > 1) {
997		(void) sprintf(t, "%dx ", ipl->ipl_count);
998		t += strlen(t);
999	}
1000#if (defined(MENTAT) || \
1001	(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
1002	(defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \
1003	(defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux)
1004	{
1005	char	ifname[sizeof(ipf->fl_ifname) + 1];
1006
1007	strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname));
1008	ifname[sizeof(ipf->fl_ifname)] = '\0';
1009	(void) sprintf(t, "%s", ifname);
1010	t += strlen(t);
1011# if defined(MENTAT) || defined(linux)
1012	if (ISALPHA(*(t - 1))) {
1013		sprintf(t, "%d", ipf->fl_unit);
1014		t += strlen(t);
1015	}
1016# endif
1017	}
1018#else
1019	for (len = 0; len < 3; len++)
1020		if (ipf->fl_ifname[len] == '\0')
1021			break;
1022	if (ipf->fl_ifname[len])
1023		len++;
1024	(void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit);
1025	t += strlen(t);
1026#endif
1027#ifdef __sgi
1028	if ((ipf->fl_group[0] == 255) && (ipf->fl_group[1] == '\0'))
1029#else
1030	if ((ipf->fl_group[0] == -1) && (ipf->fl_group[1] == '\0'))
1031#endif
1032		strcat(t, " @-1:");
1033	else if (ipf->fl_group[0] == '\0')
1034		(void) strcpy(t, " @0:");
1035	else
1036		(void) sprintf(t, " @%s:", ipf->fl_group);
1037	t += strlen(t);
1038	if (ipf->fl_rule == 0xffffffff)
1039		strcat(t, "-1 ");
1040	else
1041		(void) sprintf(t, "%u ", ipf->fl_rule + 1);
1042	t += strlen(t);
1043
1044	lvl = LOG_NOTICE;
1045
1046 	if (ipf->fl_lflags & FI_SHORT) {
1047		*t++ = 'S';
1048		lvl = LOG_ERR;
1049	}
1050
1051	if (FR_ISPASS(ipf->fl_flags)) {
1052		if (ipf->fl_flags & FR_LOGP)
1053			*t++ = 'p';
1054		else
1055			*t++ = 'P';
1056	} else if (FR_ISBLOCK(ipf->fl_flags)) {
1057		if (ipf->fl_flags & FR_LOGB)
1058			*t++ = 'b';
1059		else
1060			*t++ = 'B';
1061		lvl = LOG_WARNING;
1062	} else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) {
1063		*t++ = 'L';
1064		lvl = LOG_INFO;
1065	} else if (ipf->fl_flags & FF_LOGNOMATCH) {
1066		*t++ = 'n';
1067	} else {
1068		*t++ = '?';
1069		lvl = LOG_EMERG;
1070	}
1071	if (ipf->fl_loglevel != 0xffff)
1072		lvl = ipf->fl_loglevel;
1073	*t++ = ' ';
1074	*t = '\0';
1075
1076	if (v == 6) {
1077#ifdef	USE_INET6
1078		off = 0;
1079		ipoff = 0;
1080		hl = sizeof(ip6_t);
1081		ip6 = (ip6_t *)ip;
1082		p = (u_short)ip6->ip6_nxt;
1083		s = (u_32_t *)&ip6->ip6_src;
1084		d = (u_32_t *)&ip6->ip6_dst;
1085		plen = hl + ntohs(ip6->ip6_plen);
1086#else
1087		sprintf(t, "ipv6");
1088		goto printipflog;
1089#endif
1090	} else if (v == 4) {
1091		hl = IP_HL(ip) << 2;
1092		ipoff = ip->ip_off;
1093		off = ipoff & IP_OFFMASK;
1094		p = (u_short)ip->ip_p;
1095		s = (u_32_t *)&ip->ip_src;
1096		d = (u_32_t *)&ip->ip_dst;
1097		plen = ip->ip_len;
1098	} else {
1099		goto printipflog;
1100	}
1101	proto = getproto(p);
1102
1103	if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) {
1104		tp = (tcphdr_t *)((char *)ip + hl);
1105		if (!(ipf->fl_lflags & FI_SHORT)) {
1106			(void) sprintf(t, "%s,%s -> ", hostname(res, v, s),
1107				portname(res, proto, (u_int)tp->th_sport));
1108			t += strlen(t);
1109			(void) sprintf(t, "%s,%s PR %s len %hu %hu",
1110				hostname(res, v, d),
1111				portname(res, proto, (u_int)tp->th_dport),
1112				proto, hl, plen);
1113			t += strlen(t);
1114
1115			if (p == IPPROTO_TCP) {
1116				*t++ = ' ';
1117				*t++ = '-';
1118				for (i = 0; tcpfl[i].value; i++)
1119					if (tp->th_flags & tcpfl[i].value)
1120						*t++ = tcpfl[i].flag;
1121				if (opts & OPT_VERBOSE) {
1122					(void) sprintf(t, " %lu %lu %hu",
1123						(u_long)(ntohl(tp->th_seq)),
1124						(u_long)(ntohl(tp->th_ack)),
1125						ntohs(tp->th_win));
1126					t += strlen(t);
1127				}
1128			}
1129			*t = '\0';
1130		} else {
1131			(void) sprintf(t, "%s -> ", hostname(res, v, s));
1132			t += strlen(t);
1133			(void) sprintf(t, "%s PR %s len %hu %hu",
1134				hostname(res, v, d), proto, hl, plen);
1135		}
1136	} else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) {
1137		ic = (struct icmp *)((char *)ip + hl);
1138		(void) sprintf(t, "%s -> ", hostname(res, v, s));
1139		t += strlen(t);
1140		(void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s",
1141			hostname(res, v, d), hl, plen,
1142			icmpname6(ic->icmp_type, ic->icmp_code));
1143	} else if ((p == IPPROTO_ICMP) && !off && (v == 4)) {
1144		ic = (struct icmp *)((char *)ip + hl);
1145		(void) sprintf(t, "%s -> ", hostname(res, v, s));
1146		t += strlen(t);
1147		(void) sprintf(t, "%s PR icmp len %hu %hu icmp %s",
1148			hostname(res, v, d), hl, plen,
1149			icmpname(ic->icmp_type, ic->icmp_code));
1150		if (ic->icmp_type == ICMP_UNREACH ||
1151		    ic->icmp_type == ICMP_SOURCEQUENCH ||
1152		    ic->icmp_type == ICMP_PARAMPROB ||
1153		    ic->icmp_type == ICMP_REDIRECT ||
1154		    ic->icmp_type == ICMP_TIMXCEED) {
1155			ipc = &ic->icmp_ip;
1156			i = ntohs(ipc->ip_len);
1157			/*
1158			 * XXX - try to guess endian of ip_len in ICMP
1159			 * returned data.
1160			 */
1161			if (i > 1500)
1162				i = ipc->ip_len;
1163			ipoff = ntohs(ipc->ip_off);
1164			proto = getproto(ipc->ip_p);
1165
1166			if (!(ipoff & IP_OFFMASK) &&
1167			    ((ipc->ip_p == IPPROTO_TCP) ||
1168			     (ipc->ip_p == IPPROTO_UDP))) {
1169				tp = (tcphdr_t *)((char *)ipc + hl);
1170				t += strlen(t);
1171				(void) sprintf(t, " for %s,%s -",
1172					HOSTNAME_V4(res, ipc->ip_src),
1173					portname(res, proto,
1174						 (u_int)tp->th_sport));
1175				t += strlen(t);
1176				(void) sprintf(t, " %s,%s PR %s len %hu %hu",
1177					HOSTNAME_V4(res, ipc->ip_dst),
1178					portname(res, proto,
1179						 (u_int)tp->th_dport),
1180					proto, IP_HL(ipc) << 2, i);
1181			} else if (!(ipoff & IP_OFFMASK) &&
1182				   (ipc->ip_p == IPPROTO_ICMP)) {
1183				icmp = (icmphdr_t *)((char *)ipc + hl);
1184
1185				t += strlen(t);
1186				(void) sprintf(t, " for %s -",
1187					HOSTNAME_V4(res, ipc->ip_src));
1188				t += strlen(t);
1189				(void) sprintf(t,
1190					" %s PR icmp len %hu %hu icmp %d/%d",
1191					HOSTNAME_V4(res, ipc->ip_dst),
1192					IP_HL(ipc) << 2, i,
1193					icmp->icmp_type, icmp->icmp_code);
1194			} else {
1195				t += strlen(t);
1196				(void) sprintf(t, " for %s -",
1197						HOSTNAME_V4(res, ipc->ip_src));
1198				t += strlen(t);
1199				(void) sprintf(t, " %s PR %s len %hu (%hu)",
1200					HOSTNAME_V4(res, ipc->ip_dst), proto,
1201					IP_HL(ipc) << 2, i);
1202				t += strlen(t);
1203				if (ipoff & IP_OFFMASK) {
1204					(void) sprintf(t,
1205						"(frag %d:%hu@%hu%s%s)",
1206						ntohs(ipc->ip_id),
1207						i - (IP_HL(ipc) << 2),
1208						(ipoff & IP_OFFMASK) << 3,
1209						ipoff & IP_MF ? "+" : "",
1210						ipoff & IP_DF ? "-" : "");
1211				}
1212			}
1213
1214		}
1215	} else {
1216		(void) sprintf(t, "%s -> ", hostname(res, v, s));
1217		t += strlen(t);
1218		(void) sprintf(t, "%s PR %s len %hu (%hu)",
1219			hostname(res, v, d), proto, hl, plen);
1220		t += strlen(t);
1221		if (off & IP_OFFMASK)
1222			(void) sprintf(t, " (frag %d:%hu@%hu%s%s)",
1223				ntohs(ip->ip_id),
1224				plen - hl, (off & IP_OFFMASK) << 3,
1225				ipoff & IP_MF ? "+" : "",
1226				ipoff & IP_DF ? "-" : "");
1227	}
1228	t += strlen(t);
1229
1230printipflog:
1231	if (ipf->fl_flags & FR_KEEPSTATE) {
1232		(void) strcpy(t, " K-S");
1233		t += strlen(t);
1234	}
1235
1236	if (ipf->fl_flags & FR_KEEPFRAG) {
1237		(void) strcpy(t, " K-F");
1238		t += strlen(t);
1239	}
1240
1241	if (ipf->fl_dir == 0)
1242		strcpy(t, " IN");
1243	else if (ipf->fl_dir == 1)
1244		strcpy(t, " OUT");
1245	t += strlen(t);
1246	if (ipf->fl_logtag != 0) {
1247		sprintf(t, " log-tag %d", ipf->fl_logtag);
1248		t += strlen(t);
1249	}
1250	if (ipf->fl_nattag.ipt_num[0] != 0) {
1251		strcpy(t, " nat-tag ");
1252		t += strlen(t);
1253		strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag));
1254		t += strlen(t);
1255	}
1256	if ((ipf->fl_lflags & FI_LOWTTL) != 0) {
1257			strcpy(t, " low-ttl");
1258			t += 8;
1259	}
1260	if ((ipf->fl_lflags & FI_OOW) != 0) {
1261			strcpy(t, " OOW");
1262			t += 4;
1263	}
1264	if ((ipf->fl_lflags & FI_BAD) != 0) {
1265			strcpy(t, " bad");
1266			t += 4;
1267	}
1268	if ((ipf->fl_lflags & FI_NATED) != 0) {
1269			strcpy(t, " NAT");
1270			t += 4;
1271	}
1272	if ((ipf->fl_lflags & FI_BADNAT) != 0) {
1273			strcpy(t, " bad-NAT");
1274			t += 8;
1275	}
1276	if ((ipf->fl_lflags & FI_BADSRC) != 0) {
1277			strcpy(t, " bad-src");
1278			t += 8;
1279	}
1280	if ((ipf->fl_lflags & FI_MULTICAST) != 0) {
1281			strcpy(t, " multicast");
1282			t += 10;
1283	}
1284	if ((ipf->fl_lflags & FI_BROADCAST) != 0) {
1285			strcpy(t, " broadcast");
1286			t += 10;
1287	}
1288	if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) ==
1289	    FI_MBCAST) {
1290			strcpy(t, " mbcast");
1291			t += 7;
1292	}
1293	*t++ = '\n';
1294	*t++ = '\0';
1295	defaction = 0;
1296	if (conf_file != NULL)
1297		defaction = check_action(buf, line, opts, lvl);
1298	if (defaction == 0) {
1299		if (opts & OPT_SYSLOG)
1300			syslog(lvl, "%s", line);
1301		else
1302			(void) fprintf(log, "%s", line);
1303		if (opts & OPT_HEXHDR)
1304			dumphex(log, opts, buf,
1305				sizeof(iplog_t) + sizeof(*ipf));
1306		if (opts & OPT_HEXBODY)
1307			dumphex(log, opts, (char *)ip,
1308				ipf->fl_plen + ipf->fl_hlen);
1309		else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY))
1310			dumphex(log, opts, (char *)ip + ipf->fl_hlen,
1311				ipf->fl_plen);
1312	}
1313}
1314
1315
1316static void usage(prog)
1317char *prog;
1318{
1319	fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog);
1320	exit(1);
1321}
1322
1323
1324static void write_pid(file)
1325char *file;
1326{
1327	FILE *fp = NULL;
1328	int fd;
1329
1330	if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) {
1331		fp = fdopen(fd, "w");
1332		if (fp == NULL) {
1333			close(fd);
1334			fprintf(stderr,
1335				"unable to open/create pid file: %s\n", file);
1336			return;
1337		}
1338		fprintf(fp, "%d", getpid());
1339		fclose(fp);
1340	}
1341}
1342
1343
1344static void flushlogs(file, log)
1345char *file;
1346FILE *log;
1347{
1348	int	fd, flushed = 0;
1349
1350	if ((fd = open(file, O_RDWR)) == -1) {
1351		(void) fprintf(stderr, "%s: open: %s\n",
1352			       file, STRERROR(errno));
1353		exit(1);
1354	}
1355
1356	if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
1357		printf("%d bytes flushed from log buffer\n",
1358			flushed);
1359		fflush(stdout);
1360	} else
1361		perror("SIOCIPFFB");
1362	(void) close(fd);
1363
1364	if (flushed) {
1365		if (opts & OPT_SYSLOG)
1366			syslog(LOG_INFO, "%d bytes flushed from log\n",
1367				flushed);
1368		else if (log != stdout)
1369			fprintf(log, "%d bytes flushed from log\n", flushed);
1370	}
1371}
1372
1373
1374static void logopts(turnon, options)
1375int turnon;
1376char *options;
1377{
1378	int flags = 0;
1379	char *s;
1380
1381	for (s = options; *s; s++)
1382	{
1383		switch (*s)
1384		{
1385		case 'N' :
1386			flags |= OPT_NAT;
1387			break;
1388		case 'S' :
1389			flags |= OPT_STATE;
1390			break;
1391		case 'I' :
1392			flags |= OPT_FILTER;
1393			break;
1394		default :
1395			fprintf(stderr, "Unknown log option %c\n", *s);
1396			exit(1);
1397		}
1398	}
1399
1400	if (turnon)
1401		opts |= flags;
1402	else
1403		opts &= ~(flags);
1404}
1405
1406
1407int main(argc, argv)
1408int argc;
1409char *argv[];
1410{
1411	struct	stat	sb;
1412	FILE	*log = stdout;
1413	FILE	*fp;
1414	int	fd[3], doread, n, i;
1415	int	tr, nr, regular[3], c;
1416	int	fdt[3], devices = 0, make_daemon = 0;
1417	char	buf[DEFAULT_IPFLOGSIZE], *iplfile[3], *s;
1418	extern	int	optind;
1419	extern	char	*optarg;
1420
1421	fd[0] = fd[1] = fd[2] = -1;
1422	fdt[0] = fdt[1] = fdt[2] = -1;
1423	iplfile[0] = IPL_NAME;
1424	iplfile[1] = IPNAT_NAME;
1425	iplfile[2] = IPSTATE_NAME;
1426
1427	while ((c = getopt(argc, argv, "?abB:C:Df:FhnN:o:O:pP:sS:tvxX")) != -1)
1428		switch (c)
1429		{
1430		case 'a' :
1431			opts |= OPT_LOGALL;
1432			fdt[0] = IPL_LOGIPF;
1433			fdt[1] = IPL_LOGNAT;
1434			fdt[2] = IPL_LOGSTATE;
1435			break;
1436		case 'b' :
1437			opts |= OPT_LOGBODY;
1438			break;
1439		case 'B' :
1440			binarylogfile = optarg;
1441			binarylog = fopen(optarg, "a");
1442			break;
1443		case 'C' :
1444			conf_file = optarg;
1445			break;
1446		case 'D' :
1447			make_daemon = 1;
1448			break;
1449		case 'f' : case 'I' :
1450			opts |= OPT_FILTER;
1451			fdt[0] = IPL_LOGIPF;
1452			iplfile[0] = optarg;
1453			break;
1454		case 'F' :
1455			flushlogs(iplfile[0], log);
1456			flushlogs(iplfile[1], log);
1457			flushlogs(iplfile[2], log);
1458			break;
1459		case 'n' :
1460			opts |= OPT_RESOLVE;
1461			break;
1462		case 'N' :
1463			opts |= OPT_NAT;
1464			fdt[1] = IPL_LOGNAT;
1465			iplfile[1] = optarg;
1466			break;
1467		case 'o' : case 'O' :
1468			logopts(c == 'o', optarg);
1469			fdt[0] = fdt[1] = fdt[2] = -1;
1470			if (opts & OPT_FILTER)
1471				fdt[0] = IPL_LOGIPF;
1472			if (opts & OPT_NAT)
1473				fdt[1] = IPL_LOGNAT;
1474			if (opts & OPT_STATE)
1475				fdt[2] = IPL_LOGSTATE;
1476			break;
1477		case 'p' :
1478			opts |= OPT_PORTNUM;
1479			break;
1480		case 'P' :
1481			pidfile = optarg;
1482			break;
1483		case 's' :
1484			s = strrchr(argv[0], '/');
1485			if (s == NULL)
1486				s = argv[0];
1487			else
1488				s++;
1489			openlog(s, LOG_NDELAY|LOG_PID, LOGFAC);
1490			s = NULL;
1491			opts |= OPT_SYSLOG;
1492			log = NULL;
1493			break;
1494		case 'S' :
1495			opts |= OPT_STATE;
1496			fdt[2] = IPL_LOGSTATE;
1497			iplfile[2] = optarg;
1498			break;
1499		case 't' :
1500			opts |= OPT_TAIL;
1501			break;
1502		case 'v' :
1503			opts |= OPT_VERBOSE;
1504			break;
1505		case 'x' :
1506			opts |= OPT_HEXBODY;
1507			break;
1508		case 'X' :
1509			opts |= OPT_HEXHDR;
1510			break;
1511		default :
1512		case 'h' :
1513		case '?' :
1514			usage(argv[0]);
1515		}
1516
1517	init_tabs();
1518	if (conf_file)
1519		if (load_config(conf_file) == -1)
1520			exit(1);
1521
1522	/*
1523	 * Default action is to only open the filter log file.
1524	 */
1525	if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1))
1526		fdt[0] = IPL_LOGIPF;
1527
1528	for (i = 0; i < 3; i++) {
1529		if (fdt[i] == -1)
1530			continue;
1531		if (!strcmp(iplfile[i], "-"))
1532			fd[i] = 0;
1533		else {
1534			if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) {
1535				(void) fprintf(stderr,
1536					       "%s: open: %s\n", iplfile[i],
1537					       STRERROR(errno));
1538				exit(1);
1539				/* NOTREACHED */
1540			}
1541			if (fstat(fd[i], &sb) == -1) {
1542				(void) fprintf(stderr, "%d: fstat: %s\n",
1543					       fd[i], STRERROR(errno));
1544				exit(1);
1545				/* NOTREACHED */
1546			}
1547			if (!(regular[i] = !S_ISCHR(sb.st_mode)))
1548				devices++;
1549		}
1550	}
1551
1552	if (!(opts & OPT_SYSLOG)) {
1553		logfile = argv[optind];
1554		log = logfile ? fopen(logfile, "a") : stdout;
1555		if (log == NULL) {
1556			(void) fprintf(stderr, "%s: fopen: %s\n",
1557				       argv[optind], STRERROR(errno));
1558			exit(1);
1559			/* NOTREACHED */
1560		}
1561		setvbuf(log, NULL, _IONBF, 0);
1562	} else
1563		log = NULL;
1564
1565	if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) {
1566#if BSD >= 199306
1567		daemon(0, !(opts & OPT_SYSLOG));
1568#else
1569		int pid;
1570		if ((pid = fork()) > 0)
1571			exit(0);
1572		if (pid < 0) {
1573			(void) fprintf(stderr, "%s: fork() failed: %s\n",
1574				       argv[0], STRERROR(errno));
1575			exit(1);
1576			/* NOTREACHED */
1577		}
1578		setsid();
1579		if ((opts & OPT_SYSLOG))
1580			close(2);
1581#endif /* !BSD */
1582		close(0);
1583		close(1);
1584	}
1585	write_pid(pidfile);
1586
1587	signal(SIGHUP, handlehup);
1588
1589	for (doread = 1; doread; ) {
1590		nr = 0;
1591
1592		for (i = 0; i < 3; i++) {
1593			tr = 0;
1594			if (fdt[i] == -1)
1595				continue;
1596			if (!regular[i]) {
1597				if (ioctl(fd[i], FIONREAD, &tr) == -1) {
1598					if (opts & OPT_SYSLOG)
1599						syslog(LOG_CRIT,
1600						       "ioctl(FIONREAD): %m");
1601					else
1602						perror("ioctl(FIONREAD)");
1603					exit(1);
1604					/* NOTREACHED */
1605				}
1606			} else {
1607				tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size);
1608				if (!tr && !(opts & OPT_TAIL))
1609					doread = 0;
1610			}
1611			if (!tr)
1612				continue;
1613			nr += tr;
1614
1615			tr = read_log(fd[i], &n, buf, sizeof(buf));
1616			if (donehup) {
1617				if (logfile && (fp = fopen(logfile, "a"))) {
1618					fclose(log);
1619					log = fp;
1620				}
1621				if (binarylogfile && (fp = fopen(binarylogfile, "a"))) {
1622					fclose(binarylog);
1623					binarylog = fp;
1624				}
1625				init_tabs();
1626				if (conf_file != NULL)
1627					load_config(conf_file);
1628				donehup = 0;
1629			}
1630
1631			switch (tr)
1632			{
1633			case -1 :
1634				if (opts & OPT_SYSLOG)
1635					syslog(LOG_CRIT, "read: %m\n");
1636				else
1637					perror("read");
1638				doread = 0;
1639				break;
1640			case 1 :
1641				if (opts & OPT_SYSLOG)
1642					syslog(LOG_CRIT, "aborting logging\n");
1643				else
1644					fprintf(log, "aborting logging\n");
1645				doread = 0;
1646				break;
1647			case 2 :
1648				break;
1649			case 0 :
1650				if (n > 0) {
1651					print_log(fdt[i], log, buf, n);
1652					if (!(opts & OPT_SYSLOG))
1653						fflush(log);
1654				}
1655				break;
1656			}
1657		}
1658		if (!nr && ((opts & OPT_TAIL) || devices))
1659			sleep(1);
1660	}
1661	return(0);
1662	/* NOTREACHED */
1663}
1664