/*	$NetBSD: ippool.c,v 1.4 2013/10/20 03:09:11 christos Exp $	*/

/*
 * Copyright (C) 2012 by Darren Reed.
 *
 * See the IPFILTER.LICENCE file for details on licencing.
 */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/socket.h>
#if defined(BSD) && (BSD >= 199306)
# include <sys/cdefs.h>
#endif
#include <sys/ioctl.h>

#include <net/if.h>
#if __FreeBSD_version >= 300000
# include <net/if_var.h>
#endif
#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <ctype.h>
#include <unistd.h>
#ifdef linux
# include <linux/a.out.h>
#else
# include <nlist.h>
#endif

#include "ipf.h"
#include "netinet/ipl.h"
#include "netinet/ip_lookup.h"
#include "netinet/ip_pool.h"
#include "netinet/ip_htable.h"
#include "kmem.h"


extern	int	ippool_yyparse __P((void));
extern	int	ippool_yydebug;
extern	FILE	*ippool_yyin;
extern	char	*optarg;
extern	int	lineNum;

void	usage __P((char *));
int	main __P((int, char **));
int	poolcommand __P((int, int, char *[]));
int	poolnodecommand __P((int, int, char *[]));
int	loadpoolfile __P((int, char *[], char *));
int	poollist __P((int, char *[]));
void	poollist_dead __P((int, char *, int, char *, char *));
void	poollist_live __P((int, char *, int, int));
int	poolflush __P((int, char *[]));
int	poolstats __P((int, char *[]));
int	gettype __P((char *, u_int *));
int	getrole __P((char *));
int	setnodeaddr __P((int, int, void *ptr, char *arg));
void	showpools_live __P((int, int, ipf_pool_stat_t *, char *));
void	showhashs_live __P((int, int, iphtstat_t *, char *));
void	showdstls_live __P((int, int, ipf_dstl_stat_t *, char *));

int	opts = 0;
int	fd = -1;
int	use_inet6 = 0;
wordtab_t *pool_fields = NULL;
int	nohdrfields = 0;


void
usage(prog)
	char *prog;
{
	fprintf(stderr, "Usage:\t%s\n", prog);
	fprintf(stderr, "\t-a [-dnv] [-m <name>] [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
	fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
	fprintf(stderr, "\t-f <file> [-dnuv]\n");
	fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
	fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-O <fields>]\n");
	fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
	fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
	fprintf(stderr, "\t-s [-dtv] [-M <core>] [-N <namelist>]\n");
	exit(1);
}


int
main(argc, argv)
	int argc;
	char *argv[];
{
	int err = 1;

	if (argc < 2)
		usage(argv[0]);

	assigndefined(getenv("IPPOOL_PREDEFINED"));

	switch (getopt(argc, argv, "aAf:FlnrRsv"))
	{
	case 'a' :
		err = poolnodecommand(0, argc, argv);
		break;
	case 'A' :
		err = poolcommand(0, argc, argv);
		break;
	case 'f' :
		err = loadpoolfile(argc, argv, optarg);
		break;
	case 'F' :
		err = poolflush(argc, argv);
		break;
	case 'l' :
		err = poollist(argc, argv);
		break;
	case 'n' :
		opts |= OPT_DONOTHING|OPT_DONTOPEN;
		break;
	case 'r' :
		err = poolnodecommand(1, argc, argv);
		break;
	case 'R' :
		err = poolcommand(1, argc, argv);
		break;
	case 's' :
		err = poolstats(argc, argv);
		break;
	case 'v' :
		opts |= OPT_VERBOSE;
		break;
	default :
		exit(1);
	}

	if (err != 0)
		exit(1);
	return 0;
}


