xref: /freebsd/sbin/ipf/ippool/ippool.c (revision 32c7dde816fd1d738a48af82bf490307cb7b4739)
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 int	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 int	showpools_live(int, int, ipf_pool_stat_t *, char *);
57 int	showhashs_live(int, int, iphtstat_t *, char *);
58 int	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 		if (poollist_live(role, poolname, type, fd) != 0)
748 			return (1);
749 	} else
750 		poollist_dead(role, poolname, type, kernel, core);
751 	return (0);
752 }
753 
754 
755 void
756 poollist_dead(int role, char *poolname, int type, char *kernel, char *core)
757 {
758 	iphtable_t *hptr;
759 	ip_pool_t *ptr;
760 
761 	if (openkmem(kernel, core) == -1)
762 		exit(-1);
763 
764 	if (type == IPLT_ALL || type == IPLT_POOL) {
765 		ip_pool_t *pools[IPL_LOGSIZE];
766 		struct nlist names[2] = { { "ip_pool_list" } , { "" } };
767 
768 		if (nlist(kernel, names) != 1)
769 			return;
770 
771 		bzero(&pools, sizeof(pools));
772 		if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
773 			return;
774 
775 		if (role != IPL_LOGALL) {
776 			ptr = pools[role];
777 			while (ptr != NULL) {
778 				ptr = printpool(ptr, kmemcpywrap, poolname,
779 						opts, pool_fields);
780 			}
781 		} else {
782 			for (role = 0; role <= IPL_LOGMAX; role++) {
783 				ptr = pools[role];
784 				while (ptr != NULL) {
785 					ptr = printpool(ptr, kmemcpywrap,
786 							poolname, opts,
787 							pool_fields);
788 				}
789 			}
790 			role = IPL_LOGALL;
791 		}
792 	}
793 	if (type == IPLT_ALL || type == IPLT_HASH) {
794 		iphtable_t *tables[IPL_LOGSIZE];
795 		struct nlist names[2] = { { "ipf_htables" } , { "" } };
796 
797 		if (nlist(kernel, names) != 1)
798 			return;
799 
800 		bzero(&tables, sizeof(tables));
801 		if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
802 			return;
803 
804 		if (role != IPL_LOGALL) {
805 			hptr = tables[role];
806 			while (hptr != NULL) {
807 				hptr = printhash(hptr, kmemcpywrap,
808 						 poolname, opts, pool_fields);
809 			}
810 		} else {
811 			for (role = 0; role <= IPL_LOGMAX; role++) {
812 				hptr = tables[role];
813 				while (hptr != NULL) {
814 					hptr = printhash(hptr, kmemcpywrap,
815 							 poolname, opts,
816 							 pool_fields);
817 				}
818 			}
819 		}
820 	}
821 }
822 
823 
824 int
825 poollist_live(int role, char *poolname, int type, int fd)
826 {
827 	ipf_pool_stat_t plstat;
828 	iplookupop_t op;
829 	int c;
830 
831 	if (type == IPLT_ALL || type == IPLT_POOL) {
832 		op.iplo_type = IPLT_POOL;
833 		op.iplo_size = sizeof(plstat);
834 		op.iplo_struct = &plstat;
835 		op.iplo_name[0] = '\0';
836 		op.iplo_arg = 0;
837 
838 		if (role != IPL_LOGALL) {
839 			op.iplo_unit = role;
840 
841 			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
842 			if (c == -1) {
843 				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
844 				return (1);
845 			}
846 
847 			if (showpools_live(fd, role, &plstat, poolname))
848 				return (1);
849 		} else {
850 			for (role = -1; role <= IPL_LOGMAX; role++) {
851 				op.iplo_unit = role;
852 
853 				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
854 				if (c == -1) {
855 					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
856 					return (1);
857 				}
858 
859 				if (showpools_live(fd, role, &plstat, poolname))
860 					return (1);
861 			}
862 
863 			role = IPL_LOGALL;
864 		}
865 	}
866 
867 	if (type == IPLT_ALL || type == IPLT_HASH) {
868 		iphtstat_t htstat;
869 
870 		op.iplo_type = IPLT_HASH;
871 		op.iplo_size = sizeof(htstat);
872 		op.iplo_struct = &htstat;
873 		op.iplo_name[0] = '\0';
874 		op.iplo_arg = 0;
875 
876 		if (role != IPL_LOGALL) {
877 			op.iplo_unit = role;
878 
879 			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
880 			if (c == -1) {
881 				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
882 				return (1);
883 			}
884 			if (showhashs_live(fd, role, &htstat, poolname))
885 				return (1);
886 		} else {
887 			for (role = 0; role <= IPL_LOGMAX; role++) {
888 
889 				op.iplo_unit = role;
890 				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
891 				if (c == -1) {
892 					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
893 					return (1);
894 				}
895 
896 				if (showhashs_live(fd, role, &htstat, poolname))
897 					return(1);
898 			}
899 			role = IPL_LOGALL;
900 		}
901 	}
902 
903 	if (type == IPLT_ALL || type == IPLT_DSTLIST) {
904 		ipf_dstl_stat_t dlstat;
905 
906 		op.iplo_type = IPLT_DSTLIST;
907 		op.iplo_size = sizeof(dlstat);
908 		op.iplo_struct = &dlstat;
909 		op.iplo_name[0] = '\0';
910 		op.iplo_arg = 0;
911 
912 		if (role != IPL_LOGALL) {
913 			op.iplo_unit = role;
914 
915 			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
916 			if (c == -1) {
917 				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
918 				return (1);
919 			}
920 			if (showdstls_live(fd, role, &dlstat, poolname))
921 				return (1);
922 		} else {
923 			for (role = 0; role <= IPL_LOGMAX; role++) {
924 
925 				op.iplo_unit = role;
926 				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
927 				if (c == -1) {
928 					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
929 					return (1);
930 				}
931 
932 				if (showdstls_live(fd, role, &dlstat, poolname))
933 					return (1);
934 			}
935 			role = IPL_LOGALL;
936 		}
937 	}
938 	return (0);
939 }
940 
941 
942 int
943 showpools_live(int fd, int role, ipf_pool_stat_t *plstp, char *poolname)
944 {
945 	ipflookupiter_t iter;
946 	ip_pool_t pool;
947 	ipfobj_t obj;
948 
949 	obj.ipfo_rev = IPFILTER_VERSION;
950 	obj.ipfo_type = IPFOBJ_LOOKUPITER;
951 	obj.ipfo_size = sizeof(iter);
952 	obj.ipfo_ptr = &iter;
953 
954 	iter.ili_type = IPLT_POOL;
955 	iter.ili_otype = IPFLOOKUPITER_LIST;
956 	iter.ili_ival = IPFGENITER_LOOKUP;
957 	iter.ili_nitems = 1;
958 	iter.ili_data = &pool;
959 	iter.ili_unit = role;
960 	*iter.ili_name = '\0';
961 
962 	bzero((char *)&pool, sizeof(pool));
963 
964 	while (plstp->ipls_list[role + 1] != NULL) {
965 		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
966 			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
967 			return (1);
968 		}
969 		if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
970 		    ((opts & OPT_DEBUG) != 0))
971 			printpool_live(&pool, fd, poolname, opts, pool_fields);
972 
973 		plstp->ipls_list[role + 1] = pool.ipo_next;
974 	}
975 	return (0);
976 }
977 
978 
979 int
980 showhashs_live(int fd, int role, iphtstat_t *htstp, char *poolname)
981 {
982 	ipflookupiter_t iter;
983 	iphtable_t table;
984 	ipfobj_t obj;
985 
986 	obj.ipfo_rev = IPFILTER_VERSION;
987 	obj.ipfo_type = IPFOBJ_LOOKUPITER;
988 	obj.ipfo_size = sizeof(iter);
989 	obj.ipfo_ptr = &iter;
990 
991 	iter.ili_type = IPLT_HASH;
992 	iter.ili_otype = IPFLOOKUPITER_LIST;
993 	iter.ili_ival = IPFGENITER_LOOKUP;
994 	iter.ili_nitems = 1;
995 	iter.ili_data = &table;
996 	iter.ili_unit = role;
997 	*iter.ili_name = '\0';
998 
999 	while (htstp->iphs_tables != NULL) {
1000 		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1001 			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1002 			return (1);
1003 		}
1004 
1005 		printhash_live(&table, fd, poolname, opts, pool_fields);
1006 
1007 		htstp->iphs_tables = table.iph_next;
1008 	}
1009 	return (0);
1010 }
1011 
1012 
1013 int
1014 showdstls_live(int fd, int role, ipf_dstl_stat_t *dlstp, char *poolname)
1015 {
1016 	ipflookupiter_t iter;
1017 	ippool_dst_t table;
1018 	ipfobj_t obj;
1019 
1020 	obj.ipfo_rev = IPFILTER_VERSION;
1021 	obj.ipfo_type = IPFOBJ_LOOKUPITER;
1022 	obj.ipfo_size = sizeof(iter);
1023 	obj.ipfo_ptr = &iter;
1024 
1025 	iter.ili_type = IPLT_DSTLIST;
1026 	iter.ili_otype = IPFLOOKUPITER_LIST;
1027 	iter.ili_ival = IPFGENITER_LOOKUP;
1028 	iter.ili_nitems = 1;
1029 	iter.ili_data = &table;
1030 	iter.ili_unit = role;
1031 	*iter.ili_name = '\0';
1032 
1033 	while (dlstp->ipls_list[role] != NULL) {
1034 		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1035 			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1036 			return (1);
1037 		}
1038 
1039 		printdstl_live(&table, fd, poolname, opts, pool_fields);
1040 
1041 		dlstp->ipls_list[role] = table.ipld_next;
1042 	}
1043 	return (0);
1044 }
1045 
1046 
1047 int
1048 setnodeaddr(int type, int role, void *ptr, char *arg)
1049 {
1050 	struct in_addr mask;
1051 	sa_family_t family;
1052 	char *s;
1053 
1054 	if (strchr(arg, ':') == NULL) {
1055 		family = AF_INET;
1056 		s = strchr(arg, '/');
1057 		if (s == NULL)
1058 			mask.s_addr = 0xffffffff;
1059 		else if (strchr(s, '.') == NULL) {
1060 			if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1061 				return (-1);
1062 		} else {
1063 			mask.s_addr = inet_addr(s + 1);
1064 		}
1065 		if (s != NULL)
1066 			*s = '\0';
1067 	} else {
1068 		family = AF_INET6;
1069 
1070 		/* XXX for now we use mask for IPv6 prefix length */
1071 		/* XXX mask should be a union with prefix */
1072 		/* XXX Currently address handling is sloppy. */
1073 
1074 		if ((s = strchr(arg, '/')) == NULL)
1075 			mask.s_addr = 128;
1076 		else
1077 			mask.s_addr = atoi(s + 1);
1078 	}
1079 
1080 	if (type == IPLT_POOL) {
1081 		ip_pool_node_t *node = ptr;
1082 
1083 		node->ipn_addr.adf_family = family;
1084 
1085 #ifdef USE_INET6
1086 		if (node->ipn_addr.adf_family == AF_INET) {
1087 #endif
1088 			node->ipn_addr.adf_len = offsetof(addrfamily_t,
1089 							  adf_addr) +
1090 						 sizeof(struct in_addr);
1091 			node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1092 #ifdef USE_INET6
1093 		} else {
1094 			node->ipn_addr.adf_len = offsetof(addrfamily_t,
1095 							  adf_addr) +
1096 						 sizeof(struct in6_addr);
1097 			inet_pton(AF_INET6, arg,
1098 				&node->ipn_addr.adf_addr.in6.s6_addr);
1099 		}
1100 #endif
1101 		node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1102 		node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1103 	} else if (type == IPLT_HASH) {
1104 		iphtent_t *node = ptr;
1105 
1106 		node->ipe_family = family;
1107 		node->ipe_unit = role;
1108 
1109 #ifdef USE_INET6
1110 		if (node->ipe_family == AF_INET) {
1111 #endif
1112 			node->ipe_addr.in4.s_addr = inet_addr(arg);
1113 			node->ipe_mask.in4.s_addr = mask.s_addr;
1114 #ifdef USE_INET6
1115 		} else {
1116 			inet_pton(AF_INET6, arg,
1117 				&node->ipe_addr.in6.__u6_addr.__u6_addr32);
1118 			node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1119 				mask.s_addr;
1120 			node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1121 			node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1122 			node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;
1123 		}
1124 #endif
1125 	}
1126 
1127 	return (0);
1128 }
1129