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