int
poolnodecommand(remove, argc, argv)
	int remove, argc;
	char *argv[];
{
	int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
	char *poolname = NULL;
	ip_pool_node_t pnode;
	iphtent_t hnode;
	void *ptr = &pnode;

	ipset = 0;
	role = IPL_LOGIPF;
	bzero((char *)&pnode, sizeof(pnode));
	bzero((char *)&hnode, sizeof(hnode));

	while ((c = getopt(argc, argv, "di:m:no:Rt:T:v")) != -1)
		switch (c)
		{
		case 'd' :
			opts |= OPT_DEBUG;
			ippool_yydebug++;
			break;
		case 'i' :
			if (setnodeaddr(type, role, ptr, optarg) == 0)
				ipset = 1;
			break;
		case 'm' :
			poolname = optarg;
			break;
		case 'n' :
			opts |= OPT_DONOTHING|OPT_DONTOPEN;
			break;
		case 'o' :
			if (ipset == 1) {
				fprintf(stderr,
					"cannot set role after ip address\n");
				return -1;
			}
			role = getrole(optarg);
			if (role == IPL_LOGNONE)
				return -1;
			break;
		case 'R' :
			opts |= OPT_NORESOLVE;
			break;
		case 't' :
			if (ipset == 1) {
				fprintf(stderr,
					"cannot set type after ip address\n");
				return -1;
			}
			type = gettype(optarg, NULL);
			switch (type) {
			case IPLT_NONE :
				fprintf(stderr, "unknown type '%s'\n", optarg);
				return -1;
			case IPLT_HASH :
				ptr = &hnode;
				break;
			case IPLT_POOL :
			default :
				break;
			}
			break;
		case 'T' :
			ttl = atoi(optarg);
			if (ttl < 0) {
				fprintf(stderr, "cannot set negative ttl\n");
				return -1;
			}
			break;
		case 'v' :
			opts |= OPT_VERBOSE;
			break;
		}

	if (argv[optind] != NULL && ipset == 0) {
		if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
			ipset = 1;
	}

	if (opts & OPT_DEBUG)
		fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);

	if (ipset == 0) {
		fprintf(stderr, "no IP address given with -i\n");
		return -1;
	}

	if (poolname == NULL) {
		fprintf(stderr, "poolname not given with add/remove node\n");
		return -1;
	}

	switch (type) {
	case IPLT_POOL :
		if (remove == 0)
			err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
		else
			err = remove_poolnode(role, poolname, &pnode, ioctl);
		break;
	case IPLT_HASH :
		if (remove == 0)
			err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
		else
			err = remove_hashnode(role, poolname, &hnode, ioctl);
		break;
	default :
		break;
	}
	return err;
}


int
poolcommand(remove, argc, argv)
	int remove, argc;
	char *argv[];
{
	int type, role, c, err;
	char *poolname;
	iphtable_t iph;
	ip_pool_t pool;

	err = 1;
	role = 0;
	type = 0;
	poolname = NULL;
	role = IPL_LOGIPF;
	bzero((char *)&iph, sizeof(iph));
	bzero((char *)&pool, sizeof(pool));

	while ((c = getopt(argc, argv, "dm:no:RSv")) != -1)
		switch (c)
		{
		case 'd' :
			opts |= OPT_DEBUG;
			ippool_yydebug++;
			break;
		case 'm' :
			poolname = optarg;
			break;
		case 'n' :
			opts |= OPT_DONOTHING|OPT_DONTOPEN;
			break;
		case 'o' :
			role = getrole(optarg);
			if (role == IPL_LOGNONE) {
				fprintf(stderr, "unknown role '%s'\n", optarg);
				return -1;
			}
			break;
		case 'R' :
			opts |= OPT_NORESOLVE;
			break;
		case 'S' :
			iph.iph_seed = atoi(optarg);
			break;
		case 'v' :
			opts |= OPT_VERBOSE;
			break;
		}

	if (opts & OPT_DEBUG)
		fprintf(stderr, "poolcommand: opts = %#x\n", opts);

	if (poolname == NULL) {
		fprintf(stderr, "poolname not given with add/remove pool\n");
		return -1;
	}

	type = gettype(argv[optind], &iph.iph_type);
	if (type == IPLT_NONE) {
		fprintf(stderr, "unknown type '%s'\n", argv[optind]);
		return -1;
	}

	if (type == IPLT_HASH) {
		strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
		iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
		iph.iph_unit = role;
	} else if (type == IPLT_POOL) {
		strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
		pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
		pool.ipo_unit = role;
	}

	if (remove == 0) {
		switch (type)
		{
		case IPLT_HASH :
			err = load_hash(&iph, NULL, ioctl);
			break;
		case IPLT_POOL :
			err = load_pool(&pool, ioctl);
			break;
		}
	} else {
		switch (type)
		{
		case IPLT_HASH :
			err = remove_hash(&iph, ioctl);
			break;
		case IPLT_POOL :
			err = remove_pool(&pool, ioctl);
			break;
		}
	}
	return err;
}


