ipf.c revision 157836
1239310Sdim/*	$FreeBSD: head/contrib/ipfilter/tools/ipf.c 157836 2006-04-18 13:24:14Z darrenr $	*/
2239310Sdim
3239310Sdim/*
4239310Sdim * Copyright (C) 1993-2001 by Darren Reed.
5239310Sdim *
6239310Sdim * See the IPFILTER.LICENCE file for details on licencing.
7239310Sdim */
8239310Sdim#ifdef	__FreeBSD__
9239310Sdim# ifndef __FreeBSD_cc_version
10239310Sdim#  include <osreldate.h>
11239310Sdim# else
12239310Sdim#  if __FreeBSD_cc_version < 430000
13239310Sdim#   include <osreldate.h>
14239310Sdim#  endif
15239310Sdim# endif
16239310Sdim#endif
17239310Sdim#include "ipf.h"
18239310Sdim#include <fcntl.h>
19249423Sdim#include <sys/ioctl.h>
20239310Sdim#include "netinet/ipl.h"
21249423Sdim
22249423Sdim#if !defined(lint)
23239310Sdimstatic const char sccsid[] = "@(#)ipf.c	1.23 6/5/96 (C) 1993-2000 Darren Reed";
24249423Sdimstatic const char rcsid[] = "@(#)$Id: ipf.c,v 1.35.2.3 2004/12/15 18:27:17 darrenr Exp $";
25239310Sdim#endif
26239310Sdim
27239310Sdim#if !defined(__SVR4) && defined(__GNUC__)
28249423Sdimextern	char	*index __P((const char *, int));
29239310Sdim#endif
30239310Sdim
31249423Sdimextern	char	*optarg;
32239310Sdimextern	int	optind;
33239310Sdimextern	frentry_t *frtop;
34239310Sdim
35239310Sdim
36239310Sdimvoid	ipf_frsync __P((void));
37239310Sdimvoid	zerostats __P((void));
38239310Sdimint	main __P((int, char *[]));
39239310Sdim
40239310Sdimint	opts = 0;
41239310Sdimint	outputc = 0;
42239310Sdimint	use_inet6 = 0;
43239310Sdim
44239310Sdimstatic	void	procfile __P((char *, char *)), flushfilter __P((char *));
45239310Sdimstatic	void	set_state __P((u_int)), showstats __P((friostat_t *));
46249423Sdimstatic	void	packetlogon __P((char *)), swapactive __P((void));
47249423Sdimstatic	int	opendevice __P((char *, int));
48239310Sdimstatic	void	closedevice __P((void));
49239310Sdimstatic	char	*ipfname = IPL_NAME;
50239310Sdimstatic	void	usage __P((void));
51239310Sdimstatic	int	showversion __P((void));
52239310Sdimstatic	int	get_flags __P((void));
53239310Sdimstatic	void	ipf_interceptadd __P((int, ioctlfunc_t, void *));
54249423Sdim
55239310Sdimstatic	int	fd = -1;
56239310Sdimstatic	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
57239310Sdim						      ioctl, ioctl, ioctl,
58239310Sdim						      ioctl, ioctl };
59239310Sdim
60239310Sdim
61239310Sdimstatic void usage()
62239310Sdim{
63239310Sdim	fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
64239310Sdim		"[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
65239310Sdim		"[-f filename] [-T <tuneopts>]");
66249423Sdim	exit(1);
67239310Sdim}
68239310Sdim
69239310Sdim
70239310Sdimint main(argc,argv)
71239310Sdimint argc;
72239310Sdimchar *argv[];
73239310Sdim{
74239310Sdim	int c;
75239310Sdim
76239310Sdim	if (argc < 2)
77239310Sdim		usage();
78239310Sdim
79239310Sdim	while ((c = getopt(argc, argv, "6Ac:dDEf:F:Il:noPrRsT:vVyzZ")) != -1) {
80239310Sdim		switch (c)
81239310Sdim		{
82239310Sdim		case '?' :
83239310Sdim			usage();
84239310Sdim			break;
85239310Sdim#ifdef	USE_INET6
86239310Sdim		case '6' :
87239310Sdim			use_inet6 = 1;
88239310Sdim			break;
89239310Sdim#endif
90249423Sdim		case 'A' :
91239310Sdim			opts &= ~OPT_INACTIVE;
92239310Sdim			break;
93239310Sdim		case 'c' :
94251662Sdim			if (strcmp(optarg, "c") == 0)
95239310Sdim				outputc = 1;
96239310Sdim			break;
97239310Sdim		case 'E' :
98239310Sdim			set_state((u_int)1);
99239310Sdim			break;
100239310Sdim		case 'D' :
101239310Sdim			set_state((u_int)0);
102239310Sdim			break;
103249423Sdim		case 'd' :
104239310Sdim			opts ^= OPT_DEBUG;
105239310Sdim			break;
106239310Sdim		case 'f' :
107239310Sdim			procfile(argv[0], optarg);
108239310Sdim			break;
109249423Sdim		case 'F' :
110239310Sdim			flushfilter(optarg);
111249423Sdim			break;
112249423Sdim		case 'I' :
113249423Sdim			opts ^= OPT_INACTIVE;
114239310Sdim			break;
115249423Sdim		case 'l' :
116239310Sdim			packetlogon(optarg);
117249423Sdim			break;
118239310Sdim		case 'n' :
119249423Sdim			opts ^= OPT_DONOTHING;
120239310Sdim			break;
121239310Sdim		case 'o' :
122239310Sdim			break;
123239310Sdim		case 'P' :
124249423Sdim			ipfname = IPAUTH_NAME;
125249423Sdim			break;
126239310Sdim		case 'R' :
127249423Sdim			opts ^= OPT_NORESOLVE;
128239310Sdim			break;
129239310Sdim		case 'r' :
130239310Sdim			opts ^= OPT_REMOVE;
131251662Sdim			break;
132239310Sdim		case 's' :
133239310Sdim			swapactive();
134239310Sdim			break;
135239310Sdim		case 'T' :
136239310Sdim			if (opendevice(ipfname, 1) >= 0)
137239310Sdim				ipf_dotuning(fd, optarg, ioctl);
138239310Sdim			break;
139249423Sdim		case 'v' :
140239310Sdim			opts += OPT_VERBOSE;
141239310Sdim			break;
142249423Sdim		case 'V' :
143239310Sdim			if (showversion())
144239310Sdim				exit(1);
145239310Sdim			break;
146239310Sdim		case 'y' :
147239310Sdim			ipf_frsync();
148239310Sdim			break;
149239310Sdim		case 'z' :
150239310Sdim			opts ^= OPT_ZERORULEST;
151239310Sdim			break;
152249423Sdim		case 'Z' :
153239310Sdim			zerostats();
154239310Sdim			break;
155239310Sdim		}
156251662Sdim	}
157251662Sdim
158239310Sdim	if (optind < 2)
159239310Sdim		usage();
160251662Sdim
161239310Sdim	if (fd != -1)
162239310Sdim		(void) close(fd);
163239310Sdim
164239310Sdim	return(0);
165239310Sdim	/* NOTREACHED */
166249423Sdim}
167239310Sdim
168239310Sdim
169249423Sdimstatic int opendevice(ipfdev, check)
170249423Sdimchar *ipfdev;
171249423Sdimint check;
172249423Sdim{
173239310Sdim	if (opts & OPT_DONOTHING)
174239310Sdim		return -2;
175239310Sdim
176239310Sdim	if (check && checkrev(ipfname) == -1) {
177239310Sdim		fprintf(stderr, "User/kernel version check failed\n");
178239310Sdim		return -2;
179239310Sdim	}
180239310Sdim
181239310Sdim	if (!ipfdev)
182249423Sdim		ipfdev = ipfname;
183249423Sdim
184239310Sdim	if (fd == -1)
185239310Sdim		if ((fd = open(ipfdev, O_RDWR)) == -1)
186239310Sdim			if ((fd = open(ipfdev, O_RDONLY)) == -1)
187239310Sdim				perror("open device");
188239310Sdim	return fd;
189239310Sdim}
190239310Sdim
191239310Sdim
192239310Sdimstatic void closedevice()
193239310Sdim{
194239310Sdim	close(fd);
195239310Sdim	fd = -1;
196239310Sdim}
197239310Sdim
198249423Sdim
199239310Sdimstatic	int	get_flags()
200249423Sdim{
201249423Sdim	int i;
202249423Sdim
203239310Sdim	if ((opendevice(ipfname, 1) != -2) &&
204249423Sdim	    (ioctl(fd, SIOCGETFF, &i) == -1)) {
205239310Sdim		perror("SIOCGETFF");
206239310Sdim		return 0;
207239310Sdim	}
208251662Sdim	return i;
209251662Sdim}
210239310Sdim
211239310Sdim
212239310Sdimstatic	void	set_state(enable)
213251662Sdimu_int	enable;
214239310Sdim{
215249423Sdim	if (opendevice(ipfname, 0) != -2)
216239310Sdim		if (ioctl(fd, SIOCFRENB, &enable) == -1) {
217239310Sdim			if (errno == EBUSY)
218239310Sdim				fprintf(stderr,
219239310Sdim					"IP FIlter: already initialized\n");
220239310Sdim			else
221249423Sdim				perror("SIOCFRENB");
222239310Sdim		}
223239310Sdim	return;
224239310Sdim}
225239310Sdim
226239310Sdim
227239310Sdimstatic	void	procfile(name, file)
228239310Sdimchar	*name, *file;
229239310Sdim{
230239310Sdim	(void) opendevice(ipfname, 1);
231239310Sdim
232239310Sdim	initparse();
233239310Sdim
234239310Sdim	ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
235239310Sdim
236239310Sdim	if (outputc) {
237239310Sdim		printC(0);
238239310Sdim		printC(1);
239251662Sdim		emit(-1, -1, NULL, NULL);
240251662Sdim	}
241239310Sdim}
242239310Sdim
243239310Sdim
244239310Sdimstatic void ipf_interceptadd(fd, ioctlfunc, ptr)
245239310Sdimint fd;
246239310Sdimioctlfunc_t ioctlfunc;
247239310Sdimvoid *ptr;
248239310Sdim{
249239310Sdim	if (outputc)
250239310Sdim		printc(ptr);
251239310Sdim
252239310Sdim	ipf_addrule(fd, ioctlfunc, ptr);
253239310Sdim}
254251662Sdim
255239310Sdim
256239310Sdimstatic void packetlogon(opt)
257239310Sdimchar	*opt;
258239310Sdim{
259239310Sdim	int	flag, xfd, logopt, change = 0;
260239310Sdim
261249423Sdim	flag = get_flags();
262249423Sdim	if (flag != 0) {
263251662Sdim		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
264249423Sdim			printf("log flag is currently %#x\n", flag);
265251662Sdim	}
266251662Sdim
267239310Sdim	flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
268239310Sdim
269239310Sdim	if (strstr(opt, "pass")) {
270249423Sdim		flag |= FF_LOGPASS;
271251662Sdim		if (opts & OPT_VERBOSE)
272239310Sdim			printf("set log flag: pass\n");
273239310Sdim		change = 1;
274239310Sdim	}
275239310Sdim	if (strstr(opt, "nomatch")) {
276239310Sdim		flag |= FF_LOGNOMATCH;
277239310Sdim		if (opts & OPT_VERBOSE)
278239310Sdim			printf("set log flag: nomatch\n");
279239310Sdim		change = 1;
280249423Sdim	}
281249423Sdim	if (strstr(opt, "block") || index(opt, 'd')) {
282249423Sdim		flag |= FF_LOGBLOCK;
283239310Sdim		if (opts & OPT_VERBOSE)
284239310Sdim			printf("set log flag: block\n");
285239310Sdim		change = 1;
286239310Sdim	}
287239310Sdim	if (strstr(opt, "none")) {
288239310Sdim		if (opts & OPT_VERBOSE)
289239310Sdim			printf("disable all log flags\n");
290239310Sdim		change = 1;
291239310Sdim	}
292239310Sdim
293239310Sdim	if (change == 1) {
294239310Sdim		if (opendevice(ipfname, 1) != -2 &&
295239310Sdim		    (ioctl(fd, SIOCSETFF, &flag) != 0))
296239310Sdim			perror("ioctl(SIOCSETFF)");
297239310Sdim	}
298239310Sdim
299239310Sdim	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
300239310Sdim		flag = get_flags();
301239310Sdim		printf("log flags are now %#x\n", flag);
302239310Sdim	}
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")) {
348		if (*arg == 'S')
349			fl = 0;
350		else
351			fl = 1;
352		rem = fl;
353
354		closedevice();
355		if (opendevice(IPSTATE_NAME, 1) == -2)
356			exit(1);
357
358		if (!(opts & OPT_DONOTHING)) {
359			if (use_inet6) {
360				if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
361					perror("ioctl(SIOCIPFL6)");
362					exit(1);
363				}
364			} else {
365				if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
366					perror("ioctl(SIOCIPFFL)");
367					exit(1);
368				}
369			}
370		}
371		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
372			printf("remove flags %s (%d)\n", arg, rem);
373			printf("removed %d filter rules\n", fl);
374		}
375		closedevice();
376		return;
377	}
378
379#ifdef	SIOCIPFFA
380	if (!strcmp(arg, "u")) {
381		closedevice();
382		/*
383		 * Flush auth rules and packets
384		 */
385		if (opendevice(IPL_AUTH, 1) == -1)
386			perror("open(IPL_AUTH)");
387		else {
388			if (ioctl(fd, SIOCIPFFA, &fl) == -1)
389				perror("ioctl(SIOCIPFFA)");
390		}
391		closedevice();
392		return;
393	}
394#endif
395
396	if (strchr(arg, 'i') || strchr(arg, 'I'))
397		fl = FR_INQUE;
398	if (strchr(arg, 'o') || strchr(arg, 'O'))
399		fl = FR_OUTQUE;
400	if (strchr(arg, 'a') || strchr(arg, 'A'))
401		fl = FR_OUTQUE|FR_INQUE;
402	if (opts & OPT_INACTIVE)
403		fl |= FR_INACTIVE;
404	rem = fl;
405
406	if (opendevice(ipfname, 1) == -2)
407		exit(1);
408
409	if (!(opts & OPT_DONOTHING)) {
410		if (use_inet6) {
411			if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
412				perror("ioctl(SIOCIPFL6)");
413				exit(1);
414			}
415		} else {
416			if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
417				perror("ioctl(SIOCIPFFL)");
418				exit(1);
419			}
420		}
421	}
422
423	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
424		printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
425			(rem & FR_OUTQUE) ? "O" : "", rem);
426		printf("removed %d filter rules\n", fl);
427	}
428	return;
429}
430
431
432static void swapactive()
433{
434	int in = 2;
435
436	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
437		perror("ioctl(SIOCSWAPA)");
438	else
439		printf("Set %d now inactive\n", in);
440}
441
442
443void ipf_frsync()
444{
445	int frsyn = 0;
446
447	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
448		perror("SIOCFRSYN");
449	else
450		printf("filter sync'd\n");
451}
452
453
454void zerostats()
455{
456	ipfobj_t	obj;
457	friostat_t	fio;
458
459	obj.ipfo_rev = IPFILTER_VERSION;
460	obj.ipfo_type = IPFOBJ_IPFSTAT;
461	obj.ipfo_size = sizeof(fio);
462	obj.ipfo_ptr = &fio;
463	obj.ipfo_offset = 0;
464
465	if (opendevice(ipfname, 1) != -2) {
466		if (ioctl(fd, SIOCFRZST, &obj) == -1) {
467			perror("ioctl(SIOCFRZST)");
468			exit(-1);
469		}
470		showstats(&fio);
471	}
472
473}
474
475
476/*
477 * read the kernel stats for packets blocked and passed
478 */
479static void showstats(fp)
480friostat_t	*fp;
481{
482	printf("bad packets:\t\tin %lu\tout %lu\n",
483			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
484	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
485			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
486			fp->f_st[0].fr_nom);
487	printf(" counted %lu\n", fp->f_st[0].fr_acct);
488	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
489			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
490			fp->f_st[1].fr_nom);
491	printf(" counted %lu\n", fp->f_st[0].fr_acct);
492	printf(" input packets logged:\tblocked %lu passed %lu\n",
493			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
494	printf("output packets logged:\tblocked %lu passed %lu\n",
495			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
496	printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
497			fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
498			fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
499}
500
501
502static int showversion()
503{
504	struct friostat fio;
505	ipfobj_t ipfo;
506	u_32_t flags;
507	char *s;
508	int vfd;
509
510	bzero((caddr_t)&ipfo, sizeof(ipfo));
511	ipfo.ipfo_rev = IPFILTER_VERSION;
512	ipfo.ipfo_size = sizeof(fio);
513	ipfo.ipfo_ptr = (void *)&fio;
514	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
515
516	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
517
518	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
519		perror("open device");
520		return 1;
521	}
522
523	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
524		perror("ioctl(SIOCGETFS)");
525		close(vfd);
526		return 1;
527	}
528	close(vfd);
529	flags = get_flags();
530
531	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
532		(int)sizeof(fio.f_version), fio.f_version);
533	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
534	printf("Log Flags: %#x = ", flags);
535	s = "";
536	if (flags & FF_LOGPASS) {
537		printf("pass");
538		s = ", ";
539	}
540	if (flags & FF_LOGBLOCK) {
541		printf("%sblock", s);
542		s = ", ";
543	}
544	if (flags & FF_LOGNOMATCH) {
545		printf("%snomatch", s);
546		s = ", ";
547	}
548	if (flags & FF_BLOCKNONIP) {
549		printf("%snonip", s);
550		s = ", ";
551	}
552	if (!*s)
553		printf("none set");
554	putchar('\n');
555
556	printf("Default: ");
557	if (FR_ISPASS(fio.f_defpass))
558		s = "pass";
559	else if (FR_ISBLOCK(fio.f_defpass))
560		s = "block";
561	else
562		s = "nomatch -> block";
563	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
564	printf("Active list: %d\n", fio.f_active);
565	printf("Feature mask: %#x\n", fio.f_features);
566
567	return 0;
568}
569