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