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