xref: /freebsd-12.1/contrib/ipfilter/tools/ipf.c (revision b032f27c)
1 /*	$FreeBSD$	*/
2 
3 /*
4  * Copyright (C) 2001-2006 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)
23 static const char sccsid[] = "@(#)ipf.c	1.23 6/5/96 (C) 1993-2000 Darren Reed";
24 static const char rcsid[] = "@(#)$Id: ipf.c,v 1.35.2.8 2007/05/10 06:12:01 darrenr Exp $";
25 #endif
26 
27 #if !defined(__SVR4) && defined(__GNUC__)
28 extern	char	*index __P((const char *, int));
29 #endif
30 
31 extern	char	*optarg;
32 extern	int	optind;
33 extern	frentry_t *frtop;
34 
35 
36 void	ipf_frsync __P((void));
37 void	zerostats __P((void));
38 int	main __P((int, char *[]));
39 
40 int	opts = 0;
41 int	outputc = 0;
42 int	use_inet6 = 0;
43 
44 static	void	procfile __P((char *, char *)), flushfilter __P((char *));
45 static	void	set_state __P((u_int)), showstats __P((friostat_t *));
46 static	void	packetlogon __P((char *)), swapactive __P((void));
47 static	int	opendevice __P((char *, int));
48 static	void	closedevice __P((void));
49 static	char	*ipfname = IPL_NAME;
50 static	void	usage __P((void));
51 static	int	showversion __P((void));
52 static	int	get_flags __P((void));
53 static	void	ipf_interceptadd __P((int, ioctlfunc_t, void *));
54 
55 static	int	fd = -1;
56 static	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
57 						      ioctl, ioctl, ioctl,
58 						      ioctl, ioctl };
59 
60 
61 static 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 
70 int main(argc,argv)
71 int argc;
72 char *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 
169 static int opendevice(ipfdev, check)
170 char *ipfdev;
171 int 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 
192 static void closedevice()
193 {
194 	close(fd);
195 	fd = -1;
196 }
197 
198 
199 static	int	get_flags()
200 {
201 	int i = 0;
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 
212 static	void	set_state(enable)
213 u_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 
227 static	void	procfile(name, file)
228 char	*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 
244 static void ipf_interceptadd(fd, ioctlfunc, ptr)
245 int fd;
246 ioctlfunc_t ioctlfunc;
247 void *ptr;
248 {
249 	if (outputc)
250 		printc(ptr);
251 
252 	ipf_addrule(fd, ioctlfunc, ptr);
253 }
254 
255 
256 static void packetlogon(opt)
257 char	*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 
340 static	void	flushfilter(arg)
341 char	*arg;
342 {
343 	int	fl = 0, rem;
344 
345 	if (!arg || !*arg)
346 		return;
347 	if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
348 		if (*arg == 'S')
349 			fl = 0;
350 		else if (*arg == 's')
351 			fl = 1;
352 		else
353 			fl = atoi(arg);
354 		rem = fl;
355 
356 		closedevice();
357 		if (opendevice(IPSTATE_NAME, 1) == -2)
358 			exit(1);
359 
360 		if (!(opts & OPT_DONOTHING)) {
361 			if (use_inet6) {
362 				if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
363 					perror("ioctl(SIOCIPFL6)");
364 					exit(1);
365 				}
366 			} else {
367 				if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
368 					perror("ioctl(SIOCIPFFL)");
369 					exit(1);
370 				}
371 			}
372 		}
373 		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
374 			printf("remove flags %s (%d)\n", arg, rem);
375 			printf("removed %d entries\n", fl);
376 		}
377 		closedevice();
378 		return;
379 	}
380 
381 #ifdef	SIOCIPFFA
382 	if (!strcmp(arg, "u")) {
383 		closedevice();
384 		/*
385 		 * Flush auth rules and packets
386 		 */
387 		if (opendevice(IPL_AUTH, 1) == -1)
388 			perror("open(IPL_AUTH)");
389 		else {
390 			if (ioctl(fd, SIOCIPFFA, &fl) == -1)
391 				perror("ioctl(SIOCIPFFA)");
392 		}
393 		closedevice();
394 		return;
395 	}
396 #endif
397 
398 	if (strchr(arg, 'i') || strchr(arg, 'I'))
399 		fl = FR_INQUE;
400 	if (strchr(arg, 'o') || strchr(arg, 'O'))
401 		fl = FR_OUTQUE;
402 	if (strchr(arg, 'a') || strchr(arg, 'A'))
403 		fl = FR_OUTQUE|FR_INQUE;
404 	if (opts & OPT_INACTIVE)
405 		fl |= FR_INACTIVE;
406 	rem = fl;
407 
408 	if (opendevice(ipfname, 1) == -2)
409 		exit(1);
410 
411 	if (!(opts & OPT_DONOTHING)) {
412 		if (use_inet6) {
413 			if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
414 				perror("ioctl(SIOCIPFL6)");
415 				exit(1);
416 			}
417 		} else {
418 			if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
419 				perror("ioctl(SIOCIPFFL)");
420 				exit(1);
421 			}
422 		}
423 	}
424 
425 	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
426 		printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
427 			(rem & FR_OUTQUE) ? "O" : "", rem);
428 		printf("removed %d filter rules\n", fl);
429 	}
430 	return;
431 }
432 
433 
434 static void swapactive()
435 {
436 	int in = 2;
437 
438 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
439 		perror("ioctl(SIOCSWAPA)");
440 	else
441 		printf("Set %d now inactive\n", in);
442 }
443 
444 
445 void ipf_frsync()
446 {
447 	int frsyn = 0;
448 
449 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
450 		perror("SIOCFRSYN");
451 	else
452 		printf("filter sync'd\n");
453 }
454 
455 
456 void zerostats()
457 {
458 	ipfobj_t	obj;
459 	friostat_t	fio;
460 
461 	obj.ipfo_rev = IPFILTER_VERSION;
462 	obj.ipfo_type = IPFOBJ_IPFSTAT;
463 	obj.ipfo_size = sizeof(fio);
464 	obj.ipfo_ptr = &fio;
465 	obj.ipfo_offset = 0;
466 
467 	if (opendevice(ipfname, 1) != -2) {
468 		if (ioctl(fd, SIOCFRZST, &obj) == -1) {
469 			perror("ioctl(SIOCFRZST)");
470 			exit(-1);
471 		}
472 		showstats(&fio);
473 	}
474 
475 }
476 
477 
478 /*
479  * read the kernel stats for packets blocked and passed
480  */
481 static void showstats(fp)
482 friostat_t	*fp;
483 {
484 	printf("bad packets:\t\tin %lu\tout %lu\n",
485 			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
486 	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
487 			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
488 			fp->f_st[0].fr_nom);
489 	printf(" counted %lu\n", fp->f_st[0].fr_acct);
490 	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
491 			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
492 			fp->f_st[1].fr_nom);
493 	printf(" counted %lu\n", fp->f_st[0].fr_acct);
494 	printf(" input packets logged:\tblocked %lu passed %lu\n",
495 			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
496 	printf("output packets logged:\tblocked %lu passed %lu\n",
497 			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
498 	printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
499 			fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
500 			fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
501 }
502 
503 
504 static int showversion()
505 {
506 	struct friostat fio;
507 	ipfobj_t ipfo;
508 	u_32_t flags;
509 	char *s;
510 	int vfd;
511 
512 	bzero((caddr_t)&ipfo, sizeof(ipfo));
513 	ipfo.ipfo_rev = IPFILTER_VERSION;
514 	ipfo.ipfo_size = sizeof(fio);
515 	ipfo.ipfo_ptr = (void *)&fio;
516 	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
517 
518 	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
519 
520 	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
521 		perror("open device");
522 		return 1;
523 	}
524 
525 	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
526 		perror("ioctl(SIOCGETFS)");
527 		close(vfd);
528 		return 1;
529 	}
530 	close(vfd);
531 	flags = get_flags();
532 
533 	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
534 		(int)sizeof(fio.f_version), fio.f_version);
535 	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
536 	printf("Log Flags: %#x = ", flags);
537 	s = "";
538 	if (flags & FF_LOGPASS) {
539 		printf("pass");
540 		s = ", ";
541 	}
542 	if (flags & FF_LOGBLOCK) {
543 		printf("%sblock", s);
544 		s = ", ";
545 	}
546 	if (flags & FF_LOGNOMATCH) {
547 		printf("%snomatch", s);
548 		s = ", ";
549 	}
550 	if (flags & FF_BLOCKNONIP) {
551 		printf("%snonip", s);
552 		s = ", ";
553 	}
554 	if (!*s)
555 		printf("none set");
556 	putchar('\n');
557 
558 	printf("Default: ");
559 	if (FR_ISPASS(fio.f_defpass))
560 		s = "pass";
561 	else if (FR_ISBLOCK(fio.f_defpass))
562 		s = "block";
563 	else
564 		s = "nomatch -> block";
565 	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
566 	printf("Active list: %d\n", fio.f_active);
567 	printf("Feature mask: %#x\n", fio.f_features);
568 
569 	return 0;
570 }
571