Home | History | Annotate | Line # | Download | only in tools
ipnat.c revision 1.1.1.1
      1 /*	$NetBSD: ipnat.c,v 1.1.1.1 2012/03/23 21:20:25 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2011 by Darren Reed.
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  *
      8  * Added redirect stuff and a variety of bug fixes. (mcn (at) EnGarde.com)
      9  */
     10 #include <stdio.h>
     11 #include <string.h>
     12 #include <fcntl.h>
     13 #include <errno.h>
     14 #include <sys/types.h>
     15 #if !defined(__SVR4) && !defined(__svr4__)
     16 #include <strings.h>
     17 #else
     18 #include <sys/byteorder.h>
     19 #endif
     20 #include <sys/time.h>
     21 #include <sys/param.h>
     22 #include <stdlib.h>
     23 #include <unistd.h>
     24 #include <stddef.h>
     25 #include <sys/file.h>
     26 #define _KERNEL
     27 #include <sys/uio.h>
     28 #undef _KERNEL
     29 #include <sys/socket.h>
     30 #include <sys/ioctl.h>
     31 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
     32 # include <sys/ioccom.h>
     33 # include <sys/sysmacros.h>
     34 #endif
     35 #include <netinet/in.h>
     36 #include <netinet/in_systm.h>
     37 #include <netinet/ip.h>
     38 #include <netinet/tcp.h>
     39 #include <net/if.h>
     40 #if __FreeBSD_version >= 300000
     41 # include <net/if_var.h>
     42 #endif
     43 #include <netdb.h>
     44 #include <arpa/nameser.h>
     45 #include <arpa/inet.h>
     46 #include <resolv.h>
     47 #include <ctype.h>
     48 #if defined(linux)
     49 # include <linux/a.out.h>
     50 #else
     51 # include <nlist.h>
     52 #endif
     53 #include "ipf.h"
     54 #include "netinet/ipl.h"
     55 #include "kmem.h"
     56 
     57 #ifdef	__hpux
     58 # define	nlist	nlist64
     59 #endif
     60 
     61 #if	defined(sun) && !SOLARIS2
     62 # define	STRERROR(x)	sys_errlist[x]
     63 extern	char	*sys_errlist[];
     64 #else
     65 # define	STRERROR(x)	strerror(x)
     66 #endif
     67 
     68 #if !defined(lint)
     69 static const char sccsid[] ="@(#)ipnat.c	1.9 6/5/96 (C) 1993 Darren Reed";
     70 static const char rcsid[] = "@(#)Id";
     71 #endif
     72 
     73 
     74 #if	SOLARIS
     75 #define	bzero(a,b)	memset(a,0,b)
     76 #endif
     77 int	use_inet6 = 0;
     78 char	thishost[MAXHOSTNAMELEN];
     79 
     80 extern	char	*optarg;
     81 
     82 void	dostats __P((int, natstat_t *, int, int, int *));
     83 void	dotable __P((natstat_t *, int, int, int, char *));
     84 void	flushtable __P((int, int, int *));
     85 void	usage __P((char *));
     86 int	main __P((int, char*[]));
     87 void	showhostmap __P((natstat_t *nsp));
     88 void	natstat_dead __P((natstat_t *, char *));
     89 void	dostats_live __P((int, natstat_t *, int, int *));
     90 void	showhostmap_dead __P((natstat_t *));
     91 void	showhostmap_live __P((int, natstat_t *));
     92 void	dostats_dead __P((natstat_t *, int, int *));
     93 int	nat_matcharray __P((nat_t *, int *));
     94 
     95 int		opts;
     96 int		nohdrfields = 0;
     97 wordtab_t	*nat_fields = NULL;
     98 
     99 void usage(name)
    100 	char *name;
    101 {
    102 	fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name);
    103 	exit(1);
    104 }
    105 
    106 
    107 int main(argc, argv)
    108 	int argc;
    109 	char *argv[];
    110 {
    111 	int fd, c, mode, *natfilter;
    112 	char *file, *core, *kernel;
    113 	natstat_t ns, *nsp;
    114 	ipfobj_t obj;
    115 
    116 	fd = -1;
    117 	opts = 0;
    118 	nsp = &ns;
    119 	file = NULL;
    120 	core = NULL;
    121 	kernel = NULL;
    122 	mode = O_RDWR;
    123 	natfilter = NULL;
    124 
    125 	assigndefined(getenv("IPNAT_PREDEFINED"));
    126 
    127 	while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:rRsv")) != -1)
    128 		switch (c)
    129 		{
    130 		case 'C' :
    131 			opts |= OPT_CLEAR;
    132 			break;
    133 		case 'd' :
    134 			opts |= OPT_DEBUG;
    135 			break;
    136 		case 'f' :
    137 			file = optarg;
    138 			break;
    139 		case 'F' :
    140 			opts |= OPT_FLUSH;
    141 			break;
    142 		case 'h' :
    143 			opts |=OPT_HITS;
    144 			break;
    145 		case 'l' :
    146 			opts |= OPT_LIST;
    147 			mode = O_RDONLY;
    148 			break;
    149 		case 'm' :
    150 			natfilter = parseipfexpr(optarg, NULL);
    151 			break;
    152 		case 'M' :
    153 			core = optarg;
    154 			break;
    155 		case 'N' :
    156 			kernel = optarg;
    157 			break;
    158 		case 'n' :
    159 			opts |= OPT_DONOTHING|OPT_DONTOPEN;
    160 			mode = O_RDONLY;
    161 			break;
    162 		case 'O' :
    163 			nat_fields = parsefields(natfields, optarg);
    164 			break;
    165 		case 'R' :
    166 			opts |= OPT_NORESOLVE;
    167 			break;
    168 		case 'r' :
    169 			opts |= OPT_REMOVE;
    170 			break;
    171 		case 's' :
    172 			opts |= OPT_STAT;
    173 			mode = O_RDONLY;
    174 			break;
    175 		case 'v' :
    176 			opts |= OPT_VERBOSE;
    177 			break;
    178 		default :
    179 			usage(argv[0]);
    180 		}
    181 
    182 	initparse();
    183 
    184 	if ((kernel != NULL) || (core != NULL)) {
    185 		(void) setgid(getgid());
    186 		(void) setuid(getuid());
    187 	}
    188 
    189 	if (!(opts & OPT_DONOTHING)) {
    190 		if (((fd = open(IPNAT_NAME, mode)) == -1) &&
    191 		    ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
    192 			(void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
    193 				STRERROR(errno));
    194 			exit(1);
    195 		}
    196 	}
    197 
    198 	bzero((char *)&ns, sizeof(ns));
    199 
    200 	if ((opts & OPT_DONOTHING) == 0) {
    201 		if (checkrev(IPL_NAME) == -1) {
    202 			fprintf(stderr, "User/kernel version check failed\n");
    203 			exit(1);
    204 		}
    205 	}
    206 
    207 	if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
    208 		bzero((char *)&obj, sizeof(obj));
    209 		obj.ipfo_rev = IPFILTER_VERSION;
    210 		obj.ipfo_type = IPFOBJ_NATSTAT;
    211 		obj.ipfo_size = sizeof(*nsp);
    212 		obj.ipfo_ptr = (void *)nsp;
    213 		if (ioctl(fd, SIOCGNATS, &obj) == -1) {
    214 			ipferror(fd, "ioctl(SIOCGNATS)");
    215 			exit(1);
    216 		}
    217 		(void) setgid(getgid());
    218 		(void) setuid(getuid());
    219 	} else if ((kernel != NULL) || (core != NULL)) {
    220 		if (openkmem(kernel, core) == -1)
    221 			exit(1);
    222 
    223 		natstat_dead(nsp, kernel);
    224 		if (opts & (OPT_LIST|OPT_STAT))
    225 			dostats(fd, nsp, opts, 0, natfilter);
    226 		exit(0);
    227 	}
    228 
    229 	if (opts & (OPT_FLUSH|OPT_CLEAR))
    230 		flushtable(fd, opts, natfilter);
    231 	if (file) {
    232 		ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
    233 	}
    234 	if (opts & (OPT_LIST|OPT_STAT))
    235 		dostats(fd, nsp, opts, 1, natfilter);
    236 	return 0;
    237 }
    238 
    239 
    240 /*
    241  * Read NAT statistic information in using a symbol table and memory file
    242  * rather than doing ioctl's.
    243  */
    244 void natstat_dead(nsp, kernel)
    245 	natstat_t *nsp;
    246 	char *kernel;
    247 {
    248 	struct nlist nat_nlist[10] = {
    249 		{ "nat_table" },		/* 0 */
    250 		{ "nat_list" },
    251 		{ "maptable" },
    252 		{ "ipf_nattable_sz" },
    253 		{ "ipf_natrules_sz" },
    254 		{ "ipf_rdrrules_sz" },		/* 5 */
    255 		{ "ipf_hostmap_sz" },
    256 		{ "nat_instances" },
    257 		{ NULL }
    258 	};
    259 	void *tables[2];
    260 
    261 	if (nlist(kernel, nat_nlist) == -1) {
    262 		fprintf(stderr, "nlist error\n");
    263 		return;
    264 	}
    265 
    266 	/*
    267 	 * Normally the ioctl copies all of these values into the structure
    268 	 * for us, before returning it to userland, so here we must copy each
    269 	 * one in individually.
    270 	 */
    271 	kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables));
    272 	nsp->ns_side[0].ns_table = tables[0];
    273 	nsp->ns_side[1].ns_table = tables[1];
    274 
    275 	kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
    276 		sizeof(nsp->ns_list));
    277 	kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
    278 		sizeof(nsp->ns_maptable));
    279 	kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
    280 		sizeof(nsp->ns_nattab_sz));
    281 	kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
    282 		sizeof(nsp->ns_rultab_sz));
    283 	kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
    284 		sizeof(nsp->ns_rdrtab_sz));
    285 	kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
    286 		sizeof(nsp->ns_hostmap_sz));
    287 	kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
    288 		sizeof(nsp->ns_instances));
    289 }
    290 
    291 
    292 /*
    293  * Issue an ioctl to flush either the NAT rules table or the active mapping
    294  * table or both.
    295  */
    296 void flushtable(fd, opts, match)
    297 	int fd, opts, *match;
    298 {
    299 	int n = 0;
    300 
    301 	if (opts & OPT_FLUSH) {
    302 		n = 0;
    303 		if (!(opts & OPT_DONOTHING)) {
    304 			if (match != NULL) {
    305 				ipfobj_t obj;
    306 
    307 				obj.ipfo_rev = IPFILTER_VERSION;
    308 				obj.ipfo_size = match[0] * sizeof(int);
    309 				obj.ipfo_type = IPFOBJ_IPFEXPR;
    310 				obj.ipfo_ptr = match;
    311 				if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
    312 					ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
    313 					n = -1;
    314 				} else {
    315 					n = obj.ipfo_retval;
    316 				}
    317 			} else if (ioctl(fd, SIOCIPFFL, &n) == -1) {
    318 				ipferror(fd, "ioctl(SIOCIPFFL)");
    319 				n = -1;
    320 			}
    321 		}
    322 		if (n >= 0)
    323 			printf("%d entries flushed from NAT table\n", n);
    324 	}
    325 
    326 	if (opts & OPT_CLEAR) {
    327 		n = 1;
    328 		if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
    329 			ipferror(fd, "ioctl(SIOCCNATL)");
    330 		else
    331 			printf("%d entries flushed from NAT list\n", n);
    332 	}
    333 }
    334 
    335 
    336 /*
    337  * Display NAT statistics.
    338  */
    339 void dostats_dead(nsp, opts, filter)
    340 	natstat_t *nsp;
    341 	int opts, *filter;
    342 {
    343 	nat_t *np, nat;
    344 	ipnat_t	ipn;
    345 	int i;
    346 
    347 	if (nat_fields == NULL) {
    348 		printf("List of active MAP/Redirect filters:\n");
    349 		while (nsp->ns_list) {
    350 			if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
    351 				    sizeof(ipn))) {
    352 				perror("kmemcpy");
    353 				break;
    354 			}
    355 			if (opts & OPT_HITS)
    356 				printf("%lu ", ipn.in_hits);
    357 			printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
    358 			nsp->ns_list = ipn.in_next;
    359 		}
    360 	}
    361 
    362 	if (nat_fields == NULL) {
    363 		printf("\nList of active sessions:\n");
    364 
    365 	} else if (nohdrfields == 0) {
    366 		for (i = 0; nat_fields[i].w_value != 0; i++) {
    367 			printfieldhdr(natfields, nat_fields + i);
    368 			if (nat_fields[i + 1].w_value != 0)
    369 				printf("\t");
    370 		}
    371 		printf("\n");
    372 	}
    373 
    374 	for (np = nsp->ns_instances; np; np = nat.nat_next) {
    375 		if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
    376 			break;
    377 		if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
    378 			continue;
    379 		if (nat_fields != NULL) {
    380 			for (i = 0; nat_fields[i].w_value != 0; i++) {
    381 				printnatfield(&nat, nat_fields[i].w_value);
    382 				if (nat_fields[i + 1].w_value != 0)
    383 					printf("\t");
    384 			}
    385 			printf("\n");
    386 		} else {
    387 			printactivenat(&nat, opts, nsp->ns_ticks);
    388 			if (nat.nat_aps) {
    389 				int proto;
    390 
    391 				if (nat.nat_dir & NAT_OUTBOUND)
    392 					proto = nat.nat_pr[1];
    393 				else
    394 					proto = nat.nat_pr[0];
    395 				printaps(nat.nat_aps, opts, proto);
    396 			}
    397 		}
    398 	}
    399 
    400 	if (opts & OPT_VERBOSE)
    401 		showhostmap_dead(nsp);
    402 }
    403 
    404 
    405 void dotable(nsp, fd, alive, which, side)
    406 	natstat_t *nsp;
    407 	int fd, alive, which;
    408 	char *side;
    409 {
    410 	int sz, i, used, maxlen, minlen, totallen;
    411 	ipftable_t table;
    412 	u_int *buckets;
    413 	ipfobj_t obj;
    414 
    415 	sz = sizeof(*buckets) * nsp->ns_nattab_sz;
    416 	buckets = (u_int *)malloc(sz);
    417 	if (buckets == NULL) {
    418 		fprintf(stderr,
    419 			"cannot allocate memory (%d) for buckets\n", sz);
    420 		return;
    421 	}
    422 
    423 	obj.ipfo_rev = IPFILTER_VERSION;
    424 	obj.ipfo_type = IPFOBJ_GTABLE;
    425 	obj.ipfo_size = sizeof(table);
    426 	obj.ipfo_ptr = &table;
    427 
    428 	if (which == 0) {
    429 		table.ita_type = IPFTABLE_BUCKETS_NATIN;
    430 	} else if (which == 1) {
    431 		table.ita_type = IPFTABLE_BUCKETS_NATOUT;
    432 	}
    433 	table.ita_table = buckets;
    434 
    435 	if (alive) {
    436 		if (ioctl(fd, SIOCGTABL, &obj) != 0) {
    437 			perror("SIOCFTABL");
    438 			free(buckets);
    439 			return;
    440 		}
    441 	} else {
    442 		if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) {
    443 			free(buckets);
    444 			return;
    445 		}
    446 	}
    447 
    448 	minlen = nsp->ns_side[which].ns_inuse;
    449 	totallen = 0;
    450 	maxlen = 0;
    451 	used = 0;
    452 
    453 	for (i = 0; i < nsp->ns_nattab_sz; i++) {
    454 		if (buckets[i] > maxlen)
    455 			maxlen = buckets[i];
    456 		if (buckets[i] < minlen)
    457 			minlen = buckets[i];
    458 		if (buckets[i] != 0)
    459 			used++;
    460 		totallen += buckets[i];
    461 	}
    462 
    463 	printf("%d%%\thash efficiency %s\n",
    464 	       totallen ? used * 100 / totallen : 0, side);
    465 	printf("%2.2f%%\tbucket usage %s\n",
    466 	       ((float)used / nsp->ns_nattab_sz) * 100.0, side);
    467 	printf("%d\tminimal length %s\n", minlen, side);
    468 	printf("%d\tmaximal length %s\n", maxlen, side);
    469 	printf("%.3f\taverage length %s\n",
    470 	       used ? ((float)totallen / used) : 0.0, side);
    471 
    472 	free(buckets);
    473 }
    474 
    475 
    476 void dostats(fd, nsp, opts, alive, filter)
    477 	natstat_t *nsp;
    478 	int fd, opts, alive, *filter;
    479 {
    480 	/*
    481 	 * Show statistics ?
    482 	 */
    483 	if (opts & OPT_STAT) {
    484 		printnatside("in", nsp, &nsp->ns_side[0]);
    485 		dotable(nsp, fd, alive, 0, "in");
    486 
    487 		printnatside("out", nsp, &nsp->ns_side[1]);
    488 		dotable(nsp, fd, alive, 1, "out");
    489 
    490 		printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log);
    491 		printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log);
    492 		printf("%lu\tadded in\n%lu\tadded out\n",
    493 			nsp->ns_side[0].ns_added,
    494 			nsp->ns_side[1].ns_added);
    495 		printf("%lu\texpired\n", nsp->ns_expire);
    496 		printf("%u\twilds\n", nsp->ns_wilds);
    497 		if (opts & OPT_VERBOSE)
    498 			printf("list %p\n", nsp->ns_list);
    499 	}
    500 
    501 	if (opts & OPT_LIST) {
    502 		if (alive)
    503 			dostats_live(fd, nsp, opts, filter);
    504 		else
    505 			dostats_dead(nsp, opts, filter);
    506 	}
    507 }
    508 
    509 
    510 /*
    511  * Display NAT statistics.
    512  */
    513 void dostats_live(fd, nsp, opts, filter)
    514 	natstat_t *nsp;
    515 	int fd, opts, *filter;
    516 {
    517 	ipfgeniter_t iter;
    518 	char buffer[2000];
    519 	ipfobj_t obj;
    520 	ipnat_t	*ipn;
    521 	nat_t nat;
    522 	int i;
    523 
    524 	bzero((char *)&obj, sizeof(obj));
    525 	obj.ipfo_rev = IPFILTER_VERSION;
    526 	obj.ipfo_type = IPFOBJ_GENITER;
    527 	obj.ipfo_size = sizeof(iter);
    528 	obj.ipfo_ptr = &iter;
    529 
    530 	iter.igi_type = IPFGENITER_IPNAT;
    531 	iter.igi_nitems = 1;
    532 	iter.igi_data = buffer;
    533 	ipn = (ipnat_t *)buffer;
    534 
    535 	/*
    536 	 * Show list of NAT rules and NAT sessions ?
    537 	 */
    538 	if (nat_fields == NULL) {
    539 		printf("List of active MAP/Redirect filters:\n");
    540 		while (nsp->ns_list) {
    541 			if (ioctl(fd, SIOCGENITER, &obj) == -1)
    542 				break;
    543 			if (opts & OPT_HITS)
    544 				printf("%lu ", ipn->in_hits);
    545 			printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
    546 			nsp->ns_list = ipn->in_next;
    547 		}
    548 	}
    549 
    550 	if (nat_fields == NULL) {
    551 		printf("\nList of active sessions:\n");
    552 
    553 	} else if (nohdrfields == 0) {
    554 		for (i = 0; nat_fields[i].w_value != 0; i++) {
    555 			printfieldhdr(natfields, nat_fields + i);
    556 			if (nat_fields[i + 1].w_value != 0)
    557 				printf("\t");
    558 		}
    559 		printf("\n");
    560 	}
    561 
    562 	i = IPFGENITER_IPNAT;
    563 	(void) ioctl(fd,SIOCIPFDELTOK, &i);
    564 
    565 
    566 	iter.igi_type = IPFGENITER_NAT;
    567 	iter.igi_nitems = 1;
    568 	iter.igi_data = &nat;
    569 
    570 	while (nsp->ns_instances != NULL) {
    571 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
    572 			break;
    573 		if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
    574 			continue;
    575 		if (nat_fields != NULL) {
    576 			for (i = 0; nat_fields[i].w_value != 0; i++) {
    577 				printnatfield(&nat, nat_fields[i].w_value);
    578 				if (nat_fields[i + 1].w_value != 0)
    579 					printf("\t");
    580 			}
    581 			printf("\n");
    582 		} else {
    583 			printactivenat(&nat, opts, nsp->ns_ticks);
    584 			if (nat.nat_aps) {
    585 				int proto;
    586 
    587 				if (nat.nat_dir & NAT_OUTBOUND)
    588 					proto = nat.nat_pr[1];
    589 				else
    590 					proto = nat.nat_pr[0];
    591 				printaps(nat.nat_aps, opts, proto);
    592 			}
    593 		}
    594 		nsp->ns_instances = nat.nat_next;
    595 	}
    596 
    597 	if (opts & OPT_VERBOSE)
    598 		showhostmap_live(fd, nsp);
    599 
    600 	i = IPFGENITER_NAT;
    601 	(void) ioctl(fd,SIOCIPFDELTOK, &i);
    602 }
    603 
    604 
    605 /*
    606  * Display the active host mapping table.
    607  */
    608 void showhostmap_dead(nsp)
    609 	natstat_t *nsp;
    610 {
    611 	hostmap_t hm, *hmp, **maptable;
    612 	u_int hv;
    613 
    614 	printf("\nList of active host mappings:\n");
    615 
    616 	maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) *
    617 					nsp->ns_hostmap_sz);
    618 	if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable,
    619 		    sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) {
    620 		perror("kmemcpy (maptable)");
    621 		return;
    622 	}
    623 
    624 	for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
    625 		hmp = maptable[hv];
    626 
    627 		while (hmp) {
    628 			if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) {
    629 				perror("kmemcpy (hostmap)");
    630 				return;
    631 			}
    632 
    633 			printhostmap(&hm, hv);
    634 			hmp = hm.hm_next;
    635 		}
    636 	}
    637 	free(maptable);
    638 }
    639 
    640 
    641 /*
    642  * Display the active host mapping table.
    643  */
    644 void showhostmap_live(fd, nsp)
    645 	int fd;
    646 	natstat_t *nsp;
    647 {
    648 	ipfgeniter_t iter;
    649 	hostmap_t hm;
    650 	ipfobj_t obj;
    651 	int i;
    652 
    653 	bzero((char *)&obj, sizeof(obj));
    654 	obj.ipfo_rev = IPFILTER_VERSION;
    655 	obj.ipfo_type = IPFOBJ_GENITER;
    656 	obj.ipfo_size = sizeof(iter);
    657 	obj.ipfo_ptr = &iter;
    658 
    659 	iter.igi_type = IPFGENITER_HOSTMAP;
    660 	iter.igi_nitems = 1;
    661 	iter.igi_data = &hm;
    662 
    663 	printf("\nList of active host mappings:\n");
    664 
    665 	while (nsp->ns_maplist != NULL) {
    666 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
    667 			break;
    668 		printhostmap(&hm, hm.hm_hv);
    669 		nsp->ns_maplist = hm.hm_next;
    670 	}
    671 
    672 	i = IPFGENITER_HOSTMAP;
    673 	(void) ioctl(fd,SIOCIPFDELTOK, &i);
    674 }
    675 
    676 
    677 int nat_matcharray(nat, array)
    678 	nat_t *nat;
    679 	int *array;
    680 {
    681 	int i, n, *x, e, p;
    682 
    683 	e = 0;
    684 	n = array[0];
    685 	x = array + 1;
    686 
    687 	for (; n > 0; x += 3 + x[3]) {
    688 		if (x[0] == IPF_EXP_END)
    689 			break;
    690 		e = 0;
    691 
    692 		n -= x[3] + 3;
    693 
    694 		p = x[0] >> 16;
    695 		if (p != 0 && p != nat->nat_pr[1])
    696 			break;
    697 
    698 		switch (x[0])
    699 		{
    700 		case IPF_EXP_IP_PR :
    701 			for (i = 0; !e && i < x[3]; i++) {
    702 				e |= (nat->nat_pr[1] == x[i + 3]);
    703 			}
    704 			break;
    705 
    706 		case IPF_EXP_IP_SRCADDR :
    707 			for (i = 0; !e && i < x[3]; i++) {
    708 				e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
    709 				      x[i + 3]);
    710 			}
    711 			break;
    712 
    713 		case IPF_EXP_IP_DSTADDR :
    714 			for (i = 0; !e && i < x[3]; i++) {
    715 				e |= ((nat->nat_ndstaddr & x[i + 4]) ==
    716 				      x[i + 3]);
    717 			}
    718 			break;
    719 
    720 		case IPF_EXP_IP_ADDR :
    721 			for (i = 0; !e && i < x[3]; i++) {
    722 				e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
    723 				      x[i + 3]) ||
    724 				     ((nat->nat_ndstaddr & x[i + 4]) ==
    725 				      x[i + 3]);
    726 			}
    727 			break;
    728 
    729 		case IPF_EXP_UDP_PORT :
    730 		case IPF_EXP_TCP_PORT :
    731 			for (i = 0; !e && i < x[3]; i++) {
    732 				e |= (nat->nat_nsport == x[i + 3]) ||
    733 				     (nat->nat_ndport == x[i + 3]);
    734 			}
    735 			break;
    736 
    737 		case IPF_EXP_UDP_SPORT :
    738 		case IPF_EXP_TCP_SPORT :
    739 			for (i = 0; !e && i < x[3]; i++) {
    740 				e |= (nat->nat_nsport == x[i + 3]);
    741 			}
    742 			break;
    743 
    744 		case IPF_EXP_UDP_DPORT :
    745 		case IPF_EXP_TCP_DPORT :
    746 			for (i = 0; !e && i < x[3]; i++) {
    747 				e |= (nat->nat_ndport == x[i + 3]);
    748 			}
    749 			break;
    750 		}
    751 		e ^= x[2];
    752 
    753 		if (!e)
    754 			break;
    755 	}
    756 
    757 	return e;
    758 }
    759