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