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