1
2/*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7#include <sys/types.h>
8#include <sys/time.h>
9#include <sys/param.h>
10#include <sys/socket.h>
11# include <sys/cdefs.h>
12#include <sys/ioctl.h>
13
14#include <net/if.h>
15#include <netinet/in.h>
16
17#include <arpa/inet.h>
18
19#include <stdio.h>
20#include <fcntl.h>
21#include <stdlib.h>
22#include <string.h>
23#include <netdb.h>
24#include <ctype.h>
25#include <unistd.h>
26# include <nlist.h>
27
28#include "ipf.h"
29#include "netinet/ipl.h"
30#include "netinet/ip_lookup.h"
31#include "netinet/ip_pool.h"
32#include "netinet/ip_htable.h"
33#include "kmem.h"
34
35
36extern	int	ippool_yyparse(void);
37extern	int	ippool_yydebug;
38extern	FILE	*ippool_yyin;
39extern	char	*optarg;
40extern	int	lineNum;
41
42void	usage(char *);
43int	main(int, char **);
44int	poolcommand(int, int, char *[]);
45int	poolnodecommand(int, int, char *[]);
46int	loadpoolfile(int, char *[], char *);
47int	poollist(int, char *[]);
48void	poollist_dead(int, char *, int, char *, char *);
49int	poollist_live(int, char *, int, int);
50int	poolflush(int, char *[]);
51int	poolstats(int, char *[]);
52int	gettype(char *, u_int *);
53int	getrole(char *);
54int	setnodeaddr(int, int, void *ptr, char *arg);
55int	showpools_live(int, int, ipf_pool_stat_t *, char *);
56int	showhashs_live(int, int, iphtstat_t *, char *);
57int	showdstls_live(int, int, ipf_dstl_stat_t *, char *);
58
59int	opts = 0;
60int	fd = -1;
61int	use_inet6 = 0;
62wordtab_t *pool_fields = NULL;
63int	nohdrfields = 0;
64
65
66void
67usage(char *prog)
68{
69	fprintf(stderr, "Usage:\t%s\n", prog);
70	fprintf(stderr, "\t-a [-dnv] -m <name> [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
71	fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
72	fprintf(stderr, "\t-f <file> [-dnuvR]\n");
73	fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
74	fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-o <role>] [-M <core>] [-N <namelist>]\n");
75	fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
76	fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
77	fprintf(stderr, "\t-s [-dtv]\n");
78	exit(1);
79}
80
81
82int
83main(int argc, char *argv[])
84{
85	int err = 1;
86
87	if (argc < 2)
88		usage(argv[0]);
89
90	assigndefined(getenv("IPPOOL_PREDEFINED"));
91
92	switch (getopt(argc, argv, "aAf:FlrRs"))
93	{
94	case 'a' :
95		err = poolnodecommand(0, argc, argv);
96		break;
97	case 'A' :
98		err = poolcommand(0, argc, argv);
99		break;
100	case 'f' :
101		err = loadpoolfile(argc, argv, optarg);
102		break;
103	case 'F' :
104		err = poolflush(argc, argv);
105		break;
106	case 'l' :
107		err = poollist(argc, argv);
108		break;
109	case 'r' :
110		err = poolnodecommand(1, argc, argv);
111		break;
112	case 'R' :
113		err = poolcommand(1, argc, argv);
114		break;
115	case 's' :
116		err = poolstats(argc, argv);
117		break;
118	default :
119		exit(1);
120	}
121
122	if (err != 0)
123		exit(1);
124	return (0);
125}
126
127
128int
129poolnodecommand(int remove, int argc, char *argv[])
130{
131	int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
132	char *poolname = NULL;
133	ip_pool_node_t pnode;
134	iphtent_t hnode;
135	void *ptr = &pnode;
136
137	ipset = 0;
138	role = IPL_LOGIPF;
139	bzero((char *)&pnode, sizeof(pnode));
140	bzero((char *)&hnode, sizeof(hnode));
141
142	while ((c = getopt(argc, argv, "di:m:no:t:T:v")) != -1)
143		switch (c)
144		{
145		case 'd' :
146			opts |= OPT_DEBUG;
147			ippool_yydebug++;
148			break;
149		case 'i' :
150			if (setnodeaddr(type, role, ptr, optarg) == 0)
151				ipset = 1;
152			break;
153		case 'm' :
154			poolname = optarg;
155			break;
156		case 'n' :
157			opts |= OPT_DONOTHING|OPT_DONTOPEN;
158			break;
159		case 'o' :
160			if (ipset == 1) {
161				fprintf(stderr,
162					"cannot set role after ip address\n");
163				return (-1);
164			}
165			role = getrole(optarg);
166			if (role == IPL_LOGNONE)
167				return (-1);
168			break;
169		case 't' :
170			if (ipset == 1) {
171				fprintf(stderr,
172					"cannot set type after ip address\n");
173				return (-1);
174			}
175			type = gettype(optarg, NULL);
176			switch (type) {
177			case IPLT_NONE :
178				fprintf(stderr, "unknown type '%s'\n", optarg);
179				return (-1);
180			case IPLT_HASH :
181				ptr = &hnode;
182				break;
183			case IPLT_POOL :
184			default :
185				break;
186			}
187			break;
188		case 'T' :
189			if (remove == 0) {
190				ttl = atoi(optarg);
191				if (ttl < 0) {
192					fprintf(stderr, "cannot set negative ttl\n");
193					return (-1);
194				}
195			} else {
196				usage(argv[0]);
197			}
198			break;
199		case 'v' :
200			opts |= OPT_VERBOSE;
201			break;
202		default :
203			usage(argv[0]);
204			break;		/* keep compiler happy */
205		}
206
207	if (argc - 1 - optind > 0)
208		usage(argv[0]);
209
210	if (argv[optind] != NULL && ipset == 0) {
211		if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
212			ipset = 1;
213	}
214
215	if (opts & OPT_DEBUG)
216		fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
217
218	if (ipset == 0) {
219		fprintf(stderr, "no IP address given with -i\n");
220		return (-1);
221	}
222
223	if (poolname == NULL) {
224		fprintf(stderr, "poolname not given with add/remove node\n");
225		return (-1);
226	}
227
228	switch (type) {
229	case IPLT_POOL :
230		if (remove == 0)
231			err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
232		else
233			err = remove_poolnode(role, poolname, &pnode, ioctl);
234		break;
235	case IPLT_HASH :
236		if (remove == 0)
237			err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
238		else
239			err = remove_hashnode(role, poolname, &hnode, ioctl);
240		break;
241	default :
242		break;
243	}
244	return (err);
245}
246
247
248int
249poolcommand(int remove, int argc, char *argv[])
250{
251	int type, role, c, err;
252	char *poolname, *typearg = NULL;
253	iphtable_t iph;
254	ip_pool_t pool;
255
256	err = 1;
257	role = 0;
258	type = 0;
259	poolname = NULL;
260	role = IPL_LOGIPF;
261	bzero((char *)&iph, sizeof(iph));
262	bzero((char *)&pool, sizeof(pool));
263
264	while ((c = getopt(argc, argv, "dm:no:S:vt:")) != -1)
265		switch (c)
266		{
267		case 'd' :
268			opts |= OPT_DEBUG;
269			ippool_yydebug++;
270			break;
271		case 'm' :
272			poolname = optarg;
273			break;
274		case 'n' :
275			opts |= OPT_DONOTHING|OPT_DONTOPEN;
276			break;
277		case 'o' :
278			role = getrole(optarg);
279			if (role == IPL_LOGNONE) {
280				fprintf(stderr, "unknown role '%s'\n", optarg);
281				return (-1);
282			}
283			break;
284		case 'S' :
285			if (remove == 0)
286				iph.iph_seed = atoi(optarg);
287			else
288				usage(argv[0]);
289			break;
290		case 't' :
291			type = gettype(optarg, &iph.iph_type);
292			typearg = optarg;
293			break;
294		case 'v' :
295			opts |= OPT_VERBOSE;
296			break;
297		default :
298			usage(argv[0]);
299			break;		/* keep compiler happy */
300		}
301
302	if (argc - 1 - optind > 0)
303		usage(argv[0]);
304
305	if (opts & OPT_DEBUG)
306		fprintf(stderr, "poolcommand: opts = %#x\n", opts);
307
308	if (poolname == NULL) {
309		fprintf(stderr, "poolname not given with add/remove pool\n");
310		return (-1);
311	}
312
313	if (type == IPLT_NONE && remove == 0) {
314		if (typearg == NULL) {
315			fprintf(stderr, "type must be specified\n");
316			usage(argv[0]);
317		} else {
318			fprintf(stderr, "unknown type '%s'\n", typearg);
319		}
320		return (-1);
321	}
322
323	if (type == IPLT_HASH || (type == IPLT_NONE && remove == 1)) {
324		strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
325		iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
326		iph.iph_unit = role;
327	}
328	if (type == IPLT_POOL || (type == IPLT_NONE && remove == 1)) {
329		strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
330		pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
331		pool.ipo_unit = role;
332	}
333
334	if (remove == 0) {
335		switch (type)
336		{
337		case IPLT_HASH :
338			err = load_hash(&iph, NULL, ioctl);
339			break;
340		case IPLT_POOL :
341			err = load_pool(&pool, ioctl);
342			break;
343		}
344	} else {
345		switch (type)
346		{
347		case IPLT_HASH :
348			err = remove_hash(&iph, ioctl);
349			break;
350		case IPLT_POOL :
351			err = remove_pool(&pool, ioctl);
352			break;
353		case IPLT_NONE :
354			err = 1;
355			{
356				int err_h, err_p;
357				err_h = remove_hash(&iph, ioctl);
358				err_p = remove_pool(&pool, ioctl);
359				if (err_h == 0 || err_p == 0)
360					err = 0;
361			}
362			break;
363		}
364	}
365	return (err);
366}
367
368
369int
370loadpoolfile(int argc, char *argv[], char *infile)
371{
372	int c;
373
374	while ((c = getopt(argc, argv, "dnuvf:")) != -1)
375		switch (c)
376		{
377		case 'd' :
378			opts |= OPT_DEBUG;
379			ippool_yydebug++;
380			break;
381		case 'f' :
382			if (loadpoolfile(argc, argv, optarg) != 0)
383				return (-1);
384			break;
385		case 'n' :
386			opts |= OPT_DONOTHING|OPT_DONTOPEN;
387			break;
388		case 'u' :
389			opts |= OPT_REMOVE;
390			break;
391		case 'v' :
392			opts |= OPT_VERBOSE;
393			break;
394		default :
395			usage(argv[0]);
396			break;		/* keep compiler happy */
397		}
398
399	if (argc - 1 - optind > 0)
400		usage(argv[0]);
401
402	if (opts & OPT_DEBUG)
403		fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
404
405	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
406		fd = open(IPLOOKUP_NAME, O_RDWR);
407		if (fd == -1) {
408			perror("open(IPLOOKUP_NAME)");
409			exit(1);
410		}
411	}
412
413	if (ippool_parsefile(fd, infile, ioctl) != 0)
414		return (-1);
415	return (0);
416}
417
418
419int
420poolstats(int argc, char *argv[])
421{
422	int c, type, role;
423	ipf_pool_stat_t plstat;
424	ipf_dstl_stat_t dlstat;
425	iphtstat_t htstat;
426	iplookupop_t op;
427
428	type = IPLT_ALL;
429	role = IPL_LOGALL;
430
431	bzero((char *)&op, sizeof(op));
432
433	while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
434		switch (c)
435		{
436		case 'd' :
437			opts |= OPT_DEBUG;
438			break;
439		case 'o' :
440			role = getrole(optarg);
441			if (role == IPL_LOGNONE) {
442				fprintf(stderr, "unknown role '%s'\n", optarg);
443				return (-1);
444			}
445			break;
446		case 't' :
447			type = gettype(optarg, NULL);
448			if (type != IPLT_POOL) {
449				fprintf(stderr,
450					"-s not supported for this type yet\n");
451				return (-1);
452			}
453			break;
454		case 'v' :
455			opts |= OPT_VERBOSE;
456			break;
457		default :
458			usage(argv[0]);
459			break;		/* keep compiler happy */
460		}
461
462	if (argc - 1 - optind > 0)
463		usage(argv[0]);
464
465	if (opts & OPT_DEBUG)
466		fprintf(stderr, "poolstats: opts = %#x\n", opts);
467
468	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
469		fd = open(IPLOOKUP_NAME, O_RDWR);
470		if (fd == -1) {
471			perror("open(IPLOOKUP_NAME)");
472			exit(1);
473		}
474	}
475
476	if (type == IPLT_ALL || type == IPLT_POOL) {
477		op.iplo_type = IPLT_POOL;
478		op.iplo_struct = &plstat;
479		op.iplo_size = sizeof(plstat);
480		if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
481			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
482			if (c == -1) {
483				ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
484				return (-1);
485			}
486			printf("%lu\taddress pools\n", plstat.ipls_pools);
487			printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
488		}
489	}
490
491	if (type == IPLT_ALL || type == IPLT_HASH) {
492		op.iplo_type = IPLT_HASH;
493		op.iplo_struct = &htstat;
494		op.iplo_size = sizeof(htstat);
495		if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
496			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
497			if (c == -1) {
498				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
499				return (-1);
500			}
501			printf("%lu\thash tables\n", htstat.iphs_numtables);
502			printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
503			printf("%lu\thash table no memory \n",
504				htstat.iphs_nomem);
505		}
506	}
507
508	if (type == IPLT_ALL || type == IPLT_DSTLIST) {
509		op.iplo_type = IPLT_DSTLIST;
510		op.iplo_struct = &dlstat;
511		op.iplo_size = sizeof(dlstat);
512		if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
513			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
514			if (c == -1) {
515				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
516				return (-1);
517			}
518			printf("%u\tdestination lists\n",
519			       dlstat.ipls_numlists);
520			printf("%u\tdestination list nodes\n",
521			       dlstat.ipls_numnodes);
522			printf("%lu\tdestination list no memory\n",
523			       dlstat.ipls_nomem);
524			printf("%u\tdestination list zombies\n",
525			       dlstat.ipls_numdereflists);
526			printf("%u\tdesetination list node zombies\n",
527			       dlstat.ipls_numderefnodes);
528		}
529	}
530	return (0);
531}
532
533
534int
535poolflush(int argc, char *argv[])
536{
537	int c, role, type, arg;
538	iplookupflush_t flush;
539
540	arg = IPLT_ALL;
541	type = IPLT_ALL;
542	role = IPL_LOGALL;
543
544	while ((c = getopt(argc, argv, "do:t:v")) != -1)
545		switch (c)
546		{
547		case 'd' :
548			opts |= OPT_DEBUG;
549			break;
550		case 'o' :
551			role = getrole(optarg);
552			if (role == IPL_LOGNONE) {
553				fprintf(stderr, "unknown role '%s'\n", optarg);
554				return (-1);
555			}
556			break;
557		case 't' :
558			type = gettype(optarg, NULL);
559			if (type == IPLT_NONE) {
560				fprintf(stderr, "unknown type '%s'\n", optarg);
561				return (-1);
562			}
563			break;
564		case 'v' :
565			opts |= OPT_VERBOSE;
566			break;
567		default :
568			usage(argv[0]);
569			break;		/* keep compiler happy */
570		}
571
572	if (argc - optind > 0)
573		usage(argv[0]);
574
575	if (opts & OPT_DEBUG)
576		fprintf(stderr, "poolflush: opts = %#x\n", opts);
577
578	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
579		fd = open(IPLOOKUP_NAME, O_RDWR);
580		if (fd == -1) {
581			perror("open(IPLOOKUP_NAME)");
582			exit(1);
583		}
584	}
585
586	bzero((char *)&flush, sizeof(flush));
587	flush.iplf_type = type;
588	flush.iplf_unit = role;
589	flush.iplf_arg = arg;
590
591	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
592		if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
593			ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
594			exit(1);
595		}
596
597	}
598	printf("%u object%s flushed\n", flush.iplf_count,
599	       (flush.iplf_count == 1) ? "" : "s");
600
601	return (0);
602}
603
604
605int
606getrole(char *rolename)
607{
608	int role;
609
610	if (!strcasecmp(rolename, "ipf")) {
611		role = IPL_LOGIPF;
612#if 0
613	} else if (!strcasecmp(rolename, "nat")) {
614		role = IPL_LOGNAT;
615	} else if (!strcasecmp(rolename, "state")) {
616		role = IPL_LOGSTATE;
617	} else if (!strcasecmp(rolename, "auth")) {
618		role = IPL_LOGAUTH;
619	} else if (!strcasecmp(rolename, "sync")) {
620		role = IPL_LOGSYNC;
621	} else if (!strcasecmp(rolename, "scan")) {
622		role = IPL_LOGSCAN;
623	} else if (!strcasecmp(rolename, "pool")) {
624		role = IPL_LOGLOOKUP;
625	} else if (!strcasecmp(rolename, "count")) {
626		role = IPL_LOGCOUNT;
627#endif
628	} else {
629		role = IPL_LOGNONE;
630	}
631
632	return (role);
633}
634
635
636int
637gettype(char *typename, u_int *minor)
638{
639	int type;
640
641	if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
642		type = IPLT_POOL;
643	} else if (!strcasecmp(typename, "hash")) {
644		type = IPLT_HASH;
645		if (minor != NULL)
646			*minor = IPHASH_LOOKUP;
647	} else if (!strcasecmp(typename, "group-map")) {
648		type = IPLT_HASH;
649		if (minor != NULL)
650			*minor = IPHASH_GROUPMAP;
651	} else {
652		type = IPLT_NONE;
653	}
654	return (type);
655}
656
657
658int
659poollist(int argc, char *argv[])
660{
661	char *kernel, *core, *poolname;
662	int c, role, type, live_kernel;
663	iplookupop_t op;
664
665	core = NULL;
666	kernel = NULL;
667	live_kernel = 1;
668	type = IPLT_ALL;
669	poolname = NULL;
670	role = IPL_LOGALL;
671
672	while ((c = getopt(argc, argv, "dDm:M:N:o:t:v")) != -1)
673		switch (c)
674		{
675		case 'd' :
676			opts |= OPT_DEBUG;
677			break;
678		case 'D' :
679			opts |= OPT_SAVEOUT;
680			break;
681		case 'm' :
682			poolname = optarg;
683			break;
684		case 'M' :
685			live_kernel = 0;
686			core = optarg;
687			break;
688		case 'N' :
689			live_kernel = 0;
690			kernel = optarg;
691			break;
692		case 'o' :
693			role = getrole(optarg);
694			if (role == IPL_LOGNONE) {
695				fprintf(stderr, "unknown role '%s'\n", optarg);
696				return (-1);
697			}
698			break;
699#if 0
700		case 'O' :
701			/* XXX This option does not work. This function as  */
702			/* XXX used by state and nat can be used to format  */
703			/* XXX output especially useful for scripting. It   */
704			/* XXX is left here with the intention of making    */
705			/* XXX it work for the same purpose at some point.  */
706			pool_fields = parsefields(poolfields, optarg);
707			break;
708#endif
709		case 't' :
710			type = gettype(optarg, NULL);
711			if (type == IPLT_NONE) {
712				fprintf(stderr, "unknown type '%s'\n", optarg);
713				return (-1);
714			}
715			break;
716		case 'v' :
717			opts |= OPT_VERBOSE;
718			break;
719		default :
720			usage(argv[0]);
721			break;		/* keep compiler happy */
722		}
723
724	if (argc - optind > 0)
725		usage(argv[0]);
726
727	if (opts & OPT_DEBUG)
728		fprintf(stderr, "poollist: opts = %#x\n", opts);
729
730	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
731		fd = open(IPLOOKUP_NAME, O_RDWR);
732		if (fd == -1) {
733			perror("open(IPLOOKUP_NAME)");
734			exit(1);
735		}
736	}
737
738	bzero((char *)&op, sizeof(op));
739	if (poolname != NULL) {
740		strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
741		op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
742	}
743	op.iplo_unit = role;
744
745	if (live_kernel) {
746		if (poollist_live(role, poolname, type, fd) != 0)
747			return (1);
748	} else
749		poollist_dead(role, poolname, type, kernel, core);
750	return (0);
751}
752
753
754void
755poollist_dead(int role, char *poolname, int type, char *kernel, char *core)
756{
757	iphtable_t *hptr;
758	ip_pool_t *ptr;
759
760	if (openkmem(kernel, core) == -1)
761		exit(-1);
762
763	if (type == IPLT_ALL || type == IPLT_POOL) {
764		ip_pool_t *pools[IPL_LOGSIZE];
765		struct nlist names[2] = { { "ip_pool_list" } , { "" } };
766
767		if (nlist(kernel, names) != 1)
768			return;
769
770		bzero(&pools, sizeof(pools));
771		if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
772			return;
773
774		if (role != IPL_LOGALL) {
775			ptr = pools[role];
776			while (ptr != NULL) {
777				ptr = printpool(ptr, kmemcpywrap, poolname,
778						opts, pool_fields);
779			}
780		} else {
781			for (role = 0; role <= IPL_LOGMAX; role++) {
782				ptr = pools[role];
783				while (ptr != NULL) {
784					ptr = printpool(ptr, kmemcpywrap,
785							poolname, opts,
786							pool_fields);
787				}
788			}
789			role = IPL_LOGALL;
790		}
791	}
792	if (type == IPLT_ALL || type == IPLT_HASH) {
793		iphtable_t *tables[IPL_LOGSIZE];
794		struct nlist names[2] = { { "ipf_htables" } , { "" } };
795
796		if (nlist(kernel, names) != 1)
797			return;
798
799		bzero(&tables, sizeof(tables));
800		if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
801			return;
802
803		if (role != IPL_LOGALL) {
804			hptr = tables[role];
805			while (hptr != NULL) {
806				hptr = printhash(hptr, kmemcpywrap,
807						 poolname, opts, pool_fields);
808			}
809		} else {
810			for (role = 0; role <= IPL_LOGMAX; role++) {
811				hptr = tables[role];
812				while (hptr != NULL) {
813					hptr = printhash(hptr, kmemcpywrap,
814							 poolname, opts,
815							 pool_fields);
816				}
817			}
818		}
819	}
820}
821
822
823int
824poollist_live(int role, char *poolname, int type, int fd)
825{
826	ipf_pool_stat_t plstat;
827	iplookupop_t op;
828	int c;
829
830	if (type == IPLT_ALL || type == IPLT_POOL) {
831		op.iplo_type = IPLT_POOL;
832		op.iplo_size = sizeof(plstat);
833		op.iplo_struct = &plstat;
834		op.iplo_name[0] = '\0';
835		op.iplo_arg = 0;
836
837		if (role != IPL_LOGALL) {
838			op.iplo_unit = role;
839
840			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
841			if (c == -1) {
842				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
843				return (1);
844			}
845
846			if (showpools_live(fd, role, &plstat, poolname))
847				return (1);
848		} else {
849			for (role = -1; role <= IPL_LOGMAX; role++) {
850				op.iplo_unit = role;
851
852				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
853				if (c == -1) {
854					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
855					return (1);
856				}
857
858				if (showpools_live(fd, role, &plstat, poolname))
859					return (1);
860			}
861
862			role = IPL_LOGALL;
863		}
864	}
865
866	if (type == IPLT_ALL || type == IPLT_HASH) {
867		iphtstat_t htstat;
868
869		op.iplo_type = IPLT_HASH;
870		op.iplo_size = sizeof(htstat);
871		op.iplo_struct = &htstat;
872		op.iplo_name[0] = '\0';
873		op.iplo_arg = 0;
874
875		if (role != IPL_LOGALL) {
876			op.iplo_unit = role;
877
878			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
879			if (c == -1) {
880				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
881				return (1);
882			}
883			if (showhashs_live(fd, role, &htstat, poolname))
884				return (1);
885		} else {
886			for (role = 0; role <= IPL_LOGMAX; role++) {
887
888				op.iplo_unit = role;
889				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
890				if (c == -1) {
891					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
892					return (1);
893				}
894
895				if (showhashs_live(fd, role, &htstat, poolname))
896					return(1);
897			}
898			role = IPL_LOGALL;
899		}
900	}
901
902	if (type == IPLT_ALL || type == IPLT_DSTLIST) {
903		ipf_dstl_stat_t dlstat;
904
905		op.iplo_type = IPLT_DSTLIST;
906		op.iplo_size = sizeof(dlstat);
907		op.iplo_struct = &dlstat;
908		op.iplo_name[0] = '\0';
909		op.iplo_arg = 0;
910
911		if (role != IPL_LOGALL) {
912			op.iplo_unit = role;
913
914			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
915			if (c == -1) {
916				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
917				return (1);
918			}
919			if (showdstls_live(fd, role, &dlstat, poolname))
920				return (1);
921		} else {
922			for (role = 0; role <= IPL_LOGMAX; role++) {
923
924				op.iplo_unit = role;
925				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
926				if (c == -1) {
927					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
928					return (1);
929				}
930
931				if (showdstls_live(fd, role, &dlstat, poolname))
932					return (1);
933			}
934			role = IPL_LOGALL;
935		}
936	}
937	return (0);
938}
939
940
941int
942showpools_live(int fd, int role, ipf_pool_stat_t *plstp, char *poolname)
943{
944	ipflookupiter_t iter;
945	ip_pool_t pool;
946	ipfobj_t obj;
947
948	obj.ipfo_rev = IPFILTER_VERSION;
949	obj.ipfo_type = IPFOBJ_LOOKUPITER;
950	obj.ipfo_size = sizeof(iter);
951	obj.ipfo_ptr = &iter;
952
953	iter.ili_type = IPLT_POOL;
954	iter.ili_otype = IPFLOOKUPITER_LIST;
955	iter.ili_ival = IPFGENITER_LOOKUP;
956	iter.ili_nitems = 1;
957	iter.ili_data = &pool;
958	iter.ili_unit = role;
959	*iter.ili_name = '\0';
960
961	bzero((char *)&pool, sizeof(pool));
962
963	while (plstp->ipls_list[role + 1] != NULL) {
964		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
965			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
966			return (1);
967		}
968		if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
969		    ((opts & OPT_DEBUG) != 0))
970			printpool_live(&pool, fd, poolname, opts, pool_fields);
971
972		plstp->ipls_list[role + 1] = pool.ipo_next;
973	}
974	return (0);
975}
976
977
978int
979showhashs_live(int fd, int role, iphtstat_t *htstp, char *poolname)
980{
981	ipflookupiter_t iter;
982	iphtable_t table;
983	ipfobj_t obj;
984
985	obj.ipfo_rev = IPFILTER_VERSION;
986	obj.ipfo_type = IPFOBJ_LOOKUPITER;
987	obj.ipfo_size = sizeof(iter);
988	obj.ipfo_ptr = &iter;
989
990	iter.ili_type = IPLT_HASH;
991	iter.ili_otype = IPFLOOKUPITER_LIST;
992	iter.ili_ival = IPFGENITER_LOOKUP;
993	iter.ili_nitems = 1;
994	iter.ili_data = &table;
995	iter.ili_unit = role;
996	*iter.ili_name = '\0';
997
998	while (htstp->iphs_tables != NULL) {
999		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1000			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1001			return (1);
1002		}
1003
1004		printhash_live(&table, fd, poolname, opts, pool_fields);
1005
1006		htstp->iphs_tables = table.iph_next;
1007	}
1008	return (0);
1009}
1010
1011
1012int
1013showdstls_live(int fd, int role, ipf_dstl_stat_t *dlstp, char *poolname)
1014{
1015	ipflookupiter_t iter;
1016	ippool_dst_t table;
1017	ipfobj_t obj;
1018
1019	obj.ipfo_rev = IPFILTER_VERSION;
1020	obj.ipfo_type = IPFOBJ_LOOKUPITER;
1021	obj.ipfo_size = sizeof(iter);
1022	obj.ipfo_ptr = &iter;
1023
1024	iter.ili_type = IPLT_DSTLIST;
1025	iter.ili_otype = IPFLOOKUPITER_LIST;
1026	iter.ili_ival = IPFGENITER_LOOKUP;
1027	iter.ili_nitems = 1;
1028	iter.ili_data = &table;
1029	iter.ili_unit = role;
1030	*iter.ili_name = '\0';
1031
1032	while (dlstp->ipls_list[role] != NULL) {
1033		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1034			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1035			return (1);
1036		}
1037
1038		printdstl_live(&table, fd, poolname, opts, pool_fields);
1039
1040		dlstp->ipls_list[role] = table.ipld_next;
1041	}
1042	return (0);
1043}
1044
1045
1046int
1047setnodeaddr(int type, int role, void *ptr, char *arg)
1048{
1049	struct in_addr mask;
1050	sa_family_t family;
1051	char *s;
1052
1053	if (strchr(arg, ':') == NULL) {
1054		family = AF_INET;
1055		s = strchr(arg, '/');
1056		if (s == NULL)
1057			mask.s_addr = 0xffffffff;
1058		else if (strchr(s, '.') == NULL) {
1059			if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1060				return (-1);
1061		} else {
1062			mask.s_addr = inet_addr(s + 1);
1063		}
1064		if (s != NULL)
1065			*s = '\0';
1066	} else {
1067		family = AF_INET6;
1068
1069		/* XXX for now we use mask for IPv6 prefix length */
1070		/* XXX mask should be a union with prefix */
1071		/* XXX Currently address handling is sloppy. */
1072
1073		if ((s = strchr(arg, '/')) == NULL)
1074			mask.s_addr = 128;
1075		else
1076			mask.s_addr = atoi(s + 1);
1077	}
1078
1079	if (type == IPLT_POOL) {
1080		ip_pool_node_t *node = ptr;
1081
1082		node->ipn_addr.adf_family = family;
1083
1084#ifdef USE_INET6
1085		if (node->ipn_addr.adf_family == AF_INET) {
1086#endif
1087			node->ipn_addr.adf_len = offsetof(addrfamily_t,
1088							  adf_addr) +
1089						 sizeof(struct in_addr);
1090			node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1091#ifdef USE_INET6
1092		} else {
1093			node->ipn_addr.adf_len = offsetof(addrfamily_t,
1094							  adf_addr) +
1095						 sizeof(struct in6_addr);
1096			inet_pton(AF_INET6, arg,
1097				&node->ipn_addr.adf_addr.in6.s6_addr);
1098		}
1099#endif
1100		node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1101		node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1102	} else if (type == IPLT_HASH) {
1103		iphtent_t *node = ptr;
1104
1105		node->ipe_family = family;
1106		node->ipe_unit = role;
1107
1108#ifdef USE_INET6
1109		if (node->ipe_family == AF_INET) {
1110#endif
1111			node->ipe_addr.in4.s_addr = inet_addr(arg);
1112			node->ipe_mask.in4.s_addr = mask.s_addr;
1113#ifdef USE_INET6
1114		} else {
1115			inet_pton(AF_INET6, arg,
1116				&node->ipe_addr.in6.__u6_addr.__u6_addr32);
1117			node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1118				mask.s_addr;
1119			node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1120			node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1121			node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;
1122		}
1123#endif
1124	}
1125
1126	return (0);
1127}
1128