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