xref: /freebsd/sbin/ipf/ippool/ippool.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
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, "dm:M:N:o:t:v")) != -1)
674 		switch (c)
675 		{
676 		case 'd' :
677 			opts |= OPT_DEBUG;
678 			break;
679 		case 'm' :
680 			poolname = optarg;
681 			break;
682 		case 'M' :
683 			live_kernel = 0;
684 			core = optarg;
685 			break;
686 		case 'N' :
687 			live_kernel = 0;
688 			kernel = optarg;
689 			break;
690 		case 'o' :
691 			role = getrole(optarg);
692 			if (role == IPL_LOGNONE) {
693 				fprintf(stderr, "unknown role '%s'\n", optarg);
694 				return (-1);
695 			}
696 			break;
697 #if 0
698 		case 'O' :
699 			/* XXX This option does not work. This function as  */
700 			/* XXX used by state and nat can be used to format  */
701 			/* XXX output especially useful for scripting. It   */
702 			/* XXX is left here with the intention of making    */
703 			/* XXX it work for the same purpose at some point.  */
704 			pool_fields = parsefields(poolfields, optarg);
705 			break;
706 #endif
707 		case 't' :
708 			type = gettype(optarg, NULL);
709 			if (type == IPLT_NONE) {
710 				fprintf(stderr, "unknown type '%s'\n", optarg);
711 				return (-1);
712 			}
713 			break;
714 		case 'v' :
715 			opts |= OPT_VERBOSE;
716 			break;
717 		default :
718 			usage(argv[0]);
719 			break;		/* keep compiler happy */
720 		}
721 
722 	if (argc - optind > 0)
723 		usage(argv[0]);
724 
725 	if (opts & OPT_DEBUG)
726 		fprintf(stderr, "poollist: opts = %#x\n", opts);
727 
728 	if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
729 		fd = open(IPLOOKUP_NAME, O_RDWR);
730 		if (fd == -1) {
731 			perror("open(IPLOOKUP_NAME)");
732 			exit(1);
733 		}
734 	}
735 
736 	bzero((char *)&op, sizeof(op));
737 	if (poolname != NULL) {
738 		strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
739 		op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
740 	}
741 	op.iplo_unit = role;
742 
743 	if (live_kernel)
744 		poollist_live(role, poolname, type, fd);
745 	else
746 		poollist_dead(role, poolname, type, kernel, core);
747 	return (0);
748 }
749 
750 
751 void
752 poollist_dead(int role, char *poolname, int type, char *kernel, char *core)
753 {
754 	iphtable_t *hptr;
755 	ip_pool_t *ptr;
756 
757 	if (openkmem(kernel, core) == -1)
758 		exit(-1);
759 
760 	if (type == IPLT_ALL || type == IPLT_POOL) {
761 		ip_pool_t *pools[IPL_LOGSIZE];
762 		struct nlist names[2] = { { "ip_pool_list" } , { "" } };
763 
764 		if (nlist(kernel, names) != 1)
765 			return;
766 
767 		bzero(&pools, sizeof(pools));
768 		if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
769 			return;
770 
771 		if (role != IPL_LOGALL) {
772 			ptr = pools[role];
773 			while (ptr != NULL) {
774 				ptr = printpool(ptr, kmemcpywrap, poolname,
775 						opts, pool_fields);
776 			}
777 		} else {
778 			for (role = 0; role <= IPL_LOGMAX; role++) {
779 				ptr = pools[role];
780 				while (ptr != NULL) {
781 					ptr = printpool(ptr, kmemcpywrap,
782 							poolname, opts,
783 							pool_fields);
784 				}
785 			}
786 			role = IPL_LOGALL;
787 		}
788 	}
789 	if (type == IPLT_ALL || type == IPLT_HASH) {
790 		iphtable_t *tables[IPL_LOGSIZE];
791 		struct nlist names[2] = { { "ipf_htables" } , { "" } };
792 
793 		if (nlist(kernel, names) != 1)
794 			return;
795 
796 		bzero(&tables, sizeof(tables));
797 		if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
798 			return;
799 
800 		if (role != IPL_LOGALL) {
801 			hptr = tables[role];
802 			while (hptr != NULL) {
803 				hptr = printhash(hptr, kmemcpywrap,
804 						 poolname, opts, pool_fields);
805 			}
806 		} else {
807 			for (role = 0; role <= IPL_LOGMAX; role++) {
808 				hptr = tables[role];
809 				while (hptr != NULL) {
810 					hptr = printhash(hptr, kmemcpywrap,
811 							 poolname, opts,
812 							 pool_fields);
813 				}
814 			}
815 		}
816 	}
817 }
818 
819 
820 void
821 poollist_live(int role, char *poolname, int type, int fd)
822 {
823 	ipf_pool_stat_t plstat;
824 	iplookupop_t op;
825 	int c;
826 
827 	if (type == IPLT_ALL || type == IPLT_POOL) {
828 		op.iplo_type = IPLT_POOL;
829 		op.iplo_size = sizeof(plstat);
830 		op.iplo_struct = &plstat;
831 		op.iplo_name[0] = '\0';
832 		op.iplo_arg = 0;
833 
834 		if (role != IPL_LOGALL) {
835 			op.iplo_unit = role;
836 
837 			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
838 			if (c == -1) {
839 				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
840 				return;
841 			}
842 
843 			showpools_live(fd, role, &plstat, poolname);
844 		} else {
845 			for (role = -1; role <= IPL_LOGMAX; role++) {
846 				op.iplo_unit = role;
847 
848 				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
849 				if (c == -1) {
850 					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
851 					return;
852 				}
853 
854 				showpools_live(fd, role, &plstat, poolname);
855 			}
856 
857 			role = IPL_LOGALL;
858 		}
859 	}
860 
861 	if (type == IPLT_ALL || type == IPLT_HASH) {
862 		iphtstat_t htstat;
863 
864 		op.iplo_type = IPLT_HASH;
865 		op.iplo_size = sizeof(htstat);
866 		op.iplo_struct = &htstat;
867 		op.iplo_name[0] = '\0';
868 		op.iplo_arg = 0;
869 
870 		if (role != IPL_LOGALL) {
871 			op.iplo_unit = role;
872 
873 			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
874 			if (c == -1) {
875 				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
876 				return;
877 			}
878 			showhashs_live(fd, role, &htstat, poolname);
879 		} else {
880 			for (role = 0; role <= IPL_LOGMAX; role++) {
881 
882 				op.iplo_unit = role;
883 				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
884 				if (c == -1) {
885 					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
886 					return;
887 				}
888 
889 				showhashs_live(fd, role, &htstat, poolname);
890 			}
891 			role = IPL_LOGALL;
892 		}
893 	}
894 
895 	if (type == IPLT_ALL || type == IPLT_DSTLIST) {
896 		ipf_dstl_stat_t dlstat;
897 
898 		op.iplo_type = IPLT_DSTLIST;
899 		op.iplo_size = sizeof(dlstat);
900 		op.iplo_struct = &dlstat;
901 		op.iplo_name[0] = '\0';
902 		op.iplo_arg = 0;
903 
904 		if (role != IPL_LOGALL) {
905 			op.iplo_unit = role;
906 
907 			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
908 			if (c == -1) {
909 				ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
910 				return;
911 			}
912 			showdstls_live(fd, role, &dlstat, poolname);
913 		} else {
914 			for (role = 0; role <= IPL_LOGMAX; role++) {
915 
916 				op.iplo_unit = role;
917 				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
918 				if (c == -1) {
919 					ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
920 					return;
921 				}
922 
923 				showdstls_live(fd, role, &dlstat, poolname);
924 			}
925 			role = IPL_LOGALL;
926 		}
927 	}
928 }
929 
930 
931 void
932 showpools_live(int fd, int role, ipf_pool_stat_t *plstp, char *poolname)
933 {
934 	ipflookupiter_t iter;
935 	ip_pool_t pool;
936 	ipfobj_t obj;
937 
938 	obj.ipfo_rev = IPFILTER_VERSION;
939 	obj.ipfo_type = IPFOBJ_LOOKUPITER;
940 	obj.ipfo_size = sizeof(iter);
941 	obj.ipfo_ptr = &iter;
942 
943 	iter.ili_type = IPLT_POOL;
944 	iter.ili_otype = IPFLOOKUPITER_LIST;
945 	iter.ili_ival = IPFGENITER_LOOKUP;
946 	iter.ili_nitems = 1;
947 	iter.ili_data = &pool;
948 	iter.ili_unit = role;
949 	*iter.ili_name = '\0';
950 
951 	bzero((char *)&pool, sizeof(pool));
952 
953 	while (plstp->ipls_list[role + 1] != NULL) {
954 		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
955 			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
956 			break;
957 		}
958 		if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
959 		    ((opts & OPT_DEBUG) != 0))
960 			printpool_live(&pool, fd, poolname, opts, pool_fields);
961 
962 		plstp->ipls_list[role + 1] = pool.ipo_next;
963 	}
964 }
965 
966 
967 void
968 showhashs_live(int fd, int role, iphtstat_t *htstp, char *poolname)
969 {
970 	ipflookupiter_t iter;
971 	iphtable_t table;
972 	ipfobj_t obj;
973 
974 	obj.ipfo_rev = IPFILTER_VERSION;
975 	obj.ipfo_type = IPFOBJ_LOOKUPITER;
976 	obj.ipfo_size = sizeof(iter);
977 	obj.ipfo_ptr = &iter;
978 
979 	iter.ili_type = IPLT_HASH;
980 	iter.ili_otype = IPFLOOKUPITER_LIST;
981 	iter.ili_ival = IPFGENITER_LOOKUP;
982 	iter.ili_nitems = 1;
983 	iter.ili_data = &table;
984 	iter.ili_unit = role;
985 	*iter.ili_name = '\0';
986 
987 	while (htstp->iphs_tables != NULL) {
988 		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
989 			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
990 			break;
991 		}
992 
993 		printhash_live(&table, fd, poolname, opts, pool_fields);
994 
995 		htstp->iphs_tables = table.iph_next;
996 	}
997 }
998 
999 
1000 void
1001 showdstls_live(int fd, int role, ipf_dstl_stat_t *dlstp, char *poolname)
1002 {
1003 	ipflookupiter_t iter;
1004 	ippool_dst_t table;
1005 	ipfobj_t obj;
1006 
1007 	obj.ipfo_rev = IPFILTER_VERSION;
1008 	obj.ipfo_type = IPFOBJ_LOOKUPITER;
1009 	obj.ipfo_size = sizeof(iter);
1010 	obj.ipfo_ptr = &iter;
1011 
1012 	iter.ili_type = IPLT_DSTLIST;
1013 	iter.ili_otype = IPFLOOKUPITER_LIST;
1014 	iter.ili_ival = IPFGENITER_LOOKUP;
1015 	iter.ili_nitems = 1;
1016 	iter.ili_data = &table;
1017 	iter.ili_unit = role;
1018 	*iter.ili_name = '\0';
1019 
1020 	while (dlstp->ipls_list[role] != NULL) {
1021 		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1022 			ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1023 			break;
1024 		}
1025 
1026 		printdstl_live(&table, fd, poolname, opts, pool_fields);
1027 
1028 		dlstp->ipls_list[role] = table.ipld_next;
1029 	}
1030 }
1031 
1032 
1033 int
1034 setnodeaddr(int type, int role, void *ptr, char *arg)
1035 {
1036 	struct in_addr mask;
1037 	sa_family_t family;
1038 	char *s;
1039 
1040 	if (strchr(arg, ':') == NULL) {
1041 		family = AF_INET;
1042 		s = strchr(arg, '/');
1043 		if (s == NULL)
1044 			mask.s_addr = 0xffffffff;
1045 		else if (strchr(s, '.') == NULL) {
1046 			if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1047 				return (-1);
1048 		} else {
1049 			mask.s_addr = inet_addr(s + 1);
1050 		}
1051 		if (s != NULL)
1052 			*s = '\0';
1053 	} else {
1054 		family = AF_INET6;
1055 
1056 		/* XXX for now we use mask for IPv6 prefix length */
1057 		/* XXX mask should be a union with prefix */
1058 		/* XXX Currently address handling is sloppy. */
1059 
1060 		if ((s = strchr(arg, '/')) == NULL)
1061 			mask.s_addr = 128;
1062 		else
1063 			mask.s_addr = atoi(s + 1);
1064 	}
1065 
1066 	if (type == IPLT_POOL) {
1067 		ip_pool_node_t *node = ptr;
1068 
1069 		node->ipn_addr.adf_family = family;
1070 
1071 #ifdef USE_INET6
1072 		if (node->ipn_addr.adf_family == AF_INET) {
1073 #endif
1074 			node->ipn_addr.adf_len = offsetof(addrfamily_t,
1075 							  adf_addr) +
1076 						 sizeof(struct in_addr);
1077 			node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1078 #ifdef USE_INET6
1079 		} else {
1080 			node->ipn_addr.adf_len = offsetof(addrfamily_t,
1081 							  adf_addr) +
1082 						 sizeof(struct in6_addr);
1083 			inet_pton(AF_INET6, arg,
1084 				&node->ipn_addr.adf_addr.in6.s6_addr);
1085 		}
1086 #endif
1087 		node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1088 		node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1089 	} else if (type == IPLT_HASH) {
1090 		iphtent_t *node = ptr;
1091 
1092 		node->ipe_family = family;
1093 		node->ipe_unit = role;
1094 
1095 #ifdef USE_INET6
1096 		if (node->ipe_family == AF_INET) {
1097 #endif
1098 			node->ipe_addr.in4.s_addr = inet_addr(arg);
1099 			node->ipe_mask.in4.s_addr = mask.s_addr;
1100 #ifdef USE_INET6
1101 		} else {
1102 			inet_pton(AF_INET6, arg,
1103 				&node->ipe_addr.in6.__u6_addr.__u6_addr32);
1104 			node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1105 				mask.s_addr;
1106 			node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1107 			node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1108 			node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;
1109 		}
1110 #endif
1111 	}
1112 
1113 	return (0);
1114 }
1115