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