ippool.c revision 145511
1/*	$NetBSD$	*/
2
3/*
4 * Copyright (C) 2003 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#if __FreeBSD_version >= 300000
19# include <net/if_var.h>
20#endif
21#include <netinet/in.h>
22
23#include <arpa/inet.h>
24
25#include <stdio.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <string.h>
29#include <netdb.h>
30#include <ctype.h>
31#include <unistd.h>
32
33#include "ipf.h"
34#include "netinet/ip_lookup.h"
35#include "netinet/ip_pool.h"
36#include "netinet/ip_htable.h"
37#include "kmem.h"
38
39
40extern	int	ippool_yyparse __P((void));
41extern	int	ippool_yydebug;
42extern	FILE	*ippool_yyin;
43extern	char	*optarg;
44extern	int	lineNum;
45
46void	showpools __P((ip_pool_stat_t *));
47void	usage __P((char *));
48int	main __P((int, char **));
49int	poolcommand __P((int, int, char *[]));
50int	poolnodecommand __P((int, int, char *[]));
51int	loadpoolfile __P((int, char *[], char *));
52int	poollist __P((int, char *[]));
53int	poolflush __P((int, char *[]));
54int	poolstats __P((int, char *[]));
55int	gettype __P((char *, u_int *));
56int	getrole __P((char *));
57
58int	opts = 0;
59int	fd = -1;
60int	use_inet6 = 0;
61
62
63void usage(prog)
64char *prog;
65{
66	fprintf(stderr, "Usage:\t%s\n", prog);
67	fprintf(stderr, "\t\t\t-a [-dnv] [-m <name>] [-o <role>] -i <ipaddr>[/netmask]\n");
68	fprintf(stderr, "\t\t\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
69	fprintf(stderr, "\t\t\t-f <file> [-dnuv]\n");
70	fprintf(stderr, "\t\t\t-F [-dv] [-o <role>] [-t <type>]\n");
71	fprintf(stderr, "\t\t\t-l [-dv] [-m <name>] [-t <type>]\n");
72	fprintf(stderr, "\t\t\t-r [-dnv] [-m <name>] [-o <role>] -i <ipaddr>[/netmask]\n");
73	fprintf(stderr, "\t\t\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
74	fprintf(stderr, "\t\t\t-s [-dtv] [-M <core>] [-N <namelist>]\n");
75	exit(1);
76}
77
78
79int main(argc, argv)
80int argc;
81char *argv[];
82{
83	int err;
84
85	if (argc < 2)
86		usage(argv[0]);
87
88	switch (getopt(argc, argv, "aAf:FlrRs"))
89	{
90	case 'a' :
91		err = poolnodecommand(0, argc, argv);
92		break;
93	case 'A' :
94		err = poolcommand(0, argc, argv);
95		break;
96	case 'f' :
97		err = loadpoolfile(argc, argv, optarg);
98		break;
99	case 'F' :
100		err = poolflush(argc, argv);
101		break;
102	case 'l' :
103		err = poollist(argc, argv);
104		break;
105	case 'r' :
106		err = poolnodecommand(1, argc, argv);
107		break;
108	case 'R' :
109		err = poolcommand(1, argc, argv);
110		break;
111	case 's' :
112		err = poolstats(argc, argv);
113		break;
114	default :
115		exit(1);
116	}
117
118	return err;
119}
120
121
122int poolnodecommand(remove, argc, argv)
123int remove, argc;
124char *argv[];
125{
126	char *poolname = NULL, *s;
127	int err, c, ipset, role;
128	ip_pool_node_t node;
129	struct in_addr mask;
130
131	ipset = 0;
132	role = IPL_LOGIPF;
133	bzero((char *)&node, sizeof(node));
134
135	while ((c = getopt(argc, argv, "di:m:no:Rv")) != -1)
136		switch (c)
137		{
138		case 'd' :
139			opts |= OPT_DEBUG;
140			ippool_yydebug++;
141			break;
142		case 'i' :
143			s = strchr(optarg, '/');
144			if (s == NULL)
145				mask.s_addr = 0xffffffff;
146			else if (strchr(s, '.') == NULL) {
147				if (ntomask(4, atoi(s + 1), &mask.s_addr) != 0)
148					return -1;
149			} else {
150				mask.s_addr = inet_addr(s + 1);
151			}
152			if (s != NULL)
153				*s = '\0';
154			ipset = 1;
155			node.ipn_addr.adf_len = sizeof(node.ipn_addr);
156			node.ipn_addr.adf_addr.in4.s_addr = inet_addr(optarg);
157			node.ipn_mask.adf_len = sizeof(node.ipn_mask);
158			node.ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
159			break;
160		case 'm' :
161			poolname = optarg;
162			break;
163		case 'n' :
164			opts |= OPT_DONOTHING;
165			break;
166		case 'o' :
167			role = getrole(optarg);
168			if (role == IPL_LOGNONE)
169				return -1;
170			break;
171		case 'R' :
172			opts |= OPT_NORESOLVE;
173			break;
174		case 'v' :
175			opts |= OPT_VERBOSE;
176			break;
177		}
178
179	if (opts & OPT_DEBUG)
180		fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
181
182	if (ipset == 0)
183		return -1;
184	if (poolname == NULL) {
185		fprintf(stderr, "poolname not given with add/remove node\n");
186		return -1;
187	}
188
189	if (remove == 0)
190		err = load_poolnode(0, poolname, &node, ioctl);
191	else
192		err = remove_poolnode(0, poolname, &node, ioctl);
193	return err;
194}
195
196
197int poolcommand(remove, argc, argv)
198int remove, argc;
199char *argv[];
200{
201	int type, role, c, err;
202	char *poolname;
203	iphtable_t iph;
204	ip_pool_t pool;
205
206	err = 1;
207	role = 0;
208	type = 0;
209	poolname = NULL;
210	role = IPL_LOGIPF;
211	bzero((char *)&iph, sizeof(iph));
212	bzero((char *)&pool, sizeof(pool));
213
214	while ((c = getopt(argc, argv, "dm:no:RSt:v")) != -1)
215		switch (c)
216		{
217		case 'd' :
218			opts |= OPT_DEBUG;
219			ippool_yydebug++;
220			break;
221		case 'm' :
222			poolname = optarg;
223			break;
224		case 'n' :
225			opts |= OPT_DONOTHING;
226			break;
227		case 'o' :
228			role = getrole(optarg);
229			if (role == IPL_LOGNONE) {
230				fprintf(stderr, "unknown role '%s'\n", optarg);
231				return -1;
232			}
233			break;
234		case 'R' :
235			opts |= OPT_NORESOLVE;
236			break;
237		case 'S' :
238			iph.iph_seed = atoi(optarg);
239			break;
240		case 't' :
241			type = gettype(optarg, &iph.iph_type);
242			if (type == IPLT_NONE) {
243				fprintf(stderr, "unknown type '%s'\n", optarg);
244				return -1;
245			}
246			break;
247		case 'v' :
248			opts |= OPT_VERBOSE;
249			break;
250		}
251
252	if (opts & OPT_DEBUG)
253		fprintf(stderr, "poolcommand: opts = %#x\n", opts);
254
255	if (poolname == NULL) {
256		fprintf(stderr, "poolname not given with add/remove pool\n");
257		return -1;
258	}
259
260	if (type == IPLT_HASH) {
261		strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
262		iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
263		iph.iph_unit = role;
264	} else if (type == IPLT_POOL) {
265		strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
266		pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
267		pool.ipo_unit = role;
268	}
269
270	if (remove == 0) {
271		switch (type)
272		{
273		case IPLT_HASH :
274			err = load_hash(&iph, NULL, ioctl);
275			break;
276		case IPLT_POOL :
277			err = load_pool(&pool, ioctl);
278			break;
279		}
280	} else {
281		switch (type)
282		{
283		case IPLT_HASH :
284			err = remove_hash(&iph, ioctl);
285			break;
286		case IPLT_POOL :
287			err = remove_pool(&pool, ioctl);
288			break;
289		}
290	}
291	return err;
292}
293
294
295int loadpoolfile(argc, argv, infile)
296int argc;
297char *argv[], *infile;
298{
299	int c;
300
301	infile = optarg;
302
303	while ((c = getopt(argc, argv, "dnRuv")) != -1)
304		switch (c)
305		{
306		case 'd' :
307			opts |= OPT_DEBUG;
308			ippool_yydebug++;
309			break;
310		case 'n' :
311			opts |= OPT_DONOTHING;
312			break;
313		case 'R' :
314			opts |= OPT_NORESOLVE;
315			break;
316		case 'u' :
317			opts |= OPT_REMOVE;
318			break;
319		case 'v' :
320			opts |= OPT_VERBOSE;
321			break;
322		}
323
324	if (opts & OPT_DEBUG)
325		fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
326
327	if (!(opts & OPT_DONOTHING) && (fd == -1)) {
328		fd = open(IPLOOKUP_NAME, O_RDWR);
329		if (fd == -1) {
330			perror("open(IPLOOKUP_NAME)");
331			exit(1);
332		}
333	}
334
335	if (ippool_parsefile(fd, infile, ioctl) != 0)
336		return -1;
337	return 0;
338}
339
340
341int poollist(argc, argv)
342int argc;
343char *argv[];
344{
345	char *kernel, *core, *poolname;
346	int c, role, type, live_kernel;
347	ip_pool_stat_t *plstp, plstat;
348	iphtstat_t *htstp, htstat;
349	iphtable_t *hptr;
350	iplookupop_t op;
351	ip_pool_t *ptr;
352
353	core = NULL;
354	kernel = NULL;
355	live_kernel = 1;
356	type = IPLT_ALL;
357	poolname = NULL;
358	role = IPL_LOGALL;
359
360	while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1)
361		switch (c)
362		{
363		case 'd' :
364			opts |= OPT_DEBUG;
365			break;
366		case 'm' :
367			poolname = optarg;
368			break;
369		case 'M' :
370			live_kernel = 0;
371			core = optarg;
372			break;
373		case 'N' :
374			live_kernel = 0;
375			kernel = optarg;
376			break;
377		case 'o' :
378			role = getrole(optarg);
379			if (role == IPL_LOGNONE) {
380				fprintf(stderr, "unknown role '%s'\n", optarg);
381				return -1;
382			}
383			break;
384		case 'R' :
385			opts |= OPT_NORESOLVE;
386			break;
387		case 't' :
388			type = gettype(optarg, NULL);
389			if (type == IPLT_NONE) {
390				fprintf(stderr, "unknown type '%s'\n", optarg);
391				return -1;
392			}
393			break;
394		case 'v' :
395			opts |= OPT_VERBOSE;
396			break;
397		}
398
399	if (opts & OPT_DEBUG)
400		fprintf(stderr, "poollist: opts = %#x\n", opts);
401
402	if (!(opts & OPT_DONOTHING) && (fd == -1)) {
403		fd = open(IPLOOKUP_NAME, O_RDWR);
404		if (fd == -1) {
405			perror("open(IPLOOKUP_NAME)");
406			exit(1);
407		}
408	}
409
410	bzero((char *)&op, sizeof(op));
411	if (poolname != NULL) {
412		strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
413		op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
414	}
415	op.iplo_unit = role;
416
417	if (openkmem(kernel, core) == -1)
418		exit(-1);
419
420	if (type == IPLT_ALL || type == IPLT_POOL) {
421		plstp = &plstat;
422		op.iplo_type = IPLT_POOL;
423		op.iplo_size = sizeof(plstat);
424		op.iplo_struct = &plstat;
425		c = ioctl(fd, SIOCLOOKUPSTAT, &op);
426		if (c == -1) {
427			perror("ioctl(SIOCLOOKUPSTAT)");
428			return -1;
429		}
430
431		if (role != IPL_LOGALL) {
432			ptr = plstp->ipls_list[role];
433			while (ptr != NULL) {
434				ptr = printpool(ptr, kmemcpywrap, poolname,
435						opts);
436			}
437		} else {
438			for (role = 0; role <= IPL_LOGMAX; role++) {
439				ptr = plstp->ipls_list[role];
440				while (ptr != NULL) {
441					ptr = printpool(ptr, kmemcpywrap,
442							poolname, opts);
443				}
444			}
445			role = IPL_LOGALL;
446		}
447	}
448	if (type == IPLT_ALL || type == IPLT_HASH) {
449		htstp = &htstat;
450		op.iplo_type = IPLT_HASH;
451		op.iplo_size = sizeof(htstat);
452		op.iplo_struct = &htstat;
453		c = ioctl(fd, SIOCLOOKUPSTAT, &op);
454		if (c == -1) {
455			perror("ioctl(SIOCLOOKUPSTAT)");
456			return -1;
457		}
458
459		if (role != IPL_LOGALL) {
460			hptr = htstp->iphs_tables;
461			while (hptr != NULL) {
462				hptr = printhash(hptr, kmemcpywrap,
463						 poolname, opts);
464			}
465		} else {
466			for (role = 0; role <= IPL_LOGMAX; role++) {
467				hptr = htstp->iphs_tables;
468				while (hptr != NULL) {
469					hptr = printhash(hptr, kmemcpywrap,
470							 poolname, opts);
471				}
472
473				op.iplo_unit = role;
474				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
475				if (c == -1) {
476					perror("ioctl(SIOCLOOKUPSTAT)");
477					return -1;
478				}
479			}
480		}
481	}
482	return 0;
483}
484
485
486int poolstats(argc, argv)
487int argc;
488char *argv[];
489{
490	int c, type, role, live_kernel;
491	ip_pool_stat_t plstat;
492	char *kernel, *core;
493	iphtstat_t htstat;
494	iplookupop_t op;
495
496	core = NULL;
497	kernel = NULL;
498	live_kernel = 1;
499	type = IPLT_ALL;
500	role = IPL_LOGALL;
501
502	bzero((char *)&op, sizeof(op));
503
504	while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
505		switch (c)
506		{
507		case 'd' :
508			opts |= OPT_DEBUG;
509			break;
510		case 'M' :
511			live_kernel = 0;
512			core = optarg;
513			break;
514		case 'N' :
515			live_kernel = 0;
516			kernel = optarg;
517			break;
518		case 'o' :
519			role = getrole(optarg);
520			if (role == IPL_LOGNONE) {
521				fprintf(stderr, "unknown role '%s'\n", optarg);
522				return -1;
523			}
524			break;
525		case 't' :
526			type = gettype(optarg, NULL);
527			if (type != IPLT_POOL) {
528				fprintf(stderr,
529					"-s not supported for this type yet\n");
530				return -1;
531			}
532			break;
533		case 'v' :
534			opts |= OPT_VERBOSE;
535			break;
536		}
537
538	if (opts & OPT_DEBUG)
539		fprintf(stderr, "poolstats: opts = %#x\n", opts);
540
541	if (!(opts & OPT_DONOTHING) && (fd == -1)) {
542		fd = open(IPLOOKUP_NAME, O_RDWR);
543		if (fd == -1) {
544			perror("open(IPLOOKUP_NAME)");
545			exit(1);
546		}
547	}
548
549	if (type == IPLT_ALL || type == IPLT_POOL) {
550		op.iplo_type = IPLT_POOL;
551		op.iplo_struct = &plstat;
552		op.iplo_size = sizeof(plstat);
553		if (!(opts & OPT_DONOTHING)) {
554			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
555			if (c == -1) {
556				perror("ioctl(SIOCLOOKUPSTAT)");
557				return -1;
558			}
559			printf("Pools:\t%lu\n", plstat.ipls_pools);
560			printf("Nodes:\t%lu\n", plstat.ipls_nodes);
561		}
562	}
563
564	if (type == IPLT_ALL || type == IPLT_HASH) {
565		op.iplo_type = IPLT_HASH;
566		op.iplo_struct = &htstat;
567		op.iplo_size = sizeof(htstat);
568		if (!(opts & OPT_DONOTHING)) {
569			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
570			if (c == -1) {
571				perror("ioctl(SIOCLOOKUPSTAT)");
572				return -1;
573			}
574			printf("Hash Tables:\t%lu\n", htstat.iphs_numtables);
575			printf("Nodes:\t%lu\n", htstat.iphs_numnodes);
576			printf("Out of Memory:\t%lu\n", htstat.iphs_nomem);
577		}
578	}
579	return 0;
580}
581
582
583int poolflush(argc, argv)
584int argc;
585char *argv[];
586{
587	int c, role, type, arg;
588	iplookupflush_t flush;
589
590	arg = IPLT_ALL;
591	type = IPLT_ALL;
592	role = IPL_LOGALL;
593
594	while ((c = getopt(argc, argv, "do:t:v")) != -1)
595		switch (c)
596		{
597		case 'd' :
598			opts |= OPT_DEBUG;
599			break;
600		case 'o' :
601			role = getrole(optarg);
602			if (role == IPL_LOGNONE) {
603				fprintf(stderr, "unknown role '%s'\n", optarg);
604				return -1;
605			}
606			break;
607		case 't' :
608			type = gettype(optarg, NULL);
609			if (type == IPLT_NONE) {
610				fprintf(stderr, "unknown type '%s'\n", optarg);
611				return -1;
612			}
613			break;
614		case 'v' :
615			opts |= OPT_VERBOSE;
616			break;
617		}
618
619	if (opts & OPT_DEBUG)
620		fprintf(stderr, "poolflush: opts = %#x\n", opts);
621
622	if (!(opts & OPT_DONOTHING) && (fd == -1)) {
623		fd = open(IPLOOKUP_NAME, O_RDWR);
624		if (fd == -1) {
625			perror("open(IPLOOKUP_NAME)");
626			exit(1);
627		}
628	}
629
630	bzero((char *)&flush, sizeof(flush));
631	flush.iplf_type = type;
632	flush.iplf_unit = role;
633	flush.iplf_arg = arg;
634
635	if (!(opts & OPT_DONOTHING)) {
636		if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
637			perror("ioctl(SIOCLOOKUPFLUSH)");
638			exit(1);
639		}
640
641	}
642	printf("%u object%s flushed\n", flush.iplf_count,
643	       (flush.iplf_count == 1) ? "" : "s");
644
645	return 0;
646}
647
648
649int getrole(rolename)
650char *rolename;
651{
652	int role;
653
654	if (!strcasecmp(rolename, "ipf")) {
655		role = IPL_LOGIPF;
656#if 0
657	} else if (!strcasecmp(rolename, "nat")) {
658		role = IPL_LOGNAT;
659	} else if (!strcasecmp(rolename, "state")) {
660		role = IPL_LOGSTATE;
661	} else if (!strcasecmp(rolename, "auth")) {
662		role = IPL_LOGAUTH;
663	} else if (!strcasecmp(rolename, "sync")) {
664		role = IPL_LOGSYNC;
665	} else if (!strcasecmp(rolename, "scan")) {
666		role = IPL_LOGSCAN;
667	} else if (!strcasecmp(rolename, "pool")) {
668		role = IPL_LOGLOOKUP;
669	} else if (!strcasecmp(rolename, "count")) {
670		role = IPL_LOGCOUNT;
671#endif
672	} else {
673		role = IPL_LOGNONE;
674	}
675
676	return role;
677}
678
679
680int gettype(typename, minor)
681char *typename;
682u_int *minor;
683{
684	int type;
685
686	if (!strcasecmp(optarg, "tree")) {
687		type = IPLT_POOL;
688	} else if (!strcasecmp(optarg, "hash")) {
689		type = IPLT_HASH;
690		if (minor != NULL)
691			*minor = IPHASH_LOOKUP;
692	} else if (!strcasecmp(optarg, "group-map")) {
693		type = IPLT_HASH;
694		if (minor != NULL)
695			*minor = IPHASH_GROUPMAP;
696	} else {
697		type = IPLT_NONE;
698	}
699	return type;
700}
701