xref: /netbsd-src/external/bsd/ipf/dist/tools/ipf.c (revision 7e1677552f1aed5121549ff414f9e94bd9e5416f)
1 /*	$NetBSD: ipf.c,v 1.4 2022/06/03 21:43:37 gutteridge 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)
24 static __attribute__((__used__)) const char sccsid[] = "@(#)ipf.c	1.23 6/5/96 (C) 1993-2000 Darren Reed";
25 static __attribute__((__used__)) 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__)
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 
usage()66 static void usage()
67 {
68 	fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
69 		"[-l block|pass|nomatch|none|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
70 		"[-f filename] [-T <tuneopts>]");
71 	exit(1);
72 }
73 
74 
main(argc,argv)75 int 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 
opendevice(ipfdev,check)180 static 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 
closedevice()203 static void closedevice()
204 {
205 	close(fd);
206 	fd = -1;
207 }
208 
209 
get_flags()210 static	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 
set_state(enable)223 static	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 
procfile(file)240 static	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 
ipf_interceptadd(fd,ioctlfunc,ptr)257 static 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 
packetlogon(opt)271 static 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 
flushfilter(arg,filter)355 static 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 
swapactive()465 static 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 
ipf_frsync()476 void 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 
zerostats()487 void 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  */
showstats(fp)512 static 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 
showversion()532 static 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