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