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