1/*	$NetBSD: ipf.c,v 1.6 2012/02/15 17:55:10 riz Exp $	*/
2
3/*
4 * Copyright (C) 2001-2006 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#ifdef	__FreeBSD__
9# ifndef __FreeBSD_cc_version
10#  include <osreldate.h>
11# else
12#  if __FreeBSD_cc_version < 430000
13#   include <osreldate.h>
14#  endif
15# endif
16#endif
17#include "ipf.h"
18#include <fcntl.h>
19#include <sys/ioctl.h>
20#include "netinet/ipl.h"
21
22#if !defined(lint)
23static const char sccsid[] = "@(#)ipf.c	1.23 6/5/96 (C) 1993-2000 Darren Reed";
24static const char rcsid[] = "@(#)Id: ipf.c,v 1.35.2.8 2007/05/10 06:12:01 darrenr Exp";
25#endif
26
27#if !defined(__SVR4) && defined(__GNUC__)
28extern	char	*index __P((const char *, int));
29#endif
30
31extern	char	*optarg;
32extern	int	optind;
33extern	frentry_t *frtop;
34
35
36void	ipf_frsync __P((void));
37void	zerostats __P((void));
38int	main __P((int, char *[]));
39
40int	opts = 0;
41int	outputc = 0;
42int	use_inet6 = 0;
43
44static	void	procfile __P((char *, char *)), flushfilter __P((char *));
45static	void	set_state __P((u_int)), showstats __P((friostat_t *));
46static	void	packetlogon __P((char *)), swapactive __P((void));
47static	int	opendevice __P((char *, int));
48static	void	closedevice __P((void));
49static	char	*ipfname = IPL_NAME;
50static	void	usage __P((void));
51static	int	showversion __P((void));
52static	int	get_flags __P((void));
53static	void	ipf_interceptadd __P((int, ioctlfunc_t, void *));
54
55static	int	fd = -1;
56static	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
57						      ioctl, ioctl, ioctl,
58						      ioctl, ioctl };
59
60
61static void usage()
62{
63	fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
64		"[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
65		"[-f filename] [-T <tuneopts>]");
66	exit(1);
67}
68
69
70int main(argc,argv)
71int argc;
72char *argv[];
73{
74	int c;
75
76	if (argc < 2)
77		usage();
78
79	while ((c = getopt(argc, argv, "6Ac:dDEf:F:Il:noPrRsT:vVyzZ")) != -1) {
80		switch (c)
81		{
82		case '?' :
83			usage();
84			break;
85#ifdef	USE_INET6
86		case '6' :
87			use_inet6 = 1;
88			break;
89#endif
90		case 'A' :
91			opts &= ~OPT_INACTIVE;
92			break;
93		case 'c' :
94			if (strcmp(optarg, "c") == 0)
95				outputc = 1;
96			break;
97		case 'E' :
98			set_state((u_int)1);
99			break;
100		case 'D' :
101			set_state((u_int)0);
102			break;
103		case 'd' :
104			opts ^= OPT_DEBUG;
105			break;
106		case 'f' :
107			procfile(argv[0], optarg);
108			break;
109		case 'F' :
110			flushfilter(optarg);
111			break;
112		case 'I' :
113			opts ^= OPT_INACTIVE;
114			break;
115		case 'l' :
116			packetlogon(optarg);
117			break;
118		case 'n' :
119			opts ^= OPT_DONOTHING;
120			break;
121		case 'o' :
122			break;
123		case 'P' :
124			ipfname = IPAUTH_NAME;
125			break;
126		case 'R' :
127			opts ^= OPT_NORESOLVE;
128			break;
129		case 'r' :
130			opts ^= OPT_REMOVE;
131			break;
132		case 's' :
133			swapactive();
134			break;
135		case 'T' :
136			if (opendevice(ipfname, 1) >= 0)
137				ipf_dotuning(fd, optarg, ioctl);
138			break;
139		case 'v' :
140			opts += OPT_VERBOSE;
141			break;
142		case 'V' :
143			if (showversion())
144				exit(1);
145			break;
146		case 'y' :
147			ipf_frsync();
148			break;
149		case 'z' :
150			opts ^= OPT_ZERORULEST;
151			break;
152		case 'Z' :
153			zerostats();
154			break;
155		}
156	}
157
158	if (optind < 2)
159		usage();
160
161	if (fd != -1)
162		(void) close(fd);
163
164	return(0);
165	/* NOTREACHED */
166}
167
168
169static int opendevice(ipfdev, check)
170char *ipfdev;
171int check;
172{
173	if (opts & OPT_DONOTHING)
174		return -2;
175
176	if (check && checkrev(ipfname) == -1) {
177		fprintf(stderr, "User/kernel version check failed\n");
178		return -2;
179	}
180
181	if (!ipfdev)
182		ipfdev = ipfname;
183
184	if (fd == -1)
185		if ((fd = open(ipfdev, O_RDWR)) == -1)
186			if ((fd = open(ipfdev, O_RDONLY)) == -1)
187				perror("open device");
188	return fd;
189}
190
191
192static void closedevice()
193{
194	close(fd);
195	fd = -1;
196}
197
198
199static	int	get_flags()
200{
201	int i = 0;
202
203	if ((opendevice(ipfname, 1) != -2) &&
204	    (ioctl(fd, SIOCGETFF, &i) == -1)) {
205		perror("SIOCGETFF");
206		return 0;
207	}
208	return i;
209}
210
211
212static	void	set_state(enable)
213u_int	enable;
214{
215	if (opendevice(ipfname, 0) != -2)
216		if (ioctl(fd, SIOCFRENB, &enable) == -1) {
217			if (errno == EBUSY)
218				fprintf(stderr,
219					"IP FIlter: already initialized\n");
220			else
221				perror("SIOCFRENB");
222		}
223	return;
224}
225
226
227static	void	procfile(name, file)
228char	*name, *file;
229{
230	(void) opendevice(ipfname, 1);
231
232	initparse();
233
234	ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
235
236	if (outputc) {
237		printC(0);
238		printC(1);
239		emit(-1, -1, NULL, NULL);
240	}
241}
242
243
244static void ipf_interceptadd(fd, ioctlfunc, ptr)
245int fd;
246ioctlfunc_t ioctlfunc;
247void *ptr;
248{
249	if (outputc)
250		printc(ptr);
251
252	ipf_addrule(fd, ioctlfunc, ptr);
253}
254
255
256static void packetlogon(opt)
257char	*opt;
258{
259	int	flag, xfd, logopt, change = 0;
260
261	flag = get_flags();
262	if (flag != 0) {
263		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
264			printf("log flag is currently %#x\n", flag);
265	}
266
267	flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
268
269	if (strstr(opt, "pass")) {
270		flag |= FF_LOGPASS;
271		if (opts & OPT_VERBOSE)
272			printf("set log flag: pass\n");
273		change = 1;
274	}
275	if (strstr(opt, "nomatch")) {
276		flag |= FF_LOGNOMATCH;
277		if (opts & OPT_VERBOSE)
278			printf("set log flag: nomatch\n");
279		change = 1;
280	}
281	if (strstr(opt, "block") || index(opt, 'd')) {
282		flag |= FF_LOGBLOCK;
283		if (opts & OPT_VERBOSE)
284			printf("set log flag: block\n");
285		change = 1;
286	}
287	if (strstr(opt, "none")) {
288		if (opts & OPT_VERBOSE)
289			printf("disable all log flags\n");
290		change = 1;
291	}
292
293	if (change == 1) {
294		if (opendevice(ipfname, 1) != -2 &&
295		    (ioctl(fd, SIOCSETFF, &flag) != 0))
296			perror("ioctl(SIOCSETFF)");
297	}
298
299	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
300		flag = get_flags();
301		printf("log flags are now %#x\n", flag);
302	}
303
304	if (strstr(opt, "state")) {
305		if (opts & OPT_VERBOSE)
306			printf("set state log flag\n");
307		xfd = open(IPSTATE_NAME, O_RDWR);
308		if (xfd >= 0) {
309			logopt = 0;
310			if (ioctl(xfd, SIOCGETLG, &logopt))
311				perror("ioctl(SIOCGETLG)");
312			else {
313				logopt = 1 - logopt;
314				if (ioctl(xfd, SIOCSETLG, &logopt))
315					perror("ioctl(SIOCSETLG)");
316			}
317			close(xfd);
318		}
319	}
320
321	if (strstr(opt, "nat")) {
322		if (opts & OPT_VERBOSE)
323			printf("set nat log flag\n");
324		xfd = open(IPNAT_NAME, O_RDWR);
325		if (xfd >= 0) {
326			logopt = 0;
327			if (ioctl(xfd, SIOCGETLG, &logopt))
328				perror("ioctl(SIOCGETLG)");
329			else {
330				logopt = 1 - logopt;
331				if (ioctl(xfd, SIOCSETLG, &logopt))
332					perror("ioctl(SIOCSETLG)");
333			}
334			close(xfd);
335		}
336	}
337}
338
339
340static	void	flushfilter(arg)
341char	*arg;
342{
343	int	fl = 0, rem;
344
345	if (!arg || !*arg)
346		return;
347	if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
348		if (*arg == 'S')
349			fl = 0;
350		else if (*arg == 's')
351			fl = 1;
352		else
353			fl = atoi(arg);
354		rem = fl;
355
356		closedevice();
357		if (opendevice(IPSTATE_NAME, 1) == -2)
358			exit(1);
359
360		if (!(opts & OPT_DONOTHING)) {
361			if (use_inet6) {
362				if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
363					perror("ioctl(SIOCIPFL6)");
364					exit(1);
365				}
366			} else {
367				if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
368					perror("ioctl(SIOCIPFFL)");
369					exit(1);
370				}
371			}
372		}
373		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
374			printf("remove flags %s (%d)\n", arg, rem);
375			printf("removed %d entries\n", fl);
376		}
377		closedevice();
378		return;
379	}
380
381#ifdef	SIOCIPFFA
382	if (!strcmp(arg, "u")) {
383		closedevice();
384		/*
385		 * Flush auth rules and packets
386		 */
387		if (opendevice(IPL_AUTH, 1) == -1)
388			perror("open(IPL_AUTH)");
389		else {
390			if (ioctl(fd, SIOCIPFFA, &fl) == -1)
391				perror("ioctl(SIOCIPFFA)");
392		}
393		closedevice();
394		return;
395	}
396#endif
397
398	if (strchr(arg, 'i') || strchr(arg, 'I'))
399		fl = FR_INQUE;
400	if (strchr(arg, 'o') || strchr(arg, 'O'))
401		fl = FR_OUTQUE;
402	if (strchr(arg, 'a') || strchr(arg, 'A'))
403		fl = FR_OUTQUE|FR_INQUE;
404	if (opts & OPT_INACTIVE)
405		fl |= FR_INACTIVE;
406	rem = fl;
407
408	if (opendevice(ipfname, 1) == -2)
409		exit(1);
410
411	if (!(opts & OPT_DONOTHING)) {
412		if (use_inet6) {
413			if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
414				perror("ioctl(SIOCIPFL6)");
415				exit(1);
416			}
417		} else {
418			if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
419				perror("ioctl(SIOCIPFFL)");
420				exit(1);
421			}
422		}
423	}
424
425	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
426		printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
427			(rem & FR_OUTQUE) ? "O" : "", rem);
428		printf("removed %d filter rules\n", fl);
429	}
430	return;
431}
432
433
434static void swapactive()
435{
436	int in = 2;
437
438	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
439		perror("ioctl(SIOCSWAPA)");
440	else
441		printf("Set %d now inactive\n", in);
442}
443
444
445void ipf_frsync()
446{
447	int frsyn = 0;
448
449	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
450		perror("SIOCFRSYN");
451	else
452		printf("filter sync'd\n");
453}
454
455
456void zerostats()
457{
458	ipfobj_t	obj;
459	friostat_t	fio;
460
461	obj.ipfo_rev = IPFILTER_VERSION;
462	obj.ipfo_type = IPFOBJ_IPFSTAT;
463	obj.ipfo_size = sizeof(fio);
464	obj.ipfo_ptr = &fio;
465	obj.ipfo_offset = 0;
466
467	if (opendevice(ipfname, 1) != -2) {
468		if (ioctl(fd, SIOCFRZST, &obj) == -1) {
469			perror("ioctl(SIOCFRZST)");
470			exit(-1);
471		}
472		showstats(&fio);
473	}
474
475}
476
477
478/*
479 * read the kernel stats for packets blocked and passed
480 */
481static void showstats(fp)
482friostat_t	*fp;
483{
484	printf("bad packets:\t\tin %lu\tout %lu\n",
485			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
486	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
487			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
488			fp->f_st[0].fr_nom);
489	printf(" counted %lu\n", fp->f_st[0].fr_acct);
490	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
491			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
492			fp->f_st[1].fr_nom);
493	printf(" counted %lu\n", fp->f_st[0].fr_acct);
494	printf(" input packets logged:\tblocked %lu passed %lu\n",
495			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
496	printf("output packets logged:\tblocked %lu passed %lu\n",
497			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
498	printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
499			fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
500			fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
501}
502
503
504static int showversion()
505{
506	struct friostat fio;
507	ipfobj_t ipfo;
508	u_32_t flags;
509	char *s;
510	int vfd;
511
512	bzero((caddr_t)&ipfo, sizeof(ipfo));
513	ipfo.ipfo_rev = IPFILTER_VERSION;
514	ipfo.ipfo_size = sizeof(fio);
515	ipfo.ipfo_ptr = (void *)&fio;
516	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
517
518	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
519
520	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
521		perror("open device");
522		return 1;
523	}
524
525	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
526		perror("ioctl(SIOCGETFS)");
527		close(vfd);
528		return 1;
529	}
530	close(vfd);
531	flags = get_flags();
532
533	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
534		(int)sizeof(fio.f_version), fio.f_version);
535	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
536	printf("Log Flags: %#x = ", flags);
537	s = "";
538	if (flags & FF_LOGPASS) {
539		printf("pass");
540		s = ", ";
541	}
542	if (flags & FF_LOGBLOCK) {
543		printf("%sblock", s);
544		s = ", ";
545	}
546	if (flags & FF_LOGNOMATCH) {
547		printf("%snomatch", s);
548		s = ", ";
549	}
550	if (flags & FF_BLOCKNONIP) {
551		printf("%snonip", s);
552		s = ", ";
553	}
554	if (!*s)
555		printf("none set");
556	putchar('\n');
557
558	printf("Default: ");
559	if (FR_ISPASS(fio.f_defpass))
560		s = "pass";
561	else if (FR_ISBLOCK(fio.f_defpass))
562		s = "block";
563	else
564		s = "nomatch -> block";
565	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
566	printf("Active list: %d\n", fio.f_active);
567	printf("Feature mask: %#x\n", fio.f_features);
568
569	return 0;
570}
571