int
loadpoolfile(argc, argv, infile)
	int argc;
	char *argv[], *infile;
{
	int c;

	infile = optarg;

	while ((c = getopt(argc, argv, "dnRuv")) != -1)
		switch (c)
		{
		case 'd' :
			opts |= OPT_DEBUG;
			ippool_yydebug++;
			break;
		case 'n' :
			opts |= OPT_DONOTHING|OPT_DONTOPEN;
			break;
		case 'R' :
			opts |= OPT_NORESOLVE;
			break;
		case 'u' :
			opts |= OPT_REMOVE;
			break;
		case 'v' :
			opts |= OPT_VERBOSE;
			break;
		}

	if (opts & OPT_DEBUG)
		fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);

	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
		fd = open(IPLOOKUP_NAME, O_RDWR);
		if (fd == -1) {
			perror("open(IPLOOKUP_NAME)");
			exit(1);
		}
	}

	if (ippool_parsefile(fd, infile, ioctl) != 0)
		return -1;
	return 0;
}


int
poolstats(argc, argv)
	int argc;
	char *argv[];
{
	int c, type, role;
	ipf_pool_stat_t plstat;
	ipf_dstl_stat_t dlstat;
	iphtstat_t htstat;
	iplookupop_t op;

	type = IPLT_ALL;
	role = IPL_LOGALL;

	bzero((char *)&op, sizeof(op));

	while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
		switch (c)
		{
		case 'd' :
			opts |= OPT_DEBUG;
			break;
		case 'M' :
			break;
		case 'N' :
			break;
		case 'o' :
			role = getrole(optarg);
			if (role == IPL_LOGNONE) {
				fprintf(stderr, "unknown role '%s'\n", optarg);
				return -1;
			}
			break;
		case 't' :
			type = gettype(optarg, NULL);
			if (type != IPLT_POOL) {
				fprintf(stderr,
					"-s not supported for this type yet\n");
				return -1;
			}
			break;
		case 'v' :
			opts |= OPT_VERBOSE;
			break;
		}

	if (opts & OPT_DEBUG)
		fprintf(stderr, "poolstats: opts = %#x\n", opts);

	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
		fd = open(IPLOOKUP_NAME, O_RDWR);
		if (fd == -1) {
			perror("open(IPLOOKUP_NAME)");
			exit(1);
		}
	}

	if (type == IPLT_ALL || type == IPLT_POOL) {
		op.iplo_type = IPLT_POOL;
		op.iplo_struct = &plstat;
		op.iplo_size = sizeof(plstat);
		if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
			if (c == -1) {
				ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
				return -1;
			}
			printf("%lu\taddress pools\n", plstat.ipls_pools);
			printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
		}
	}

	if (type == IPLT_ALL || type == IPLT_HASH) {
		op.iplo_type = IPLT_HASH;
		op.iplo_struct = &htstat;
		op.iplo_size = sizeof(htstat);
		if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
			if (c == -1) {
				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
				return -1;
			}
			printf("%lu\thash tables\n", htstat.iphs_numtables);
			printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
			printf("%lu\thash table no memory \n",
				htstat.iphs_nomem);
		}
	}

	if (type == IPLT_ALL || type == IPLT_DSTLIST) {
		op.iplo_type = IPLT_DSTLIST;
		op.iplo_struct = &dlstat;
		op.iplo_size = sizeof(dlstat);
		if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
			if (c == -1) {
				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
				return -1;
			}
			printf("%u\tdestination lists\n",
			       dlstat.ipls_numlists);
			printf("%u\tdestination list nodes\n",
			       dlstat.ipls_numnodes);
			printf("%lu\tdestination list no memory\n",
			       dlstat.ipls_nomem);
			printf("%u\tdestination list zombies\n",
			       dlstat.ipls_numdereflists);
			printf("%u\tdesetination list node zombies\n",
			       dlstat.ipls_numderefnodes);
		}
	}
	return 0;
}


