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