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