xref: /freebsd/sbin/ipf/ipf/ipf.c (revision abd87254)
1 
2 /*
3  * Copyright (C) 2012 by Darren Reed.
4  *
5  * See the IPFILTER.LICENCE file for details on licencing.
6  */
7 #include "ipf.h"
8 #include <fcntl.h>
9 #include <ctype.h>
10 #include <sys/ioctl.h>
11 #include "netinet/ipl.h"
12 
13 
14 #if !defined(__SVR4) && defined(__GNUC__)
15 extern	char	*index(const char *, int);
16 #endif
17 
18 extern	char	*optarg;
19 extern	int	optind;
20 extern	frentry_t *frtop;
21 
22 
23 void	ipf_frsync(void);
24 void	zerostats(void);
25 int	main(int, char *[]);
26 
27 int	opts = 0;
28 int	outputc = 0;
29 int	use_inet6 = 0;
30 int	exitstatus = 0;
31 
32 static	void	procfile(char *);
33 static	void	flushfilter(char *, int *);
34 static	void	set_state(u_int);
35 static	void	showstats(friostat_t *);
36 static	void	packetlogon(char *);
37 static	void	swapactive(void);
38 static	int	opendevice(char *, int);
39 static	void	closedevice(void);
40 static	char	*ipfname = IPL_NAME;
41 static	void	usage(void);
42 static	int	showversion(void);
43 static	int	get_flags(void);
44 static	int	ipf_interceptadd(int, ioctlfunc_t, void *);
45 
46 static	int	fd = -1;
47 static	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
48 						      ioctl, ioctl, ioctl,
49 						      ioctl, ioctl };
50 
51 /* XXX	The following was added to satisfy a rescue/rescue/ build
52    XXX	requirement.  */
53 int	nohdrfields;
54 
55 static void usage()
56 {
57 	fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
58 		"[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
59 		"[-f filename] [-T <tuneopts>]");
60 	exit(1);
61 }
62 
63 
64 int
65 main(int argc, char *argv[])
66 {
67 	int c, *filter = NULL;
68 
69 	if (argc < 2)
70 		usage();
71 
72 	assigndefined(getenv("IPF_PREDEFINED"));
73 
74 	while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) {
75 		switch (c)
76 		{
77 		case '?' :
78 			usage();
79 			break;
80 		case '4' :
81 			use_inet6 = -1;
82 			break;
83 		case '6' :
84 			use_inet6 = 1;
85 			break;
86 		case 'A' :
87 			opts &= ~OPT_INACTIVE;
88 			break;
89 		case 'c' :
90 			if (strcmp(optarg, "c") == 0)
91 				outputc = 1;
92 			break;
93 		case 'E' :
94 			set_state((u_int)1);
95 			break;
96 		case 'D' :
97 			set_state((u_int)0);
98 			break;
99 		case 'd' :
100 			opts ^= OPT_DEBUG;
101 			break;
102 		case 'f' :
103 			procfile(optarg);
104 			break;
105 		case 'F' :
106 			flushfilter(optarg, filter);
107 			break;
108 		case 'I' :
109 			opts ^= OPT_INACTIVE;
110 			break;
111 		case 'l' :
112 			packetlogon(optarg);
113 			break;
114 		case 'm' :
115 			filter = parseipfexpr(optarg, NULL);
116 			break;
117 		case 'n' :
118 			opts ^= OPT_DONOTHING|OPT_DONTOPEN;
119 			break;
120 		case 'o' :
121 			break;
122 		case 'P' :
123 			ipfname = IPAUTH_NAME;
124 			break;
125 		case 'R' :
126 			opts ^= OPT_NORESOLVE;
127 			break;
128 		case 'r' :
129 			opts ^= OPT_REMOVE;
130 			break;
131 		case 's' :
132 			swapactive();
133 			break;
134 		case 'T' :
135 			if (opendevice(ipfname, 1) >= 0)
136 				ipf_dotuning(fd, optarg, ioctl);
137 			break;
138 		case 'v' :
139 			opts += OPT_VERBOSE;
140 			break;
141 		case 'V' :
142 			if (showversion())
143 				exit(1);
144 			break;
145 		case 'y' :
146 			ipf_frsync();
147 			break;
148 		case 'z' :
149 			opts ^= OPT_ZERORULEST;
150 			break;
151 		case 'Z' :
152 			zerostats();
153 			break;
154 		}
155 	}
156 
157 	if (optind < 2)
158 		usage();
159 
160 	if (fd != -1)
161 		(void) close(fd);
162 
163 	return (exitstatus);
164 	/* NOTREACHED */
165 }
166 
167 
168 static int
169 opendevice(char *ipfdev, int check)
170 {
171 	if (opts & OPT_DONOTHING)
172 		return (-2);
173 
174 	if (check && checkrev(ipfname) == -1) {
175 		fprintf(stderr, "User/kernel version check failed\n");
176 		return (-2);
177 	}
178 
179 	if (!ipfdev)
180 		ipfdev = ipfname;
181 
182 	if (fd == -1)
183 		if ((fd = open(ipfdev, O_RDWR)) == -1)
184 			if ((fd = open(ipfdev, O_RDONLY)) == -1)
185 				ipferror(fd, "open device");
186 	return (fd);
187 }
188 
189 
190 static void
191 closedevice(void)
192 {
193 	close(fd);
194 	fd = -1;
195 }
196 
197 
198 static int
199 get_flags(void)
200 {
201 	int i = 0;
202 
203 	if ((opendevice(ipfname, 1) != -2) &&
204 	    (ioctl(fd, SIOCGETFF, &i) == -1)) {
205 		ipferror(fd, "SIOCGETFF");
206 		return (0);
207 	}
208 	return (i);
209 }
210 
211 
212 static void
213 set_state(u_int enable)
214 {
215 	if (opendevice(ipfname, 0) != -2) {
216 		if (ioctl(fd, SIOCFRENB, &enable) == -1) {
217 			if (errno == EBUSY) {
218 				fprintf(stderr,
219 					"IP FIlter: already initialized\n");
220 			} else {
221 				ipferror(fd, "SIOCFRENB");
222 			}
223 		}
224 	}
225 	return;
226 }
227 
228 
229 static void
230 procfile(char *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 int
247 ipf_interceptadd(int fd, ioctlfunc_t ioctlfunc, void *ptr)
248 {
249 	if (outputc)
250 		printc(ptr);
251 
252 	if (ipf_addrule(fd, ioctlfunc, ptr) != 0)
253 		exitstatus = 1;
254 	return (0);
255 }
256 
257 
258 static void
259 packetlogon(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") || strchr(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 			ipferror(fd, "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 				ipferror(fd, "ioctl(SIOCGETLG)");
314 			else {
315 				logopt = 1 - logopt;
316 				if (ioctl(xfd, SIOCSETLG, &logopt))
317 					ipferror(xfd, "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 				ipferror(xfd, "ioctl(SIOCGETLG)");
331 			else {
332 				logopt = 1 - logopt;
333 				if (ioctl(xfd, SIOCSETLG, &logopt))
334 					ipferror(xfd, "ioctl(SIOCSETLG)");
335 			}
336 			close(xfd);
337 		}
338 	}
339 }
340 
341 
342 static void
343 flushfilter(char *arg, int *filter)
344 {
345 	int	fl = 0, rem;
346 
347 	if (!arg || !*arg)
348 		return;
349 	if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
350 		if (*arg == 'S')
351 			fl = 0;
352 		else if (*arg == 's')
353 			fl = 1;
354 		else
355 			fl = atoi(arg);
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 				fprintf(stderr,
365 					"IPv6 rules are no longer separate\n");
366 			} else if (filter != NULL) {
367 				ipfobj_t obj;
368 
369 				obj.ipfo_rev = IPFILTER_VERSION;
370 				obj.ipfo_size = filter[0] * sizeof(int);
371 				obj.ipfo_type = IPFOBJ_IPFEXPR;
372 				obj.ipfo_ptr = filter;
373 				if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
374 					ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
375 					fl = -1;
376 				} else {
377 					fl = obj.ipfo_retval;
378 				}
379 			} else {
380 				if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
381 					ipferror(fd, "ioctl(SIOCIPFFL)");
382 					exit(1);
383 				}
384 			}
385 		}
386 		if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
387 			printf("remove flags %s (%d)\n", arg, rem);
388 		}
389 		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
390 			printf("%d state entries removed\n", fl);
391 		}
392 		closedevice();
393 		return;
394 	} else if (strchr(arg, 'i') || strchr(arg, 'I'))
395 		fl = FR_INQUE;
396 	else if (strchr(arg, 'o') || strchr(arg, 'O'))
397 		fl = FR_OUTQUE;
398 	else if (strchr(arg, 'a') || strchr(arg, 'A'))
399 		fl = FR_OUTQUE|FR_INQUE;
400 	else {
401 		fprintf(stderr, "Incorrect flush argument: %s\n", arg);
402 		usage();
403 	}
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 				ipferror(fd, "ioctl(SIOCIPFL6)");
415 				exit(1);
416 			}
417 		} else {
418 			if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
419 				ipferror(fd, "ioctl(SIOCIPFFL)");
420 				exit(1);
421 			}
422 		}
423 	}
424 
425 	if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
426 		printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
427 			(rem & FR_OUTQUE) ? "O" : "", rem);
428 	}
429 	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
430 		printf("%d filter rules removed\n", fl);
431 	}
432 	return;
433 }
434 
435 
436 static void
437 swapactive(void)
438 {
439 	int in = 2;
440 
441 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
442 		ipferror(fd, "ioctl(SIOCSWAPA)");
443 	else
444 		printf("Set %d now inactive\n", in);
445 }
446 
447 
448 void
449 ipf_frsync(void)
450 {
451 	int frsyn = 0;
452 
453 	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
454 		ipferror(fd, "SIOCFRSYN");
455 	else
456 		printf("filter sync'd\n");
457 }
458 
459 
460 void
461 zerostats(void)
462 {
463 	ipfobj_t	obj;
464 	friostat_t	fio;
465 
466 	obj.ipfo_rev = IPFILTER_VERSION;
467 	obj.ipfo_type = IPFOBJ_IPFSTAT;
468 	obj.ipfo_size = sizeof(fio);
469 	obj.ipfo_ptr = &fio;
470 	obj.ipfo_offset = 0;
471 
472 	if (opendevice(ipfname, 1) != -2) {
473 		if (ioctl(fd, SIOCFRZST, &obj) == -1) {
474 			ipferror(fd, "ioctl(SIOCFRZST)");
475 			exit(-1);
476 		}
477 		showstats(&fio);
478 	}
479 
480 }
481 
482 
483 /*
484  * read the kernel stats for packets blocked and passed
485  */
486 static void
487 showstats(friostat_t *fp)
488 {
489 	printf("bad packets:\t\tin %lu\tout %lu\n",
490 			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
491 	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
492 			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
493 			fp->f_st[0].fr_nom);
494 	printf(" counted %lu\n", fp->f_st[0].fr_acct);
495 	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
496 			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
497 			fp->f_st[1].fr_nom);
498 	printf(" counted %lu\n", fp->f_st[0].fr_acct);
499 	printf(" input packets logged:\tblocked %lu passed %lu\n",
500 			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
501 	printf("output packets logged:\tblocked %lu passed %lu\n",
502 			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
503 }
504 
505 
506 static int
507 showversion(void)
508 {
509 	struct friostat fio;
510 	ipfobj_t ipfo;
511 	u_32_t flags;
512 	char *s;
513 	int vfd;
514 
515 	bzero((caddr_t)&ipfo, sizeof(ipfo));
516 	ipfo.ipfo_rev = IPFILTER_VERSION;
517 	ipfo.ipfo_size = sizeof(fio);
518 	ipfo.ipfo_ptr = (void *)&fio;
519 	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
520 
521 	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
522 
523 	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
524 		perror("open device");
525 		return (1);
526 	}
527 
528 	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
529 		ipferror(vfd, "ioctl(SIOCGETFS)");
530 		close(vfd);
531 		return (1);
532 	}
533 	close(vfd);
534 	flags = get_flags();
535 
536 	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
537 		(int)sizeof(fio.f_version), fio.f_version);
538 	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
539 	printf("Log Flags: %#x = ", flags);
540 	s = "";
541 	if (flags & FF_LOGPASS) {
542 		printf("pass");
543 		s = ", ";
544 	}
545 	if (flags & FF_LOGBLOCK) {
546 		printf("%sblock", s);
547 		s = ", ";
548 	}
549 	if (flags & FF_LOGNOMATCH) {
550 		printf("%snomatch", s);
551 		s = ", ";
552 	}
553 	if (flags & FF_BLOCKNONIP) {
554 		printf("%snonip", s);
555 		s = ", ";
556 	}
557 	if (!*s)
558 		printf("none set");
559 	putchar('\n');
560 
561 	printf("Default: ");
562 	if (FR_ISPASS(fio.f_defpass))
563 		s = "pass";
564 	else if (FR_ISBLOCK(fio.f_defpass))
565 		s = "block";
566 	else
567 		s = "nomatch -> block";
568 	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
569 	printf("Active list: %d\n", fio.f_active);
570 	printf("Feature mask: %#x\n", fio.f_features);
571 
572 	return (0);
573 }
574