xref: /netbsd/external/bsd/ipf/dist/tools/ipnat.c (revision f38cfa5b)
1*f38cfa5bSmrg /*	$NetBSD: ipnat.c,v 1.4 2021/04/12 04:09:26 mrg Exp $	*/
226945a25Schristos 
326945a25Schristos /*
4c50c2f6fSdarrenr  * Copyright (C) 2012 by Darren Reed.
526945a25Schristos  *
626945a25Schristos  * See the IPFILTER.LICENCE file for details on licencing.
726945a25Schristos  *
826945a25Schristos  * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
926945a25Schristos  */
1026945a25Schristos #include <stdio.h>
1126945a25Schristos #include <string.h>
1226945a25Schristos #include <fcntl.h>
1326945a25Schristos #include <errno.h>
1426945a25Schristos #include <sys/types.h>
1526945a25Schristos #if !defined(__SVR4) && !defined(__svr4__)
1626945a25Schristos #include <strings.h>
1726945a25Schristos #else
1826945a25Schristos #include <sys/byteorder.h>
1926945a25Schristos #endif
2026945a25Schristos #include <sys/time.h>
2126945a25Schristos #include <sys/param.h>
2226945a25Schristos #include <stdlib.h>
2326945a25Schristos #include <unistd.h>
2426945a25Schristos #include <stddef.h>
2526945a25Schristos #include <sys/file.h>
2626945a25Schristos #define _KERNEL
2726945a25Schristos #include <sys/uio.h>
2826945a25Schristos #undef _KERNEL
2926945a25Schristos #include <sys/socket.h>
3026945a25Schristos #include <sys/ioctl.h>
3126945a25Schristos #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
3226945a25Schristos # include <sys/ioccom.h>
3326945a25Schristos # include <sys/sysmacros.h>
3426945a25Schristos #endif
3526945a25Schristos #include <netinet/in.h>
3626945a25Schristos #include <netinet/in_systm.h>
3726945a25Schristos #include <netinet/ip.h>
3826945a25Schristos #include <netinet/tcp.h>
3926945a25Schristos #include <net/if.h>
4026945a25Schristos #if __FreeBSD_version >= 300000
4126945a25Schristos # include <net/if_var.h>
4226945a25Schristos #endif
4326945a25Schristos #include <netdb.h>
4426945a25Schristos #include <arpa/nameser.h>
4526945a25Schristos #include <arpa/inet.h>
4626945a25Schristos #include <resolv.h>
4726945a25Schristos #include <ctype.h>
4826945a25Schristos #if defined(linux)
4926945a25Schristos # include <linux/a.out.h>
5026945a25Schristos #else
5126945a25Schristos # include <nlist.h>
5226945a25Schristos #endif
5326945a25Schristos #include "ipf.h"
5426945a25Schristos #include "netinet/ipl.h"
5526945a25Schristos #include "kmem.h"
5626945a25Schristos 
5726945a25Schristos #ifdef	__hpux
5826945a25Schristos # define	nlist	nlist64
5926945a25Schristos #endif
6026945a25Schristos 
6126945a25Schristos #if	defined(sun) && !SOLARIS2
6226945a25Schristos # define	STRERROR(x)	sys_errlist[x]
6326945a25Schristos extern	char	*sys_errlist[];
6426945a25Schristos #else
6526945a25Schristos # define	STRERROR(x)	strerror(x)
6626945a25Schristos #endif
6726945a25Schristos 
6826945a25Schristos #if !defined(lint)
698ff8d226Smrg static __attribute__((__used__)) const char sccsid[] ="@(#)ipnat.c	1.9 6/5/96 (C) 1993 Darren Reed";
708ff8d226Smrg static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipnat.c,v 1.1.1.2 2012/07/22 13:44:56 darrenr Exp $";
7126945a25Schristos #endif
7226945a25Schristos 
7326945a25Schristos 
7426945a25Schristos #if	SOLARIS
7526945a25Schristos #define	bzero(a,b)	memset(a,0,b)
7626945a25Schristos #endif
7726945a25Schristos int	use_inet6 = 0;
7826945a25Schristos 
7926945a25Schristos extern	char	*optarg;
8026945a25Schristos 
8126945a25Schristos void	dostats __P((int, natstat_t *, int, int, int *));
8226945a25Schristos void	dotable __P((natstat_t *, int, int, int, char *));
8326945a25Schristos void	flushtable __P((int, int, int *));
8426945a25Schristos void	usage __P((char *));
8526945a25Schristos int	main __P((int, char*[]));
8626945a25Schristos void	showhostmap __P((natstat_t *nsp));
8726945a25Schristos void	natstat_dead __P((natstat_t *, char *));
8826945a25Schristos void	dostats_live __P((int, natstat_t *, int, int *));
8926945a25Schristos void	showhostmap_dead __P((natstat_t *));
9026945a25Schristos void	showhostmap_live __P((int, natstat_t *));
9126945a25Schristos void	dostats_dead __P((natstat_t *, int, int *));
9226945a25Schristos int	nat_matcharray __P((nat_t *, int *));
9326945a25Schristos 
9426945a25Schristos int		opts;
9526945a25Schristos int		nohdrfields = 0;
9626945a25Schristos wordtab_t	*nat_fields = NULL;
9726945a25Schristos 
usage(name)9826945a25Schristos void usage(name)
9926945a25Schristos 	char *name;
10026945a25Schristos {
10126945a25Schristos 	fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name);
10226945a25Schristos 	exit(1);
10326945a25Schristos }
10426945a25Schristos 
10526945a25Schristos 
main(argc,argv)10626945a25Schristos int main(argc, argv)
10726945a25Schristos 	int argc;
10826945a25Schristos 	char *argv[];
10926945a25Schristos {
11026945a25Schristos 	int fd, c, mode, *natfilter;
11126945a25Schristos 	char *file, *core, *kernel;
11226945a25Schristos 	natstat_t ns, *nsp;
11326945a25Schristos 	ipfobj_t obj;
11426945a25Schristos 
11526945a25Schristos 	fd = -1;
11626945a25Schristos 	opts = 0;
11726945a25Schristos 	nsp = &ns;
11826945a25Schristos 	file = NULL;
11926945a25Schristos 	core = NULL;
12026945a25Schristos 	kernel = NULL;
12126945a25Schristos 	mode = O_RDWR;
12226945a25Schristos 	natfilter = NULL;
12326945a25Schristos 
12426945a25Schristos 	assigndefined(getenv("IPNAT_PREDEFINED"));
12526945a25Schristos 
126c50c2f6fSdarrenr 	while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:prRsv")) != -1)
12726945a25Schristos 		switch (c)
12826945a25Schristos 		{
12926945a25Schristos 		case 'C' :
13026945a25Schristos 			opts |= OPT_CLEAR;
13126945a25Schristos 			break;
13226945a25Schristos 		case 'd' :
13326945a25Schristos 			opts |= OPT_DEBUG;
13426945a25Schristos 			break;
13526945a25Schristos 		case 'f' :
13626945a25Schristos 			file = optarg;
13726945a25Schristos 			break;
13826945a25Schristos 		case 'F' :
13926945a25Schristos 			opts |= OPT_FLUSH;
14026945a25Schristos 			break;
14126945a25Schristos 		case 'h' :
14226945a25Schristos 			opts |=OPT_HITS;
14326945a25Schristos 			break;
14426945a25Schristos 		case 'l' :
14526945a25Schristos 			opts |= OPT_LIST;
14626945a25Schristos 			mode = O_RDONLY;
14726945a25Schristos 			break;
14826945a25Schristos 		case 'm' :
14926945a25Schristos 			natfilter = parseipfexpr(optarg, NULL);
15026945a25Schristos 			break;
15126945a25Schristos 		case 'M' :
15226945a25Schristos 			core = optarg;
15326945a25Schristos 			break;
15426945a25Schristos 		case 'N' :
15526945a25Schristos 			kernel = optarg;
15626945a25Schristos 			break;
15726945a25Schristos 		case 'n' :
15826945a25Schristos 			opts |= OPT_DONOTHING|OPT_DONTOPEN;
15926945a25Schristos 			mode = O_RDONLY;
16026945a25Schristos 			break;
16126945a25Schristos 		case 'O' :
16226945a25Schristos 			nat_fields = parsefields(natfields, optarg);
16326945a25Schristos 			break;
164c50c2f6fSdarrenr 		case 'p' :
165c50c2f6fSdarrenr 			opts |= OPT_PURGE;
166c50c2f6fSdarrenr 			break;
16726945a25Schristos 		case 'R' :
16826945a25Schristos 			opts |= OPT_NORESOLVE;
16926945a25Schristos 			break;
17026945a25Schristos 		case 'r' :
17126945a25Schristos 			opts |= OPT_REMOVE;
17226945a25Schristos 			break;
17326945a25Schristos 		case 's' :
17426945a25Schristos 			opts |= OPT_STAT;
17526945a25Schristos 			mode = O_RDONLY;
17626945a25Schristos 			break;
17726945a25Schristos 		case 'v' :
17826945a25Schristos 			opts |= OPT_VERBOSE;
17926945a25Schristos 			break;
18026945a25Schristos 		default :
18126945a25Schristos 			usage(argv[0]);
18226945a25Schristos 		}
18326945a25Schristos 
184c50c2f6fSdarrenr 	if (((opts & OPT_PURGE) != 0) && ((opts & OPT_REMOVE) == 0)) {
185c50c2f6fSdarrenr 		(void) fprintf(stderr, "%s: -p must be used with -r\n",
186c50c2f6fSdarrenr 			       argv[0]);
187c50c2f6fSdarrenr 		exit(1);
188c50c2f6fSdarrenr 	}
189c50c2f6fSdarrenr 
19026945a25Schristos 	initparse();
19126945a25Schristos 
19226945a25Schristos 	if ((kernel != NULL) || (core != NULL)) {
19326945a25Schristos 		(void) setgid(getgid());
19426945a25Schristos 		(void) setuid(getuid());
19526945a25Schristos 	}
19626945a25Schristos 
19726945a25Schristos 	if (!(opts & OPT_DONOTHING)) {
19826945a25Schristos 		if (((fd = open(IPNAT_NAME, mode)) == -1) &&
19926945a25Schristos 		    ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
20026945a25Schristos 			(void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
20126945a25Schristos 				STRERROR(errno));
20226945a25Schristos 			exit(1);
20326945a25Schristos 		}
20426945a25Schristos 	}
20526945a25Schristos 
20626945a25Schristos 	bzero((char *)&ns, sizeof(ns));
20726945a25Schristos 
20826945a25Schristos 	if ((opts & OPT_DONOTHING) == 0) {
20926945a25Schristos 		if (checkrev(IPL_NAME) == -1) {
21026945a25Schristos 			fprintf(stderr, "User/kernel version check failed\n");
21126945a25Schristos 			exit(1);
21226945a25Schristos 		}
21326945a25Schristos 	}
21426945a25Schristos 
21526945a25Schristos 	if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
21626945a25Schristos 		bzero((char *)&obj, sizeof(obj));
21726945a25Schristos 		obj.ipfo_rev = IPFILTER_VERSION;
21826945a25Schristos 		obj.ipfo_type = IPFOBJ_NATSTAT;
21926945a25Schristos 		obj.ipfo_size = sizeof(*nsp);
22026945a25Schristos 		obj.ipfo_ptr = (void *)nsp;
22126945a25Schristos 		if (ioctl(fd, SIOCGNATS, &obj) == -1) {
22226945a25Schristos 			ipferror(fd, "ioctl(SIOCGNATS)");
22326945a25Schristos 			exit(1);
22426945a25Schristos 		}
22526945a25Schristos 		(void) setgid(getgid());
22626945a25Schristos 		(void) setuid(getuid());
22726945a25Schristos 	} else if ((kernel != NULL) || (core != NULL)) {
22826945a25Schristos 		if (openkmem(kernel, core) == -1)
22926945a25Schristos 			exit(1);
23026945a25Schristos 
23126945a25Schristos 		natstat_dead(nsp, kernel);
23226945a25Schristos 		if (opts & (OPT_LIST|OPT_STAT))
23326945a25Schristos 			dostats(fd, nsp, opts, 0, natfilter);
23426945a25Schristos 		exit(0);
23526945a25Schristos 	}
23626945a25Schristos 
23726945a25Schristos 	if (opts & (OPT_FLUSH|OPT_CLEAR))
23826945a25Schristos 		flushtable(fd, opts, natfilter);
23926945a25Schristos 	if (file) {
240c50c2f6fSdarrenr 		return ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
24126945a25Schristos 	}
24226945a25Schristos 	if (opts & (OPT_LIST|OPT_STAT))
24326945a25Schristos 		dostats(fd, nsp, opts, 1, natfilter);
24426945a25Schristos 	return 0;
24526945a25Schristos }
24626945a25Schristos 
24726945a25Schristos 
24826945a25Schristos /*
24926945a25Schristos  * Read NAT statistic information in using a symbol table and memory file
25026945a25Schristos  * rather than doing ioctl's.
25126945a25Schristos  */
natstat_dead(nsp,kernel)25226945a25Schristos void natstat_dead(nsp, kernel)
25326945a25Schristos 	natstat_t *nsp;
25426945a25Schristos 	char *kernel;
25526945a25Schristos {
25626945a25Schristos 	struct nlist nat_nlist[10] = {
25726945a25Schristos 		{ "nat_table" },		/* 0 */
25826945a25Schristos 		{ "nat_list" },
25926945a25Schristos 		{ "maptable" },
26026945a25Schristos 		{ "ipf_nattable_sz" },
26126945a25Schristos 		{ "ipf_natrules_sz" },
26226945a25Schristos 		{ "ipf_rdrrules_sz" },		/* 5 */
26326945a25Schristos 		{ "ipf_hostmap_sz" },
26426945a25Schristos 		{ "nat_instances" },
26526945a25Schristos 		{ NULL }
26626945a25Schristos 	};
26726945a25Schristos 	void *tables[2];
26826945a25Schristos 
26926945a25Schristos 	if (nlist(kernel, nat_nlist) == -1) {
27026945a25Schristos 		fprintf(stderr, "nlist error\n");
27126945a25Schristos 		return;
27226945a25Schristos 	}
27326945a25Schristos 
27426945a25Schristos 	/*
27526945a25Schristos 	 * Normally the ioctl copies all of these values into the structure
27626945a25Schristos 	 * for us, before returning it to userland, so here we must copy each
27726945a25Schristos 	 * one in individually.
27826945a25Schristos 	 */
27926945a25Schristos 	kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables));
28026945a25Schristos 	nsp->ns_side[0].ns_table = tables[0];
28126945a25Schristos 	nsp->ns_side[1].ns_table = tables[1];
28226945a25Schristos 
28326945a25Schristos 	kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
28426945a25Schristos 		sizeof(nsp->ns_list));
28526945a25Schristos 	kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
28626945a25Schristos 		sizeof(nsp->ns_maptable));
28726945a25Schristos 	kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
28826945a25Schristos 		sizeof(nsp->ns_nattab_sz));
28926945a25Schristos 	kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
29026945a25Schristos 		sizeof(nsp->ns_rultab_sz));
29126945a25Schristos 	kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
29226945a25Schristos 		sizeof(nsp->ns_rdrtab_sz));
29326945a25Schristos 	kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
29426945a25Schristos 		sizeof(nsp->ns_hostmap_sz));
29526945a25Schristos 	kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
29626945a25Schristos 		sizeof(nsp->ns_instances));
29726945a25Schristos }
29826945a25Schristos 
29926945a25Schristos 
30026945a25Schristos /*
30126945a25Schristos  * Issue an ioctl to flush either the NAT rules table or the active mapping
30226945a25Schristos  * table or both.
30326945a25Schristos  */
flushtable(fd,opts,match)30426945a25Schristos void flushtable(fd, opts, match)
30526945a25Schristos 	int fd, opts, *match;
30626945a25Schristos {
30726945a25Schristos 	int n = 0;
30826945a25Schristos 
30926945a25Schristos 	if (opts & OPT_FLUSH) {
31026945a25Schristos 		n = 0;
31126945a25Schristos 		if (!(opts & OPT_DONOTHING)) {
31226945a25Schristos 			if (match != NULL) {
31326945a25Schristos 				ipfobj_t obj;
31426945a25Schristos 
31526945a25Schristos 				obj.ipfo_rev = IPFILTER_VERSION;
31626945a25Schristos 				obj.ipfo_size = match[0] * sizeof(int);
31726945a25Schristos 				obj.ipfo_type = IPFOBJ_IPFEXPR;
31826945a25Schristos 				obj.ipfo_ptr = match;
31926945a25Schristos 				if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
32026945a25Schristos 					ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
32126945a25Schristos 					n = -1;
32226945a25Schristos 				} else {
32326945a25Schristos 					n = obj.ipfo_retval;
32426945a25Schristos 				}
32526945a25Schristos 			} else if (ioctl(fd, SIOCIPFFL, &n) == -1) {
32626945a25Schristos 				ipferror(fd, "ioctl(SIOCIPFFL)");
32726945a25Schristos 				n = -1;
32826945a25Schristos 			}
32926945a25Schristos 		}
33026945a25Schristos 		if (n >= 0)
33126945a25Schristos 			printf("%d entries flushed from NAT table\n", n);
33226945a25Schristos 	}
33326945a25Schristos 
33426945a25Schristos 	if (opts & OPT_CLEAR) {
33526945a25Schristos 		n = 1;
33626945a25Schristos 		if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
33726945a25Schristos 			ipferror(fd, "ioctl(SIOCCNATL)");
33826945a25Schristos 		else
33926945a25Schristos 			printf("%d entries flushed from NAT list\n", n);
34026945a25Schristos 	}
34126945a25Schristos }
34226945a25Schristos 
34326945a25Schristos 
34426945a25Schristos /*
34526945a25Schristos  * Display NAT statistics.
34626945a25Schristos  */
dostats_dead(nsp,opts,filter)34726945a25Schristos void dostats_dead(nsp, opts, filter)
34826945a25Schristos 	natstat_t *nsp;
34926945a25Schristos 	int opts, *filter;
35026945a25Schristos {
35126945a25Schristos 	nat_t *np, nat;
35226945a25Schristos 	ipnat_t	ipn;
35326945a25Schristos 	int i;
35426945a25Schristos 
35526945a25Schristos 	if (nat_fields == NULL) {
35626945a25Schristos 		printf("List of active MAP/Redirect filters:\n");
35726945a25Schristos 		while (nsp->ns_list) {
35826945a25Schristos 			if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
35926945a25Schristos 				    sizeof(ipn))) {
36026945a25Schristos 				perror("kmemcpy");
36126945a25Schristos 				break;
36226945a25Schristos 			}
36326945a25Schristos 			if (opts & OPT_HITS)
36426945a25Schristos 				printf("%lu ", ipn.in_hits);
36526945a25Schristos 			printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
36626945a25Schristos 			nsp->ns_list = ipn.in_next;
36726945a25Schristos 		}
36826945a25Schristos 	}
36926945a25Schristos 
37026945a25Schristos 	if (nat_fields == NULL) {
37126945a25Schristos 		printf("\nList of active sessions:\n");
37226945a25Schristos 
37326945a25Schristos 	} else if (nohdrfields == 0) {
37426945a25Schristos 		for (i = 0; nat_fields[i].w_value != 0; i++) {
37526945a25Schristos 			printfieldhdr(natfields, nat_fields + i);
37626945a25Schristos 			if (nat_fields[i + 1].w_value != 0)
37726945a25Schristos 				printf("\t");
37826945a25Schristos 		}
37926945a25Schristos 		printf("\n");
38026945a25Schristos 	}
38126945a25Schristos 
38226945a25Schristos 	for (np = nsp->ns_instances; np; np = nat.nat_next) {
38326945a25Schristos 		if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
38426945a25Schristos 			break;
38526945a25Schristos 		if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
38626945a25Schristos 			continue;
38726945a25Schristos 		if (nat_fields != NULL) {
38826945a25Schristos 			for (i = 0; nat_fields[i].w_value != 0; i++) {
38926945a25Schristos 				printnatfield(&nat, nat_fields[i].w_value);
39026945a25Schristos 				if (nat_fields[i + 1].w_value != 0)
39126945a25Schristos 					printf("\t");
39226945a25Schristos 			}
39326945a25Schristos 			printf("\n");
39426945a25Schristos 		} else {
39526945a25Schristos 			printactivenat(&nat, opts, nsp->ns_ticks);
39626945a25Schristos 			if (nat.nat_aps) {
39726945a25Schristos 				int proto;
39826945a25Schristos 
39926945a25Schristos 				if (nat.nat_dir & NAT_OUTBOUND)
40026945a25Schristos 					proto = nat.nat_pr[1];
40126945a25Schristos 				else
40226945a25Schristos 					proto = nat.nat_pr[0];
40326945a25Schristos 				printaps(nat.nat_aps, opts, proto);
40426945a25Schristos 			}
40526945a25Schristos 		}
40626945a25Schristos 	}
40726945a25Schristos 
40826945a25Schristos 	if (opts & OPT_VERBOSE)
40926945a25Schristos 		showhostmap_dead(nsp);
41026945a25Schristos }
41126945a25Schristos 
41226945a25Schristos 
dotable(nsp,fd,alive,which,side)41326945a25Schristos void dotable(nsp, fd, alive, which, side)
41426945a25Schristos 	natstat_t *nsp;
41526945a25Schristos 	int fd, alive, which;
41626945a25Schristos 	char *side;
41726945a25Schristos {
41826945a25Schristos 	int sz, i, used, maxlen, minlen, totallen;
41926945a25Schristos 	ipftable_t table;
42026945a25Schristos 	u_int *buckets;
42126945a25Schristos 	ipfobj_t obj;
42226945a25Schristos 
42326945a25Schristos 	sz = sizeof(*buckets) * nsp->ns_nattab_sz;
42426945a25Schristos 	buckets = (u_int *)malloc(sz);
42526945a25Schristos 	if (buckets == NULL) {
42626945a25Schristos 		fprintf(stderr,
42726945a25Schristos 			"cannot allocate memory (%d) for buckets\n", sz);
42826945a25Schristos 		return;
42926945a25Schristos 	}
43026945a25Schristos 
43126945a25Schristos 	obj.ipfo_rev = IPFILTER_VERSION;
43226945a25Schristos 	obj.ipfo_type = IPFOBJ_GTABLE;
43326945a25Schristos 	obj.ipfo_size = sizeof(table);
43426945a25Schristos 	obj.ipfo_ptr = &table;
43526945a25Schristos 
43626945a25Schristos 	if (which == 0) {
43726945a25Schristos 		table.ita_type = IPFTABLE_BUCKETS_NATIN;
43826945a25Schristos 	} else if (which == 1) {
43926945a25Schristos 		table.ita_type = IPFTABLE_BUCKETS_NATOUT;
44026945a25Schristos 	}
44126945a25Schristos 	table.ita_table = buckets;
44226945a25Schristos 
44326945a25Schristos 	if (alive) {
44426945a25Schristos 		if (ioctl(fd, SIOCGTABL, &obj) != 0) {
445c50c2f6fSdarrenr 			ipferror(fd, "SIOCFTABL");
44626945a25Schristos 			free(buckets);
44726945a25Schristos 			return;
44826945a25Schristos 		}
44926945a25Schristos 	} else {
45026945a25Schristos 		if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) {
45126945a25Schristos 			free(buckets);
45226945a25Schristos 			return;
45326945a25Schristos 		}
45426945a25Schristos 	}
45526945a25Schristos 
45626945a25Schristos 	minlen = nsp->ns_side[which].ns_inuse;
45726945a25Schristos 	totallen = 0;
45826945a25Schristos 	maxlen = 0;
45926945a25Schristos 	used = 0;
46026945a25Schristos 
46126945a25Schristos 	for (i = 0; i < nsp->ns_nattab_sz; i++) {
46226945a25Schristos 		if (buckets[i] > maxlen)
46326945a25Schristos 			maxlen = buckets[i];
46426945a25Schristos 		if (buckets[i] < minlen)
46526945a25Schristos 			minlen = buckets[i];
46626945a25Schristos 		if (buckets[i] != 0)
46726945a25Schristos 			used++;
46826945a25Schristos 		totallen += buckets[i];
46926945a25Schristos 	}
47026945a25Schristos 
47126945a25Schristos 	printf("%d%%\thash efficiency %s\n",
47226945a25Schristos 	       totallen ? used * 100 / totallen : 0, side);
47326945a25Schristos 	printf("%2.2f%%\tbucket usage %s\n",
47426945a25Schristos 	       ((float)used / nsp->ns_nattab_sz) * 100.0, side);
47526945a25Schristos 	printf("%d\tminimal length %s\n", minlen, side);
47626945a25Schristos 	printf("%d\tmaximal length %s\n", maxlen, side);
47726945a25Schristos 	printf("%.3f\taverage length %s\n",
47826945a25Schristos 	       used ? ((float)totallen / used) : 0.0, side);
47926945a25Schristos 
48026945a25Schristos 	free(buckets);
48126945a25Schristos }
48226945a25Schristos 
48326945a25Schristos 
dostats(fd,nsp,opts,alive,filter)48426945a25Schristos void dostats(fd, nsp, opts, alive, filter)
48526945a25Schristos 	natstat_t *nsp;
48626945a25Schristos 	int fd, opts, alive, *filter;
48726945a25Schristos {
48826945a25Schristos 	/*
48926945a25Schristos 	 * Show statistics ?
49026945a25Schristos 	 */
49126945a25Schristos 	if (opts & OPT_STAT) {
492c50c2f6fSdarrenr 		printnatside("in", &nsp->ns_side[0]);
49326945a25Schristos 		dotable(nsp, fd, alive, 0, "in");
49426945a25Schristos 
495c50c2f6fSdarrenr 		printnatside("out", &nsp->ns_side[1]);
49626945a25Schristos 		dotable(nsp, fd, alive, 1, "out");
49726945a25Schristos 
49826945a25Schristos 		printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log);
49926945a25Schristos 		printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log);
50026945a25Schristos 		printf("%lu\tadded in\n%lu\tadded out\n",
50126945a25Schristos 			nsp->ns_side[0].ns_added,
50226945a25Schristos 			nsp->ns_side[1].ns_added);
503c50c2f6fSdarrenr 		printf("%u\tactive\n", nsp->ns_active);
504c50c2f6fSdarrenr 		printf("%lu\ttransparent adds\n", nsp->ns_addtrpnt);
505c50c2f6fSdarrenr 		printf("%lu\tdivert build\n", nsp->ns_divert_build);
50626945a25Schristos 		printf("%lu\texpired\n", nsp->ns_expire);
507c50c2f6fSdarrenr 		printf("%lu\tflush all\n", nsp->ns_flush_all);
508c50c2f6fSdarrenr 		printf("%lu\tflush closing\n", nsp->ns_flush_closing);
509c50c2f6fSdarrenr 		printf("%lu\tflush queue\n", nsp->ns_flush_queue);
510c50c2f6fSdarrenr 		printf("%lu\tflush state\n", nsp->ns_flush_state);
511c50c2f6fSdarrenr 		printf("%lu\tflush timeout\n", nsp->ns_flush_timeout);
512c50c2f6fSdarrenr 		printf("%lu\thostmap new\n", nsp->ns_hm_new);
513c50c2f6fSdarrenr 		printf("%lu\thostmap fails\n", nsp->ns_hm_newfail);
514c50c2f6fSdarrenr 		printf("%lu\thostmap add\n", nsp->ns_hm_addref);
515c50c2f6fSdarrenr 		printf("%lu\thostmap NULL rule\n", nsp->ns_hm_nullnp);
516c50c2f6fSdarrenr 		printf("%lu\tlog ok\n", nsp->ns_log_ok);
517c50c2f6fSdarrenr 		printf("%lu\tlog fail\n", nsp->ns_log_fail);
518c50c2f6fSdarrenr 		printf("%u\torphan count\n", nsp->ns_orphans);
519c50c2f6fSdarrenr 		printf("%u\trule count\n", nsp->ns_rules);
520c50c2f6fSdarrenr 		printf("%u\tmap rules\n", nsp->ns_rules_map);
521c50c2f6fSdarrenr 		printf("%u\trdr rules\n", nsp->ns_rules_rdr);
52226945a25Schristos 		printf("%u\twilds\n", nsp->ns_wilds);
52326945a25Schristos 		if (opts & OPT_VERBOSE)
52426945a25Schristos 			printf("list %p\n", nsp->ns_list);
52526945a25Schristos 	}
52626945a25Schristos 
52726945a25Schristos 	if (opts & OPT_LIST) {
52826945a25Schristos 		if (alive)
52926945a25Schristos 			dostats_live(fd, nsp, opts, filter);
53026945a25Schristos 		else
53126945a25Schristos 			dostats_dead(nsp, opts, filter);
53226945a25Schristos 	}
53326945a25Schristos }
53426945a25Schristos 
53526945a25Schristos 
53626945a25Schristos /*
53726945a25Schristos  * Display NAT statistics.
53826945a25Schristos  */
dostats_live(fd,nsp,opts,filter)53926945a25Schristos void dostats_live(fd, nsp, opts, filter)
54026945a25Schristos 	natstat_t *nsp;
54126945a25Schristos 	int fd, opts, *filter;
54226945a25Schristos {
54326945a25Schristos 	ipfgeniter_t iter;
54426945a25Schristos 	char buffer[2000];
54526945a25Schristos 	ipfobj_t obj;
54626945a25Schristos 	ipnat_t	*ipn;
54726945a25Schristos 	nat_t nat;
54826945a25Schristos 	int i;
54926945a25Schristos 
55026945a25Schristos 	bzero((char *)&obj, sizeof(obj));
55126945a25Schristos 	obj.ipfo_rev = IPFILTER_VERSION;
55226945a25Schristos 	obj.ipfo_type = IPFOBJ_GENITER;
55326945a25Schristos 	obj.ipfo_size = sizeof(iter);
55426945a25Schristos 	obj.ipfo_ptr = &iter;
55526945a25Schristos 
55626945a25Schristos 	iter.igi_type = IPFGENITER_IPNAT;
55726945a25Schristos 	iter.igi_nitems = 1;
55826945a25Schristos 	iter.igi_data = buffer;
55926945a25Schristos 	ipn = (ipnat_t *)buffer;
56026945a25Schristos 
56126945a25Schristos 	/*
56226945a25Schristos 	 * Show list of NAT rules and NAT sessions ?
56326945a25Schristos 	 */
56426945a25Schristos 	if (nat_fields == NULL) {
56526945a25Schristos 		printf("List of active MAP/Redirect filters:\n");
56626945a25Schristos 		while (nsp->ns_list) {
56726945a25Schristos 			if (ioctl(fd, SIOCGENITER, &obj) == -1)
56826945a25Schristos 				break;
56926945a25Schristos 			if (opts & OPT_HITS)
57026945a25Schristos 				printf("%lu ", ipn->in_hits);
57126945a25Schristos 			printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
57226945a25Schristos 			nsp->ns_list = ipn->in_next;
57326945a25Schristos 		}
57426945a25Schristos 	}
57526945a25Schristos 
57626945a25Schristos 	if (nat_fields == NULL) {
57726945a25Schristos 		printf("\nList of active sessions:\n");
57826945a25Schristos 
57926945a25Schristos 	} else if (nohdrfields == 0) {
58026945a25Schristos 		for (i = 0; nat_fields[i].w_value != 0; i++) {
58126945a25Schristos 			printfieldhdr(natfields, nat_fields + i);
58226945a25Schristos 			if (nat_fields[i + 1].w_value != 0)
58326945a25Schristos 				printf("\t");
58426945a25Schristos 		}
58526945a25Schristos 		printf("\n");
58626945a25Schristos 	}
58726945a25Schristos 
58826945a25Schristos 	i = IPFGENITER_IPNAT;
58926945a25Schristos 	(void) ioctl(fd,SIOCIPFDELTOK, &i);
59026945a25Schristos 
59126945a25Schristos 
59226945a25Schristos 	iter.igi_type = IPFGENITER_NAT;
59326945a25Schristos 	iter.igi_nitems = 1;
59426945a25Schristos 	iter.igi_data = &nat;
59526945a25Schristos 
59626945a25Schristos 	while (nsp->ns_instances != NULL) {
59726945a25Schristos 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
59826945a25Schristos 			break;
59926945a25Schristos 		if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
60026945a25Schristos 			continue;
60126945a25Schristos 		if (nat_fields != NULL) {
60226945a25Schristos 			for (i = 0; nat_fields[i].w_value != 0; i++) {
60326945a25Schristos 				printnatfield(&nat, nat_fields[i].w_value);
60426945a25Schristos 				if (nat_fields[i + 1].w_value != 0)
60526945a25Schristos 					printf("\t");
60626945a25Schristos 			}
60726945a25Schristos 			printf("\n");
60826945a25Schristos 		} else {
60926945a25Schristos 			printactivenat(&nat, opts, nsp->ns_ticks);
61026945a25Schristos 			if (nat.nat_aps) {
61126945a25Schristos 				int proto;
61226945a25Schristos 
61326945a25Schristos 				if (nat.nat_dir & NAT_OUTBOUND)
61426945a25Schristos 					proto = nat.nat_pr[1];
61526945a25Schristos 				else
61626945a25Schristos 					proto = nat.nat_pr[0];
61726945a25Schristos 				printaps(nat.nat_aps, opts, proto);
61826945a25Schristos 			}
61926945a25Schristos 		}
62026945a25Schristos 		nsp->ns_instances = nat.nat_next;
62126945a25Schristos 	}
62226945a25Schristos 
62326945a25Schristos 	if (opts & OPT_VERBOSE)
62426945a25Schristos 		showhostmap_live(fd, nsp);
62526945a25Schristos 
62626945a25Schristos 	i = IPFGENITER_NAT;
62726945a25Schristos 	(void) ioctl(fd,SIOCIPFDELTOK, &i);
62826945a25Schristos }
62926945a25Schristos 
63026945a25Schristos 
63126945a25Schristos /*
63226945a25Schristos  * Display the active host mapping table.
63326945a25Schristos  */
showhostmap_dead(nsp)63426945a25Schristos void showhostmap_dead(nsp)
63526945a25Schristos 	natstat_t *nsp;
63626945a25Schristos {
63726945a25Schristos 	hostmap_t hm, *hmp, **maptable;
63826945a25Schristos 	u_int hv;
63926945a25Schristos 
64026945a25Schristos 	printf("\nList of active host mappings:\n");
64126945a25Schristos 
64226945a25Schristos 	maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) *
64326945a25Schristos 					nsp->ns_hostmap_sz);
64426945a25Schristos 	if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable,
64526945a25Schristos 		    sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) {
64626945a25Schristos 		perror("kmemcpy (maptable)");
64726945a25Schristos 		return;
64826945a25Schristos 	}
64926945a25Schristos 
65026945a25Schristos 	for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
65126945a25Schristos 		hmp = maptable[hv];
65226945a25Schristos 
65326945a25Schristos 		while (hmp) {
65426945a25Schristos 			if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) {
65526945a25Schristos 				perror("kmemcpy (hostmap)");
65626945a25Schristos 				return;
65726945a25Schristos 			}
65826945a25Schristos 
65926945a25Schristos 			printhostmap(&hm, hv);
66026945a25Schristos 			hmp = hm.hm_next;
66126945a25Schristos 		}
66226945a25Schristos 	}
66326945a25Schristos 	free(maptable);
66426945a25Schristos }
66526945a25Schristos 
66626945a25Schristos 
66726945a25Schristos /*
66826945a25Schristos  * Display the active host mapping table.
66926945a25Schristos  */
showhostmap_live(fd,nsp)67026945a25Schristos void showhostmap_live(fd, nsp)
67126945a25Schristos 	int fd;
67226945a25Schristos 	natstat_t *nsp;
67326945a25Schristos {
67426945a25Schristos 	ipfgeniter_t iter;
67526945a25Schristos 	hostmap_t hm;
67626945a25Schristos 	ipfobj_t obj;
67726945a25Schristos 	int i;
67826945a25Schristos 
67926945a25Schristos 	bzero((char *)&obj, sizeof(obj));
68026945a25Schristos 	obj.ipfo_rev = IPFILTER_VERSION;
68126945a25Schristos 	obj.ipfo_type = IPFOBJ_GENITER;
68226945a25Schristos 	obj.ipfo_size = sizeof(iter);
68326945a25Schristos 	obj.ipfo_ptr = &iter;
68426945a25Schristos 
68526945a25Schristos 	iter.igi_type = IPFGENITER_HOSTMAP;
68626945a25Schristos 	iter.igi_nitems = 1;
68726945a25Schristos 	iter.igi_data = &hm;
68826945a25Schristos 
68926945a25Schristos 	printf("\nList of active host mappings:\n");
69026945a25Schristos 
69126945a25Schristos 	while (nsp->ns_maplist != NULL) {
69226945a25Schristos 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
69326945a25Schristos 			break;
69426945a25Schristos 		printhostmap(&hm, hm.hm_hv);
69526945a25Schristos 		nsp->ns_maplist = hm.hm_next;
69626945a25Schristos 	}
69726945a25Schristos 
69826945a25Schristos 	i = IPFGENITER_HOSTMAP;
69926945a25Schristos 	(void) ioctl(fd,SIOCIPFDELTOK, &i);
70026945a25Schristos }
70126945a25Schristos 
70226945a25Schristos 
nat_matcharray(nat,array)70326945a25Schristos int nat_matcharray(nat, array)
70426945a25Schristos 	nat_t *nat;
70526945a25Schristos 	int *array;
70626945a25Schristos {
707c50c2f6fSdarrenr 	int i, n, *x, rv, p;
708c50c2f6fSdarrenr 	ipfexp_t *e;
70926945a25Schristos 
710c50c2f6fSdarrenr 	rv = 0;
71126945a25Schristos 	n = array[0];
71226945a25Schristos 	x = array + 1;
71326945a25Schristos 
714c50c2f6fSdarrenr 	for (; n > 0; x += 3 + x[3], rv = 0) {
715c50c2f6fSdarrenr 		e = (ipfexp_t *)x;
716c50c2f6fSdarrenr 		if (e->ipfe_cmd == IPF_EXP_END)
71726945a25Schristos 			break;
718c50c2f6fSdarrenr 		n -= e->ipfe_size;
71926945a25Schristos 
720c50c2f6fSdarrenr 		p = e->ipfe_cmd >> 16;
721c50c2f6fSdarrenr 		if ((p != 0) && (p != nat->nat_pr[1]))
72226945a25Schristos 			break;
72326945a25Schristos 
724c50c2f6fSdarrenr 		switch (e->ipfe_cmd)
72526945a25Schristos 		{
72626945a25Schristos 		case IPF_EXP_IP_PR :
727c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
728c50c2f6fSdarrenr 				rv |= (nat->nat_pr[1] == e->ipfe_arg0[i]);
72926945a25Schristos 			}
73026945a25Schristos 			break;
73126945a25Schristos 
73226945a25Schristos 		case IPF_EXP_IP_SRCADDR :
733c50c2f6fSdarrenr 			if (nat->nat_v[0] != 4)
734c50c2f6fSdarrenr 				break;
735c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
736c50c2f6fSdarrenr 				rv |= ((nat->nat_osrcaddr &
737c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
738c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]) ||
739c50c2f6fSdarrenr 				      ((nat->nat_nsrcaddr &
740c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
741c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]);
74226945a25Schristos 			}
74326945a25Schristos 			break;
74426945a25Schristos 
74526945a25Schristos 		case IPF_EXP_IP_DSTADDR :
746c50c2f6fSdarrenr 			if (nat->nat_v[0] != 4)
747c50c2f6fSdarrenr 				break;
748c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
749c50c2f6fSdarrenr 				rv |= ((nat->nat_odstaddr &
750c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
751c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]) ||
752c50c2f6fSdarrenr 				      ((nat->nat_ndstaddr &
753c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
754c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]);
75526945a25Schristos 			}
75626945a25Schristos 			break;
75726945a25Schristos 
75826945a25Schristos 		case IPF_EXP_IP_ADDR :
759c50c2f6fSdarrenr 			if (nat->nat_v[0] != 4)
760c50c2f6fSdarrenr 				break;
761c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
762c50c2f6fSdarrenr 				rv |= ((nat->nat_osrcaddr &
763c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
764c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]) ||
765c50c2f6fSdarrenr 				      ((nat->nat_nsrcaddr &
766c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
767c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]) ||
768c50c2f6fSdarrenr 				     ((nat->nat_odstaddr &
769c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
770c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]) ||
771c50c2f6fSdarrenr 				     ((nat->nat_ndstaddr &
772c50c2f6fSdarrenr 					e->ipfe_arg0[i * 2 + 1]) ==
773c50c2f6fSdarrenr 				       e->ipfe_arg0[i * 2]);
77426945a25Schristos 			}
77526945a25Schristos 			break;
77626945a25Schristos 
777c50c2f6fSdarrenr #ifdef USE_INET6
778c50c2f6fSdarrenr 		case IPF_EXP_IP6_SRCADDR :
779c50c2f6fSdarrenr 			if (nat->nat_v[0] != 6)
780c50c2f6fSdarrenr 				break;
781c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
782c50c2f6fSdarrenr 				rv |= IP6_MASKEQ(&nat->nat_osrc6,
783c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
784c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]) ||
785c50c2f6fSdarrenr 				      IP6_MASKEQ(&nat->nat_nsrc6,
786c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
787c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]);
788c50c2f6fSdarrenr 			}
789c50c2f6fSdarrenr 			break;
790c50c2f6fSdarrenr 
791c50c2f6fSdarrenr 		case IPF_EXP_IP6_DSTADDR :
792c50c2f6fSdarrenr 			if (nat->nat_v[0] != 6)
793c50c2f6fSdarrenr 				break;
794c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
795c50c2f6fSdarrenr 				rv |= IP6_MASKEQ(&nat->nat_odst6,
796c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
797c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]) ||
798c50c2f6fSdarrenr 				      IP6_MASKEQ(&nat->nat_ndst6,
799c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
800c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]);
801c50c2f6fSdarrenr 			}
802c50c2f6fSdarrenr 			break;
803c50c2f6fSdarrenr 
804c50c2f6fSdarrenr 		case IPF_EXP_IP6_ADDR :
805c50c2f6fSdarrenr 			if (nat->nat_v[0] != 6)
806c50c2f6fSdarrenr 				break;
807c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
808c50c2f6fSdarrenr 				rv |= IP6_MASKEQ(&nat->nat_osrc6,
809c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
810c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]) ||
811c50c2f6fSdarrenr 				      IP6_MASKEQ(&nat->nat_nsrc6,
812c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
813c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]) ||
814c50c2f6fSdarrenr 				      IP6_MASKEQ(&nat->nat_odst6,
815c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
816c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]) ||
817c50c2f6fSdarrenr 				      IP6_MASKEQ(&nat->nat_ndst6,
818c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8 + 4],
819c50c2f6fSdarrenr 						 &e->ipfe_arg0[i * 8]);
820c50c2f6fSdarrenr 			}
821c50c2f6fSdarrenr 			break;
822c50c2f6fSdarrenr #endif
823c50c2f6fSdarrenr 
82426945a25Schristos 		case IPF_EXP_UDP_PORT :
82526945a25Schristos 		case IPF_EXP_TCP_PORT :
826c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
827c50c2f6fSdarrenr 				rv |= (nat->nat_osport == e->ipfe_arg0[i]) ||
828c50c2f6fSdarrenr 				      (nat->nat_nsport == e->ipfe_arg0[i]) ||
829c50c2f6fSdarrenr 				      (nat->nat_odport == e->ipfe_arg0[i]) ||
830c50c2f6fSdarrenr 				      (nat->nat_ndport == e->ipfe_arg0[i]);
83126945a25Schristos 			}
83226945a25Schristos 			break;
83326945a25Schristos 
83426945a25Schristos 		case IPF_EXP_UDP_SPORT :
83526945a25Schristos 		case IPF_EXP_TCP_SPORT :
836c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
837c50c2f6fSdarrenr 				rv |= (nat->nat_osport == e->ipfe_arg0[i]) ||
838c50c2f6fSdarrenr 				      (nat->nat_nsport == e->ipfe_arg0[i]);
83926945a25Schristos 			}
84026945a25Schristos 			break;
84126945a25Schristos 
84226945a25Schristos 		case IPF_EXP_UDP_DPORT :
84326945a25Schristos 		case IPF_EXP_TCP_DPORT :
844c50c2f6fSdarrenr 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
845c50c2f6fSdarrenr 				rv |= (nat->nat_odport == e->ipfe_arg0[i]) ||
846c50c2f6fSdarrenr 				      (nat->nat_ndport == e->ipfe_arg0[i]);
84726945a25Schristos 			}
84826945a25Schristos 			break;
84926945a25Schristos 		}
850c50c2f6fSdarrenr 		rv ^= e->ipfe_not;
85126945a25Schristos 
852c50c2f6fSdarrenr 		if (rv == 0)
85326945a25Schristos 			break;
85426945a25Schristos 	}
85526945a25Schristos 
856c50c2f6fSdarrenr 	return rv;
85726945a25Schristos }
858