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