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