ipf.c revision 153881
1/*	$FreeBSD: head/contrib/ipfilter/tools/ipf.c 153881 2005-12-30 11:52:26Z guido $	*/
2
3/*
4 * Copyright (C) 1993-2001 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.3 2004/12/15 18:27:17 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;
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")) {
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	friostat_t	fio;
457	friostat_t	*fiop = &fio;
458
459	if (opendevice(ipfname, 1) != -2) {
460		if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
461			perror("ioctl(SIOCFRZST)");
462			exit(-1);
463		}
464		showstats(fiop);
465	}
466
467}
468
469
470/*
471 * read the kernel stats for packets blocked and passed
472 */
473static void showstats(fp)
474friostat_t	*fp;
475{
476	printf("bad packets:\t\tin %lu\tout %lu\n",
477			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
478	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
479			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
480			fp->f_st[0].fr_nom);
481	printf(" counted %lu\n", fp->f_st[0].fr_acct);
482	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
483			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
484			fp->f_st[1].fr_nom);
485	printf(" counted %lu\n", fp->f_st[0].fr_acct);
486	printf(" input packets logged:\tblocked %lu passed %lu\n",
487			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
488	printf("output packets logged:\tblocked %lu passed %lu\n",
489			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
490	printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
491			fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
492			fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
493}
494
495
496static int showversion()
497{
498	struct friostat fio;
499	ipfobj_t ipfo;
500	u_32_t flags;
501	char *s;
502	int vfd;
503
504	bzero((caddr_t)&ipfo, sizeof(ipfo));
505	ipfo.ipfo_rev = IPFILTER_VERSION;
506	ipfo.ipfo_size = sizeof(fio);
507	ipfo.ipfo_ptr = (void *)&fio;
508	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
509
510	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
511
512	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
513		perror("open device");
514		return 1;
515	}
516
517	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
518		perror("ioctl(SIOCGETFS)");
519		close(vfd);
520		return 1;
521	}
522	close(vfd);
523	flags = get_flags();
524
525	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
526		(int)sizeof(fio.f_version), fio.f_version);
527	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
528	printf("Log Flags: %#x = ", flags);
529	s = "";
530	if (flags & FF_LOGPASS) {
531		printf("pass");
532		s = ", ";
533	}
534	if (flags & FF_LOGBLOCK) {
535		printf("%sblock", s);
536		s = ", ";
537	}
538	if (flags & FF_LOGNOMATCH) {
539		printf("%snomatch", s);
540		s = ", ";
541	}
542	if (flags & FF_BLOCKNONIP) {
543		printf("%snonip", s);
544		s = ", ";
545	}
546	if (!*s)
547		printf("none set");
548	putchar('\n');
549
550	printf("Default: ");
551	if (FR_ISPASS(fio.f_defpass))
552		s = "pass";
553	else if (FR_ISBLOCK(fio.f_defpass))
554		s = "block";
555	else
556		s = "nomatch -> block";
557	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
558	printf("Active list: %d\n", fio.f_active);
559	printf("Feature mask: %#x\n", fio.f_features);
560
561	return 0;
562}
563