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