int
poolflush(argc, argv)
	int argc;
	char *argv[];
{
	int c, role, type, arg;
	iplookupflush_t flush;

	arg = IPLT_ALL;
	type = IPLT_ALL;
	role = IPL_LOGALL;

	while ((c = getopt(argc, argv, "do:t:v")) != -1)
		switch (c)
		{
		case 'd' :
			opts |= OPT_DEBUG;
			break;
		case 'o' :
			role = getrole(optarg);
			if (role == IPL_LOGNONE) {
				fprintf(stderr, "unknown role '%s'\n", optarg);
				return -1;
			}
			break;
		case 't' :
			type = gettype(optarg, NULL);
			if (type == IPLT_NONE) {
				fprintf(stderr, "unknown type '%s'\n", optarg);
				return -1;
			}
			break;
		case 'v' :
			opts |= OPT_VERBOSE;
			break;
		}

	if (opts & OPT_DEBUG)
		fprintf(stderr, "poolflush: opts = %#x\n", opts);

	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
		fd = open(IPLOOKUP_NAME, O_RDWR);
		if (fd == -1) {
			perror("open(IPLOOKUP_NAME)");
			exit(1);
		}
	}

	bzero((char *)&flush, sizeof(flush));
	flush.iplf_type = type;
	flush.iplf_unit = role;
	flush.iplf_arg = arg;

	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
		if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
			ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
			exit(1);
		}

	}
	printf("%u object%s flushed\n", flush.iplf_count,
	       (flush.iplf_count == 1) ? "" : "s");

	return 0;
}


int
getrole(rolename)
	char *rolename;
{
	int role;

	if (!strcasecmp(rolename, "ipf")) {
		role = IPL_LOGIPF;
#if 0
	} else if (!strcasecmp(rolename, "nat")) {
		role = IPL_LOGNAT;
	} else if (!strcasecmp(rolename, "state")) {
		role = IPL_LOGSTATE;
	} else if (!strcasecmp(rolename, "auth")) {
		role = IPL_LOGAUTH;
	} else if (!strcasecmp(rolename, "sync")) {
		role = IPL_LOGSYNC;
	} else if (!strcasecmp(rolename, "scan")) {
		role = IPL_LOGSCAN;
	} else if (!strcasecmp(rolename, "pool")) {
		role = IPL_LOGLOOKUP;
	} else if (!strcasecmp(rolename, "count")) {
		role = IPL_LOGCOUNT;
#endif
	} else {
		role = IPL_LOGNONE;
	}

	return role;
}


int
gettype(typename, minor)
	char *typename;
	u_int *minor;
{
	int type;

	if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
		type = IPLT_POOL;
	} else if (!strcasecmp(typename, "hash")) {
		type = IPLT_HASH;
		if (minor != NULL)
			*minor = IPHASH_LOOKUP;
	} else if (!strcasecmp(typename, "group-map")) {
		type = IPLT_HASH;
		if (minor != NULL)
			*minor = IPHASH_GROUPMAP;
	} else {
		type = IPLT_NONE;
	}
	return type;
}


int
poollist(argc, argv)
	int argc;
	char *argv[];
{
	char *kernel, *core, *poolname;
	int c, role, type, live_kernel;
	iplookupop_t op;

	core = NULL;
	kernel = NULL;
	live_kernel = 1;
	type = IPLT_ALL;
	poolname = NULL;
	role = IPL_LOGALL;

	while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1)
		switch (c)
		{
		case 'd' :
			opts |= OPT_DEBUG;
			break;
		case 'm' :
			poolname = optarg;
			break;
		case 'M' :
			live_kernel = 0;
			core = optarg;
			break;
		case 'N' :
			live_kernel = 0;
			kernel = optarg;
			break;
		case 'o' :
			role = getrole(optarg);
			if (role == IPL_LOGNONE) {
				fprintf(stderr, "unknown role '%s'\n", optarg);
				return -1;
			}
			break;
		case 'O' :
			pool_fields = parsefields(poolfields, optarg);
			break;
		case 'R' :
			opts |= OPT_NORESOLVE;
			break;
		case 't' :
			type = gettype(optarg, NULL);
			if (type == IPLT_NONE) {
				fprintf(stderr, "unknown type '%s'\n", optarg);
				return -1;
			}
			break;
		case 'v' :
			opts |= OPT_VERBOSE;
			break;
		}

	if (opts & OPT_DEBUG)
		fprintf(stderr, "poollist: opts = %#x\n", opts);

	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
		fd = open(IPLOOKUP_NAME, O_RDWR);
		if (fd == -1) {
			perror("open(IPLOOKUP_NAME)");
			exit(1);
		}
	}

	bzero((char *)&op, sizeof(op));
	if (poolname != NULL) {
		strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
		op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
	}
	op.iplo_unit = role;

	if (live_kernel)
		poollist_live(role, poolname, type, fd);
	else
		poollist_dead(role, poolname, type, kernel, core);
	return 0;
}


