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