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