void
poollist_dead(role, poolname, type, kernel, core)
	int role, type;
	char *poolname, *kernel, *core;
{
	iphtable_t *hptr;
	ip_pool_t *ptr;

	if (openkmem(kernel, core) == -1)
		exit(-1);

	if (type == IPLT_ALL || type == IPLT_POOL) {
		ip_pool_t *pools[IPL_LOGSIZE];
		struct nlist names[2] = { { "ip_pool_list" } , { "" } };

		if (nlist(kernel, names) != 1)
			return;

		bzero(&pools, sizeof(pools));
		if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
			return;

		if (role != IPL_LOGALL) {
			ptr = pools[role];
			while (ptr != NULL) {
				ptr = printpool(ptr, kmemcpywrap, poolname,
						opts, pool_fields);
			}
		} else {
			for (role = 0; role <= IPL_LOGMAX; role++) {
				ptr = pools[role];
				while (ptr != NULL) {
					ptr = printpool(ptr, kmemcpywrap,
							poolname, opts,
							pool_fields);
				}
			}
			role = IPL_LOGALL;
		}
	}
	if (type == IPLT_ALL || type == IPLT_HASH) {
		iphtable_t *tables[IPL_LOGSIZE];
		struct nlist names[2] = { { "ipf_htables" } , { "" } };

		if (nlist(kernel, names) != 1)
			return;

		bzero(&tables, sizeof(tables));
		if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
			return;

		if (role != IPL_LOGALL) {
			hptr = tables[role];
			while (hptr != NULL) {
				hptr = printhash(hptr, kmemcpywrap,
						 poolname, opts, pool_fields);
			}
		} else {
			for (role = 0; role <= IPL_LOGMAX; role++) {
				hptr = tables[role];
				while (hptr != NULL) {
					hptr = printhash(hptr, kmemcpywrap,
							 poolname, opts,
							 pool_fields);
				}
			}
		}
	}
}


void
poollist_live(role, poolname, type, fd)
	int role, type, fd;
	char *poolname;
{
	ipf_pool_stat_t plstat;
	iplookupop_t op;
	int unit;
	int c;

	if (type == IPLT_ALL || type == IPLT_POOL) {
		op.iplo_type = IPLT_POOL;
		op.iplo_size = sizeof(plstat);
		op.iplo_struct = &plstat;
		op.iplo_name[0] = '\0';
		op.iplo_arg = 0;

		if (role != IPL_LOGALL) {
			op.iplo_unit = role;

			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
			if (c == -1) {
				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
				return;
			}

			showpools_live(fd, role, &plstat, poolname);
		} else {
			for (unit = -1; unit <= IPL_LOGMAX; unit++) {
				op.iplo_unit = unit;

				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
				if (c == -1) {
					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
					return;
				}

				showpools_live(fd, unit, &plstat, poolname);
			}
		}
	}

	if (type == IPLT_ALL || type == IPLT_HASH) {
		iphtstat_t htstat;

		op.iplo_type = IPLT_HASH;
		op.iplo_size = sizeof(htstat);
		op.iplo_struct = &htstat;
		op.iplo_name[0] = '\0';
		op.iplo_arg = 0;

		if (role != IPL_LOGALL) {
			op.iplo_unit = role;

			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
			if (c == -1) {
				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
				return;
			}
			showhashs_live(fd, role, &htstat, poolname);
		} else {
			for (unit = 0; unit <= IPL_LOGMAX; unit++) {

				op.iplo_unit = unit;
				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
				if (c == -1) {
					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
					return;
				}

				showhashs_live(fd, unit, &htstat, poolname);
			}
		}
	}

	if (type == IPLT_ALL || type == IPLT_DSTLIST) {
		ipf_dstl_stat_t dlstat;

		op.iplo_type = IPLT_DSTLIST;
		op.iplo_size = sizeof(dlstat);
		op.iplo_struct = &dlstat;
		op.iplo_name[0] = '\0';
		op.iplo_arg = 0;

		if (role != IPL_LOGALL) {
			op.iplo_unit = role;

			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
			if (c == -1) {
				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
				return;
			}
			showdstls_live(fd, role, &dlstat, poolname);
		} else {
			for (unit = 0; unit <= IPL_LOGMAX; unit++) {

				op.iplo_unit = unit;
				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
				if (c == -1) {
					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
					return;
				}

				showdstls_live(fd, unit, &dlstat, poolname);
			}
		}
	}
}


