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