xref: /illumos-gate/usr/src/cmd/ipf/tools/ipf.c (revision fe0e7ec4)
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11 
12 #ifdef	__FreeBSD__
13 # ifndef __FreeBSD_cc_version
14 #  include <osreldate.h>
15 # else
16 #  if __FreeBSD_cc_version < 430000
17 #   include <osreldate.h>
18 #  endif
19 # endif
20 #endif
21 #include "ipf.h"
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #if SOLARIS2 >= 10
25 #include "ipl.h"
26 #else
27 #include "netinet/ipl.h"
28 #endif
29 
30 #if !defined(lint)
31 static const char sccsid[] = "@(#)ipf.c	1.23 6/5/96 (C) 1993-2000 Darren Reed";
32 static const char rcsid[] = "@(#)$Id: ipf.c,v 1.24 2003/07/01 16:30:47 darrenr Exp $";
33 #endif
34 
35 #if	SOLARIS
36 static	void	blockunknown __P((void));
37 #endif
38 #if !defined(__SVR4) && defined(__GNUC__)
39 extern	char	*index __P((const char *, int));
40 #endif
41 
42 extern	char	*optarg;
43 extern	int	optind;
44 extern	frentry_t *frtop;
45 
46 
47 void	frsync __P((void));
48 void	zerostats __P((void));
49 int	main __P((int, char *[]));
50 
51 int	opts = 0;
52 int	outputc = 0;
53 int	use_inet6 = 0;
54 
55 static	void	procfile __P((char *, char *)), flushfilter __P((char *));
56 static	void	set_state __P((u_int)), showstats __P((friostat_t *));
57 static	void	packetlogon __P((char *)), swapactive __P((void));
58 static	int	opendevice __P((char *, int));
59 static	void	closedevice __P((void));
60 static	char	*ipfname = IPL_NAME;
61 static	void	usage __P((void));
62 static	int	showversion __P((void));
63 static	int	get_flags __P((void));
64 static	void	ipf_interceptadd __P((int, ioctlfunc_t, void *));
65 static	void	dotuning __P((char *));
66 static	void	printtunable __P((ipftune_t *));
67 
68 static	int	fd = -1;
69 static	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
70 						      ioctl, ioctl, ioctl,
71 						      ioctl, ioctl };
72 
73 
74 static void usage()
75 {
76 	fprintf(stderr, "usage: ipf [-"
77 #ifdef USE_INET6
78 		"6"
79 #endif
80 		"AdDEInoPrsUvVyzZ] %s %s %s %s\n",
81 		"[-l block|pass|nomatch|state|nat]", "[-T optionlist]",
82 		"[-F i|o|a|s|S|u]", "[-f filename]");
83 	exit(1);
84 }
85 
86 
87 int main(argc,argv)
88 int argc;
89 char *argv[];
90 {
91 	int c;
92 
93 	if (argc < 2)
94 		usage();
95 
96 	while ((c = getopt(argc, argv, "6ACdDEf:F:Il:noPrsT:UvVyzZ")) != -1) {
97 		switch (c)
98 		{
99 		case '?' :
100 			usage();
101 			break;
102 #ifdef	USE_INET6
103 		case '6' :
104 			use_inet6 = 1;
105 			break;
106 #endif
107 		case 'A' :
108 			opts &= ~OPT_INACTIVE;
109 			break;
110 #ifdef USE_OPTIONC
111 		case 'C' :
112 			outputc = 1;
113 			break;
114 #endif
115 		case 'E' :
116 			set_state((u_int)1);
117 			break;
118 		case 'D' :
119 			set_state((u_int)0);
120 			break;
121 		case 'd' :
122 			opts ^= OPT_DEBUG;
123 			break;
124 		case 'f' :
125 			procfile(argv[0], optarg);
126 			break;
127 		case 'F' :
128 			flushfilter(optarg);
129 			break;
130 		case 'I' :
131 			opts ^= OPT_INACTIVE;
132 			break;
133 		case 'l' :
134 			packetlogon(optarg);
135 			break;
136 		case 'n' :
137 			opts ^= OPT_DONOTHING;
138 			break;
139 		case 'o' :
140 			break;
141 		case 'P' :
142 			ipfname = IPAUTH_NAME;
143 			break;
144 		case 'r' :
145 			opts ^= OPT_REMOVE;
146 			break;
147 		case 's' :
148 			swapactive();
149 			break;
150 		case 'T' :
151 			dotuning(optarg);
152 			break;
153 #if SOLARIS
154 		case 'U' :
155 			blockunknown();
156 			break;
157 #endif
158 		case 'v' :
159 			opts += OPT_VERBOSE;
160 			break;
161 		case 'V' :
162 			if (showversion())
163 				exit(1);
164 			break;
165 		case 'y' :
166 			frsync();
167 			break;
168 		case 'z' :
169 			opts ^= OPT_ZERORULEST;
170 			break;
171 		case 'Z' :
172 			zerostats();
173 			break;
174 		}
175 	}
176 
177 	if (optind < 2)
178 		usage();
179 
180 	if (fd != -1)
181 		(void) close(fd);
182 
183 	return(0);
184 	/* NOTREACHED */
185 }
186 
187 
188 static int opendevice(ipfdev, check)
189 char *ipfdev;
190 int check;
191 {
192 	if (opts & OPT_DONOTHING)
193 		return -2;
194 
195 	if (check && checkrev(ipfname) == -1) {
196 		fprintf(stderr, "User/kernel version check failed\n");
197 		return -2;
198 	}
199 
200 	if (!ipfdev)
201 		ipfdev = ipfname;
202 
203 	if (fd == -1)
204 		if ((fd = open(ipfdev, O_RDWR)) == -1)
205 			if ((fd = open(ipfdev, O_RDONLY)) == -1)
206 				perror("open device");
207 	return fd;
208 }
209 
210 
211 static void closedevice()
212 {
213 	close(fd);
214 	fd = -1;
215 }
216 
217 
218 static	int	get_flags()
219 {
220 	int i;
221 
222 	if ((opendevice(ipfname, 1) != -2) &&
223 	    (ioctl(fd, SIOCGETFF, &i) == -1)) {
224 		perror("SIOCGETFF");
225 		return 0;
226 	}
227 	return i;
228 }
229 
230 
231 static	void	set_state(enable)
232 u_int	enable;
233 {
234 	if (opendevice(ipfname, 0) != -2)
235 		if (ioctl(fd, SIOCFRENB, &enable) == -1) {
236 			if (errno == EBUSY)
237 				fprintf(stderr,
238 					"IP FIlter: already initialized\n");
239 			else
240 				perror("SIOCFRENB");
241 		}
242 	return;
243 }
244 
245 
246 static	void	procfile(name, file)
247 char	*name, *file;
248 {
249 	(void) opendevice(ipfname, 1);
250 
251 	initparse();
252 
253 	ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
254 
255 	if (outputc) {
256 		printC(0);
257 		printC(1);
258 		emit(-1, -1, NULL, NULL);
259 	}
260 }
261 
262 
263 static void ipf_interceptadd(fd, ioctlfunc, ptr)
264 int fd;
265 ioctlfunc_t ioctlfunc;
266 void *ptr;
267 {
268 	if (outputc)
269 		printc(ptr);
270 
271 	ipf_addrule(fd, ioctlfunc, ptr);
272 }
273 
274 
275 static void packetlogon(opt)
276 char	*opt;
277 {
278 	int	flag, xfd, logopt;
279 
280 	flag = get_flags();
281 	if (flag != 0) {
282 		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
283 			printf("log flag is currently %#x\n", flag);
284 	}
285 
286 	flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
287 
288 	if (strstr(opt, "pass")) {
289 		flag |= FF_LOGPASS;
290 		if (opts & OPT_VERBOSE)
291 			printf("set log flag: pass\n");
292 	}
293 	if (strstr(opt, "nomatch")) {
294 		flag |= FF_LOGNOMATCH;
295 		if (opts & OPT_VERBOSE)
296 			printf("set log flag: nomatch\n");
297 	}
298 	if (strstr(opt, "block") || index(opt, 'd')) {
299 		flag |= FF_LOGBLOCK;
300 		if (opts & OPT_VERBOSE)
301 			printf("set log flag: block\n");
302 	}
303 
304 	if (opendevice(ipfname, 1) != -2 && (ioctl(fd, SIOCSETFF, &flag) != 0))
305 		perror("ioctl(SIOCSETFF)");
306 
307 	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
308 		flag = get_flags();
309 		printf("log flag is now %#x\n", flag);
310 	}
311 
312 	if (strstr(opt, "state")) {
313 		if (opts & OPT_VERBOSE)
314 			printf("set state log flag\n");
315 		xfd = open(IPSTATE_NAME, O_RDWR);
316 		if (xfd >= 0) {
317 			logopt = 0;
318 			if (ioctl(xfd, SIOCGETLG, &logopt))
319 				perror("ioctl(SIOCGETLG)");
320 			else {
321 				logopt = 1 - logopt;
322 				if (ioctl(xfd, SIOCSETLG, &logopt))
323 					perror("ioctl(SIOCSETLG)");
324 			}
325 			close(xfd);
326 		}
327 	}
328 
329 	if (strstr(opt, "nat")) {
330 		if (opts & OPT_VERBOSE)
331 			printf("set nat log flag\n");
332 		xfd = open(IPNAT_NAME, O_RDWR);
333 		if (xfd >= 0) {
334 			logopt = 0;
335 			if (ioctl(xfd, SIOCGETLG, &logopt))
336 				perror("ioctl(SIOCGETLG)");
337 			else {
338 				logopt = 1 - logopt;
339 				if (ioctl(xfd, SIOCSETLG, &logopt))
340 					perror("ioctl(SIOCSETLG)");
341 			}
342 			close(xfd);
343 		}
344 	}
345 }
346 
347 
348 static	void	flushfilter(arg)
349 char	*arg;
350 {
351 	int	fl = 0, rem;
352 
353 	if (!arg || !*arg)
354 		return;
355 	if (!strcmp(arg, "s") || !strcmp(arg, "S")) {
356 		if (*arg == 'S')
357 			fl = 0;
358 		else
359 			fl = 1;
360 		rem = fl;
361 
362 		closedevice();
363 
364 		if (opendevice(IPSTATE_NAME, 1) != -2) {
365 			if (use_inet6) {
366 #ifdef USE_INET6
367 				if (ioctl(fd, SIOCIPFL6, &fl) == -1)
368 					perror("SIOCIPFL6");
369 #endif
370 			} else {
371 				if (ioctl(fd, SIOCIPFFL, &fl) == -1)
372 					perror("SIOCIPFFL");
373 			}
374 		}
375 
376 		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
377 			printf("remove flags %s (%d)\n", arg, rem);
378 			printf("removed %d filter rules\n", fl);
379 		}
380 		closedevice();
381 		return;
382 	}
383 
384 #ifdef	SIOCIPFFA
385 	if (!strcmp(arg, "u")) {
386 		closedevice();
387 		/*
388 		 * Flush auth rules and packets
389 		 */
390 		if (opendevice(IPL_AUTH, 1) == -1)
391 			perror("open(IPL_AUTH)");
392 		else {
393 			if (ioctl(fd, SIOCIPFFA, &fl) == -1)
394 				perror("ioctl(SIOCIPFFA)");
395 		}
396 		closedevice();
397 		return;
398 	}
399 #endif
400 
401 	if (strchr(arg, 'i') || strchr(arg, 'I'))
402 		fl = FR_INQUE;
403 	if (strchr(arg, 'o') || strchr(arg, 'O'))
404 		fl = FR_OUTQUE;
405 	if (strchr(arg, 'a') || strchr(arg, 'A'))
406 		fl = FR_OUTQUE|FR_INQUE;
407 	if (opts & OPT_INACTIVE)
408 		fl |= FR_INACTIVE;
409 	rem = fl;
410 
411 	if (opendevice(ipfname, 1) != -2) {
412 		if (use_inet6) {
413 #ifdef USE_INET6
414 			if (ioctl(fd, SIOCIPFL6, &fl) == -1)
415 				perror("SIOCIPFL6");
416 #endif
417 		} else {
418 			if (ioctl(fd, SIOCIPFFL, &fl) == -1)
419 				perror("SIOCIPFFL");
420 		}
421 	}
422 
423 	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
424 		printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
425 			(rem & FR_OUTQUE) ? "O" : "", rem);
426 		printf("removed %d filter rules\n", fl);
427 	}
428 	return;
429 }
430 
431 
432 static void swapactive()
433 {
434 	int in = 2;
435 
436 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
437 		perror("ioctl(SIOCSWAPA)");
438 	else
439 		printf("Set %d now inactive\n", in);
440 }
441 
442 
443 void frsync()
444 {
445 	int frsyn = 0;
446 
447 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
448 		perror("SIOCFRSYN");
449 	else
450 		printf("filter sync'd\n");
451 }
452 
453 
454 void zerostats()
455 {
456 	friostat_t	fio;
457 	friostat_t	*fiop = &fio;
458 
459 	if (opendevice(ipfname, 1) != -2) {
460 		if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
461 			perror("ioctl(SIOCFRZST)");
462 			exit(-1);
463 		}
464 		showstats(fiop);
465 	}
466 
467 }
468 
469 
470 /*
471  * read the kernel stats for packets blocked and passed
472  */
473 static void showstats(fp)
474 friostat_t	*fp;
475 {
476 	printf("bad packets:\t\tin %lu\tout %lu\n",
477 			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
478 	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
479 			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
480 			fp->f_st[0].fr_nom);
481 	printf(" counted %lu\n", fp->f_st[0].fr_acct);
482 	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
483 			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
484 			fp->f_st[1].fr_nom);
485 	printf(" counted %lu\n", fp->f_st[0].fr_acct);
486 	printf(" input packets logged:\tblocked %lu passed %lu\n",
487 			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
488 	printf("output packets logged:\tblocked %lu passed %lu\n",
489 			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
490 	printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
491 			fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
492 			fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
493 }
494 
495 
496 #if SOLARIS
497 static void blockunknown()
498 {
499 	u_32_t	flag;
500 
501 	if (opendevice(ipfname, 1) == -1)
502 		return;
503 
504 	flag = get_flags();
505 	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
506 		printf("log flag is currently %#x\n", flag);
507 
508 	flag ^= FF_BLOCKNONIP;
509 
510 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSETFF, &flag))
511 		perror("ioctl(SIOCSETFF)");
512 
513 	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
514 		if (ioctl(fd, SIOCGETFF, &flag))
515 			perror("ioctl(SIOCGETFF)");
516 
517 		printf("log flag is now %#x\n", flag);
518 	}
519 }
520 #endif
521 
522 
523 static int showversion()
524 {
525 	struct friostat fio;
526 	ipfobj_t ipfo;
527 	u_32_t flags;
528 	char *s;
529 	int vfd;
530 
531 	bzero((caddr_t)&ipfo, sizeof(ipfo));
532 	ipfo.ipfo_rev = IPFILTER_VERSION;
533 	ipfo.ipfo_size = sizeof(fio);
534 	ipfo.ipfo_ptr = (void *)&fio;
535 	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
536 
537 	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
538 
539 	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
540 		perror("open device");
541 		return 1;
542 	}
543 
544 	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
545 		perror("ioctl(SIOCGETFS)");
546 		close(vfd);
547 		return 1;
548 	}
549 	close(vfd);
550 	flags = get_flags();
551 
552 	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
553 		(int)sizeof(fio.f_version), fio.f_version);
554 	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
555 	printf("Log Flags: %#x = ", flags);
556 	s = "";
557 	if (flags & FF_LOGPASS) {
558 		printf("pass");
559 		s = ", ";
560 	}
561 	if (flags & FF_LOGBLOCK) {
562 		printf("%sblock", s);
563 		s = ", ";
564 	}
565 	if (flags & FF_LOGNOMATCH) {
566 		printf("%snomatch", s);
567 		s = ", ";
568 	}
569 	if (flags & FF_BLOCKNONIP) {
570 		printf("%snonip", s);
571 		s = ", ";
572 	}
573 	if (!*s)
574 		printf("none set");
575 	putchar('\n');
576 
577 	printf("Default: ");
578 	if (FR_ISPASS(fio.f_defpass))
579 		s = "pass";
580 	else if (FR_ISBLOCK(fio.f_defpass))
581 		s = "block";
582 	else
583 		s = "nomatch -> block";
584 	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
585 	printf("Active list: %d\n", fio.f_active);
586 
587 	return 0;
588 }
589 
590 
591 static void dotuning(tuneargs)
592 char *tuneargs;
593 {
594 	ipfobj_t obj;
595 	ipftune_t tu;
596 	char *s, *t;
597 
598 	if (opendevice(ipfname, 1) < 0)
599 		return;
600 
601 	bzero((char *)&tu, sizeof(tu));
602 	obj.ipfo_rev = IPFILTER_VERSION;
603 	obj.ipfo_size = sizeof(tu);;
604 	obj.ipfo_ptr = (void *)&tu;
605 	obj.ipfo_type = IPFOBJ_TUNEABLE;
606 
607 	for (s = strtok(tuneargs, ","); s != NULL; s = strtok(NULL, ",")) {
608 		if (!strcmp(s, "list")) {
609 			while (1) {
610 				if (ioctl(fd, SIOCIPFGETNEXT, &obj) == -1) {
611 					perror("ioctl(SIOCIPFGETNEXT)");
612 					break;
613 				}
614 				if (tu.ipft_cookie == NULL)
615 					break;
616 
617 				tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
618 				printtunable(&tu);
619 			}
620 		} else if ((t = strchr(s, '=')) != NULL) {
621 			*t++ = '\0';
622 			strncpy(tu.ipft_name, s, sizeof(tu.ipft_name));
623 			if (sscanf(t, "%lu", &tu.ipft_vlong) == 1) {
624 				if (ioctl(fd, SIOCIPFSET, &obj) == -1) {
625 					perror("ioctl(SIOCIPFSET)");
626 					return;
627 				}
628 			} else {
629 				fprintf(stderr, "invalid value '%s'\n", s);
630 				return;
631 			}
632 		} else {
633 			strncpy(tu.ipft_name, s, sizeof(tu.ipft_name));
634 			if (ioctl(fd, SIOCIPFGET, &obj) == -1) {
635 				perror("ioctl(SIOCIPFGET)");
636 				return;
637 			}
638 			if (tu.ipft_cookie == NULL)
639 				return;
640 
641 			tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
642 			printtunable(&tu);
643 		}
644 	}
645 }
646 
647 
648 static void printtunable(tup)
649 ipftune_t *tup;
650 {
651 	printf("%s\tmin %#lx\tmax %#lx\tcurrent ",
652 		tup->ipft_name, tup->ipft_min, tup->ipft_max);
653 	if (tup->ipft_sz == sizeof(u_long))
654 		printf("%lu\n", tup->ipft_vlong);
655 	else if (tup->ipft_sz == sizeof(u_int))
656 		printf("%u\n", tup->ipft_vint);
657 	else if (tup->ipft_sz == sizeof(u_short))
658 		printf("%hu\n", tup->ipft_vshort);
659 	else if (tup->ipft_sz == sizeof(u_char))
660 		printf("%u\n", (u_int)tup->ipft_vchar);
661 	else {
662 		printf("sz = %d\n", tup->ipft_sz);
663 	}
664 }
665