void
showpools_live(fd, role, plstp, poolname)
	int fd, role;
	ipf_pool_stat_t *plstp;
	char *poolname;
{
	ipflookupiter_t iter;
	ip_pool_t pool;
	ipfobj_t obj;

	obj.ipfo_rev = IPFILTER_VERSION;
	obj.ipfo_type = IPFOBJ_LOOKUPITER;
	obj.ipfo_size = sizeof(iter);
	obj.ipfo_ptr = &iter;

	iter.ili_type = IPLT_POOL;
	iter.ili_otype = IPFLOOKUPITER_LIST;
	iter.ili_ival = IPFGENITER_LOOKUP;
	iter.ili_nitems = 1;
	iter.ili_data = &pool;
	iter.ili_unit = role;
	*iter.ili_name = '\0';

	bzero((char *)&pool, sizeof(pool));

	while (plstp->ipls_list[role + 1] != NULL) {
		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
			break;
		}
		if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
		    ((opts & OPT_DEBUG) != 0))
			printpool_live(&pool, fd, poolname, opts, pool_fields);

		plstp->ipls_list[role + 1] = pool.ipo_next;
	}
}


void
showhashs_live(fd, role, htstp, poolname)
	int fd, role;
	iphtstat_t *htstp;
	char *poolname;
{
	ipflookupiter_t iter;
	iphtable_t table;
	ipfobj_t obj;

	obj.ipfo_rev = IPFILTER_VERSION;
	obj.ipfo_type = IPFOBJ_LOOKUPITER;
	obj.ipfo_size = sizeof(iter);
	obj.ipfo_ptr = &iter;

	iter.ili_type = IPLT_HASH;
	iter.ili_otype = IPFLOOKUPITER_LIST;
	iter.ili_ival = IPFGENITER_LOOKUP;
	iter.ili_nitems = 1;
	iter.ili_data = &table;
	iter.ili_unit = role;
	*iter.ili_name = '\0';

	while (htstp->iphs_tables != NULL) {
		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
			break;
		}

		printhash_live(&table, fd, poolname, opts, pool_fields);

		htstp->iphs_tables = table.iph_next;
	}
}


void
showdstls_live(fd, role, dlstp, poolname)
	int fd, role;
	ipf_dstl_stat_t *dlstp;
	char *poolname;
{
	ipflookupiter_t iter;
	ippool_dst_t table;
	ipfobj_t obj;

	obj.ipfo_rev = IPFILTER_VERSION;
	obj.ipfo_type = IPFOBJ_LOOKUPITER;
	obj.ipfo_size = sizeof(iter);
	obj.ipfo_ptr = &iter;

	iter.ili_type = IPLT_DSTLIST;
	iter.ili_otype = IPFLOOKUPITER_LIST;
	iter.ili_ival = IPFGENITER_LOOKUP;
	iter.ili_nitems = 1;
	iter.ili_data = &table;
	iter.ili_unit = role;
	*iter.ili_name = '\0';

	while (dlstp->ipls_list[role] != NULL) {
		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
			break;
		}

		printdstl_live(&table, fd, poolname, opts, pool_fields);

		dlstp->ipls_list[role] = table.ipld_next;
	}
}


int
setnodeaddr(int type, int role, void *ptr, char *arg)
{
	struct in_addr mask;
	char *s;

	s = strchr(arg, '/');
	if (s == NULL)
		mask.s_addr = 0xffffffff;
	else if (strchr(s, '.') == NULL) {
		if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
			return -1;
	} else {
		mask.s_addr = inet_addr(s + 1);
	}
	if (s != NULL)
		*s = '\0';

	if (type == IPLT_POOL) {
		ip_pool_node_t *node = ptr;

		if (node->ipn_addr.adf_family == AF_INET)
			node->ipn_addr.adf_len = offsetof(addrfamily_t,
							  adf_addr) +
						 sizeof(struct in_addr);
#ifdef USE_INET6
		else
			node->ipn_addr.adf_len = offsetof(addrfamily_t,
							  adf_addr) +
						 sizeof(struct in6_addr);
#endif
		node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
		node->ipn_mask.adf_len = node->ipn_addr.adf_len;
		node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
	} else if (type == IPLT_HASH) {
		iphtent_t *node = ptr;

		node->ipe_addr.in4.s_addr = inet_addr(arg);
		node->ipe_mask.in4.s_addr = mask.s_addr;
        	node->ipe_family = AF_INET;
        	node->ipe_unit = role;
	}

	return 0;
}