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