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