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