4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
10 #include <sys/param.h>
11 #include <sys/socket.h>
12 # include <sys/cdefs.h>
13 #include <sys/ioctl.h>
16 #include <netinet/in.h>
18 #include <arpa/inet.h>
30 #include "netinet/ipl.h"
31 #include "netinet/ip_lookup.h"
32 #include "netinet/ip_pool.h"
33 #include "netinet/ip_htable.h"
37 extern int ippool_yyparse(void);
38 extern int ippool_yydebug;
39 extern FILE *ippool_yyin;
44 int main(int, char **);
45 int poolcommand(int, int, char *[]);
46 int poolnodecommand(int, int, char *[]);
47 int loadpoolfile(int, char *[], char *);
48 int poollist(int, char *[]);
49 void poollist_dead(int, char *, int, char *, char *);
50 void poollist_live(int, char *, int, int);
51 int poolflush(int, char *[]);
52 int poolstats(int, char *[]);
53 int gettype(char *, u_int *);
55 int setnodeaddr(int, int, void *ptr, char *arg);
56 void showpools_live(int, int, ipf_pool_stat_t *, char *);
57 void showhashs_live(int, int, iphtstat_t *, char *);
58 void showdstls_live(int, int, ipf_dstl_stat_t *, char *);
63 wordtab_t *pool_fields = NULL;
70 fprintf(stderr, "Usage:\t%s\n", prog);
71 fprintf(stderr, "\t-a [-dnv] -m <name> [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
72 fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
73 fprintf(stderr, "\t-f <file> [-dnuvR]\n");
74 fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
75 fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-o <role>] [-M <core>] [-N <namelist>]\n");
76 fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
77 fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
78 fprintf(stderr, "\t-s [-dtv]\n");
84 main(int argc, char *argv[])
91 assigndefined(getenv("IPPOOL_PREDEFINED"));
93 switch (getopt(argc, argv, "aAf:FlrRs"))
96 err = poolnodecommand(0, argc, argv);
99 err = poolcommand(0, argc, argv);
102 err = loadpoolfile(argc, argv, optarg);
105 err = poolflush(argc, argv);
108 err = poollist(argc, argv);
111 err = poolnodecommand(1, argc, argv);
114 err = poolcommand(1, argc, argv);
117 err = poolstats(argc, argv);
130 poolnodecommand(int remove, int argc, char *argv[])
132 int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
133 char *poolname = NULL;
134 ip_pool_node_t pnode;
140 bzero((char *)&pnode, sizeof(pnode));
141 bzero((char *)&hnode, sizeof(hnode));
143 while ((c = getopt(argc, argv, "di:m:no:t:T:v")) != -1)
151 if (setnodeaddr(type, role, ptr, optarg) == 0)
158 opts |= OPT_DONOTHING|OPT_DONTOPEN;
163 "cannot set role after ip address\n");
166 role = getrole(optarg);
167 if (role == IPL_LOGNONE)
173 "cannot set type after ip address\n");
176 type = gettype(optarg, NULL);
179 fprintf(stderr, "unknown type '%s'\n", optarg);
193 fprintf(stderr, "cannot set negative ttl\n");
205 break; /* keep compiler happy */
208 if (argc - 1 - optind > 0)
211 if (argv[optind] != NULL && ipset == 0) {
212 if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
216 if (opts & OPT_DEBUG)
217 fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
220 fprintf(stderr, "no IP address given with -i\n");
224 if (poolname == NULL) {
225 fprintf(stderr, "poolname not given with add/remove node\n");
232 err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
234 err = remove_poolnode(role, poolname, &pnode, ioctl);
238 err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
240 err = remove_hashnode(role, poolname, &hnode, ioctl);
250 poolcommand(int remove, int argc, char *argv[])
252 int type, role, c, err;
253 char *poolname, *typearg = NULL;
262 bzero((char *)&iph, sizeof(iph));
263 bzero((char *)&pool, sizeof(pool));
265 while ((c = getopt(argc, argv, "dm:no:S:vt:")) != -1)
276 opts |= OPT_DONOTHING|OPT_DONTOPEN;
279 role = getrole(optarg);
280 if (role == IPL_LOGNONE) {
281 fprintf(stderr, "unknown role '%s'\n", optarg);
287 iph.iph_seed = atoi(optarg);
292 type = gettype(optarg, &iph.iph_type);
300 break; /* keep compiler happy */
303 if (argc - 1 - optind > 0)
306 if (opts & OPT_DEBUG)
307 fprintf(stderr, "poolcommand: opts = %#x\n", opts);
309 if (poolname == NULL) {
310 fprintf(stderr, "poolname not given with add/remove pool\n");
314 if (type == IPLT_NONE && remove == 0) {
315 if (typearg == NULL) {
316 fprintf(stderr, "type must be specified\n");
319 fprintf(stderr, "unknown type '%s'\n", typearg);
324 if (type == IPLT_HASH || (type == IPLT_NONE && remove == 1)) {
325 strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
326 iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
329 if (type == IPLT_POOL || (type == IPLT_NONE && remove == 1)) {
330 strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
331 pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
332 pool.ipo_unit = role;
339 err = load_hash(&iph, NULL, ioctl);
342 err = load_pool(&pool, ioctl);
349 err = remove_hash(&iph, ioctl);
352 err = remove_pool(&pool, ioctl);
358 err_h = remove_hash(&iph, ioctl);
359 err_p = remove_pool(&pool, ioctl);
360 if (err_h == 0 || err_p == 0)
371 loadpoolfile(int argc, char *argv[], char *infile)
375 while ((c = getopt(argc, argv, "dnuvf:")) != -1)
383 if (loadpoolfile(argc, argv, optarg) != 0)
387 opts |= OPT_DONOTHING|OPT_DONTOPEN;
397 break; /* keep compiler happy */
400 if (argc - 1 - optind > 0)
403 if (opts & OPT_DEBUG)
404 fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
406 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
407 fd = open(IPLOOKUP_NAME, O_RDWR);
409 perror("open(IPLOOKUP_NAME)");
414 if (ippool_parsefile(fd, infile, ioctl) != 0)
421 poolstats(int argc, char *argv[])
424 ipf_pool_stat_t plstat;
425 ipf_dstl_stat_t dlstat;
432 bzero((char *)&op, sizeof(op));
434 while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
441 role = getrole(optarg);
442 if (role == IPL_LOGNONE) {
443 fprintf(stderr, "unknown role '%s'\n", optarg);
448 type = gettype(optarg, NULL);
449 if (type != IPLT_POOL) {
451 "-s not supported for this type yet\n");
460 break; /* keep compiler happy */
463 if (argc - 1 - optind > 0)
466 if (opts & OPT_DEBUG)
467 fprintf(stderr, "poolstats: opts = %#x\n", opts);
469 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
470 fd = open(IPLOOKUP_NAME, O_RDWR);
472 perror("open(IPLOOKUP_NAME)");
477 if (type == IPLT_ALL || type == IPLT_POOL) {
478 op.iplo_type = IPLT_POOL;
479 op.iplo_struct = &plstat;
480 op.iplo_size = sizeof(plstat);
481 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
482 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
484 ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
487 printf("%lu\taddress pools\n", plstat.ipls_pools);
488 printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
492 if (type == IPLT_ALL || type == IPLT_HASH) {
493 op.iplo_type = IPLT_HASH;
494 op.iplo_struct = &htstat;
495 op.iplo_size = sizeof(htstat);
496 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
497 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
499 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
502 printf("%lu\thash tables\n", htstat.iphs_numtables);
503 printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
504 printf("%lu\thash table no memory \n",
509 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
510 op.iplo_type = IPLT_DSTLIST;
511 op.iplo_struct = &dlstat;
512 op.iplo_size = sizeof(dlstat);
513 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
514 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
516 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
519 printf("%u\tdestination lists\n",
520 dlstat.ipls_numlists);
521 printf("%u\tdestination list nodes\n",
522 dlstat.ipls_numnodes);
523 printf("%lu\tdestination list no memory\n",
525 printf("%u\tdestination list zombies\n",
526 dlstat.ipls_numdereflists);
527 printf("%u\tdesetination list node zombies\n",
528 dlstat.ipls_numderefnodes);
536 poolflush(int argc, char *argv[])
538 int c, role, type, arg;
539 iplookupflush_t flush;
545 while ((c = getopt(argc, argv, "do:t:v")) != -1)
552 role = getrole(optarg);
553 if (role == IPL_LOGNONE) {
554 fprintf(stderr, "unknown role '%s'\n", optarg);
559 type = gettype(optarg, NULL);
560 if (type == IPLT_NONE) {
561 fprintf(stderr, "unknown type '%s'\n", optarg);
570 break; /* keep compiler happy */
573 if (argc - optind > 0)
576 if (opts & OPT_DEBUG)
577 fprintf(stderr, "poolflush: opts = %#x\n", opts);
579 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
580 fd = open(IPLOOKUP_NAME, O_RDWR);
582 perror("open(IPLOOKUP_NAME)");
587 bzero((char *)&flush, sizeof(flush));
588 flush.iplf_type = type;
589 flush.iplf_unit = role;
590 flush.iplf_arg = arg;
592 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
593 if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
594 ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
599 printf("%u object%s flushed\n", flush.iplf_count,
600 (flush.iplf_count == 1) ? "" : "s");
607 getrole(char *rolename)
611 if (!strcasecmp(rolename, "ipf")) {
614 } else if (!strcasecmp(rolename, "nat")) {
616 } else if (!strcasecmp(rolename, "state")) {
618 } else if (!strcasecmp(rolename, "auth")) {
620 } else if (!strcasecmp(rolename, "sync")) {
622 } else if (!strcasecmp(rolename, "scan")) {
624 } else if (!strcasecmp(rolename, "pool")) {
625 role = IPL_LOGLOOKUP;
626 } else if (!strcasecmp(rolename, "count")) {
638 gettype(char *typename, u_int *minor)
642 if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
644 } else if (!strcasecmp(typename, "hash")) {
647 *minor = IPHASH_LOOKUP;
648 } else if (!strcasecmp(typename, "group-map")) {
651 *minor = IPHASH_GROUPMAP;
660 poollist(int argc, char *argv[])
662 char *kernel, *core, *poolname;
663 int c, role, type, live_kernel;
673 while ((c = getopt(argc, argv, "dm:M:N:o:t:v")) != -1)
691 role = getrole(optarg);
692 if (role == IPL_LOGNONE) {
693 fprintf(stderr, "unknown role '%s'\n", optarg);
699 /* XXX This option does not work. This function as */
700 /* XXX used by state and nat can be used to format */
701 /* XXX output especially useful for scripting. It */
702 /* XXX is left here with the intention of making */
703 /* XXX it work for the same purpose at some point. */
704 pool_fields = parsefields(poolfields, optarg);
708 type = gettype(optarg, NULL);
709 if (type == IPLT_NONE) {
710 fprintf(stderr, "unknown type '%s'\n", optarg);
719 break; /* keep compiler happy */
722 if (argc - optind > 0)
725 if (opts & OPT_DEBUG)
726 fprintf(stderr, "poollist: opts = %#x\n", opts);
728 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
729 fd = open(IPLOOKUP_NAME, O_RDWR);
731 perror("open(IPLOOKUP_NAME)");
736 bzero((char *)&op, sizeof(op));
737 if (poolname != NULL) {
738 strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
739 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
744 poollist_live(role, poolname, type, fd);
746 poollist_dead(role, poolname, type, kernel, core);
752 poollist_dead(int role, char *poolname, int type, char *kernel, char *core)
757 if (openkmem(kernel, core) == -1)
760 if (type == IPLT_ALL || type == IPLT_POOL) {
761 ip_pool_t *pools[IPL_LOGSIZE];
762 struct nlist names[2] = { { "ip_pool_list" } , { "" } };
764 if (nlist(kernel, names) != 1)
767 bzero(&pools, sizeof(pools));
768 if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
771 if (role != IPL_LOGALL) {
773 while (ptr != NULL) {
774 ptr = printpool(ptr, kmemcpywrap, poolname,
778 for (role = 0; role <= IPL_LOGMAX; role++) {
780 while (ptr != NULL) {
781 ptr = printpool(ptr, kmemcpywrap,
789 if (type == IPLT_ALL || type == IPLT_HASH) {
790 iphtable_t *tables[IPL_LOGSIZE];
791 struct nlist names[2] = { { "ipf_htables" } , { "" } };
793 if (nlist(kernel, names) != 1)
796 bzero(&tables, sizeof(tables));
797 if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
800 if (role != IPL_LOGALL) {
802 while (hptr != NULL) {
803 hptr = printhash(hptr, kmemcpywrap,
804 poolname, opts, pool_fields);
807 for (role = 0; role <= IPL_LOGMAX; role++) {
809 while (hptr != NULL) {
810 hptr = printhash(hptr, kmemcpywrap,
821 poollist_live(int role, char *poolname, int type, int fd)
823 ipf_pool_stat_t plstat;
827 if (type == IPLT_ALL || type == IPLT_POOL) {
828 op.iplo_type = IPLT_POOL;
829 op.iplo_size = sizeof(plstat);
830 op.iplo_struct = &plstat;
831 op.iplo_name[0] = '\0';
834 if (role != IPL_LOGALL) {
837 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
839 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
843 showpools_live(fd, role, &plstat, poolname);
845 for (role = -1; role <= IPL_LOGMAX; role++) {
848 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
850 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
854 showpools_live(fd, role, &plstat, poolname);
861 if (type == IPLT_ALL || type == IPLT_HASH) {
864 op.iplo_type = IPLT_HASH;
865 op.iplo_size = sizeof(htstat);
866 op.iplo_struct = &htstat;
867 op.iplo_name[0] = '\0';
870 if (role != IPL_LOGALL) {
873 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
875 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
878 showhashs_live(fd, role, &htstat, poolname);
880 for (role = 0; role <= IPL_LOGMAX; role++) {
883 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
885 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
889 showhashs_live(fd, role, &htstat, poolname);
895 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
896 ipf_dstl_stat_t dlstat;
898 op.iplo_type = IPLT_DSTLIST;
899 op.iplo_size = sizeof(dlstat);
900 op.iplo_struct = &dlstat;
901 op.iplo_name[0] = '\0';
904 if (role != IPL_LOGALL) {
907 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
909 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
912 showdstls_live(fd, role, &dlstat, poolname);
914 for (role = 0; role <= IPL_LOGMAX; role++) {
917 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
919 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
923 showdstls_live(fd, role, &dlstat, poolname);
932 showpools_live(int fd, int role, ipf_pool_stat_t *plstp, char *poolname)
934 ipflookupiter_t iter;
938 obj.ipfo_rev = IPFILTER_VERSION;
939 obj.ipfo_type = IPFOBJ_LOOKUPITER;
940 obj.ipfo_size = sizeof(iter);
941 obj.ipfo_ptr = &iter;
943 iter.ili_type = IPLT_POOL;
944 iter.ili_otype = IPFLOOKUPITER_LIST;
945 iter.ili_ival = IPFGENITER_LOOKUP;
947 iter.ili_data = &pool;
948 iter.ili_unit = role;
949 *iter.ili_name = '\0';
951 bzero((char *)&pool, sizeof(pool));
953 while (plstp->ipls_list[role + 1] != NULL) {
954 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
955 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
958 if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
959 ((opts & OPT_DEBUG) != 0))
960 printpool_live(&pool, fd, poolname, opts, pool_fields);
962 plstp->ipls_list[role + 1] = pool.ipo_next;
968 showhashs_live(int fd, int role, iphtstat_t *htstp, char *poolname)
970 ipflookupiter_t iter;
974 obj.ipfo_rev = IPFILTER_VERSION;
975 obj.ipfo_type = IPFOBJ_LOOKUPITER;
976 obj.ipfo_size = sizeof(iter);
977 obj.ipfo_ptr = &iter;
979 iter.ili_type = IPLT_HASH;
980 iter.ili_otype = IPFLOOKUPITER_LIST;
981 iter.ili_ival = IPFGENITER_LOOKUP;
983 iter.ili_data = &table;
984 iter.ili_unit = role;
985 *iter.ili_name = '\0';
987 while (htstp->iphs_tables != NULL) {
988 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
989 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
993 printhash_live(&table, fd, poolname, opts, pool_fields);
995 htstp->iphs_tables = table.iph_next;
1001 showdstls_live(int fd, int role, ipf_dstl_stat_t *dlstp, char *poolname)
1003 ipflookupiter_t iter;
1007 obj.ipfo_rev = IPFILTER_VERSION;
1008 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1009 obj.ipfo_size = sizeof(iter);
1010 obj.ipfo_ptr = &iter;
1012 iter.ili_type = IPLT_DSTLIST;
1013 iter.ili_otype = IPFLOOKUPITER_LIST;
1014 iter.ili_ival = IPFGENITER_LOOKUP;
1015 iter.ili_nitems = 1;
1016 iter.ili_data = &table;
1017 iter.ili_unit = role;
1018 *iter.ili_name = '\0';
1020 while (dlstp->ipls_list[role] != NULL) {
1021 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1022 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1026 printdstl_live(&table, fd, poolname, opts, pool_fields);
1028 dlstp->ipls_list[role] = table.ipld_next;
1034 setnodeaddr(int type, int role, void *ptr, char *arg)
1036 struct in_addr mask;
1040 if (strchr(arg, ':') == NULL) {
1042 s = strchr(arg, '/');
1044 mask.s_addr = 0xffffffff;
1045 else if (strchr(s, '.') == NULL) {
1046 if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1049 mask.s_addr = inet_addr(s + 1);
1056 /* XXX for now we use mask for IPv6 prefix length */
1057 /* XXX mask should be a union with prefix */
1058 /* XXX Currently address handling is sloppy. */
1060 if ((s = strchr(arg, '/')) == NULL)
1063 mask.s_addr = atoi(s + 1);
1066 if (type == IPLT_POOL) {
1067 ip_pool_node_t *node = ptr;
1069 node->ipn_addr.adf_family = family;
1072 if (node->ipn_addr.adf_family == AF_INET) {
1074 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1076 sizeof(struct in_addr);
1077 node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1080 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1082 sizeof(struct in6_addr);
1083 inet_pton(AF_INET6, arg,
1084 &node->ipn_addr.adf_addr.in6.s6_addr);
1087 node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1088 node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1089 } else if (type == IPLT_HASH) {
1090 iphtent_t *node = ptr;
1092 node->ipe_family = family;
1093 node->ipe_unit = role;
1096 if (node->ipe_family == AF_INET) {
1098 node->ipe_addr.in4.s_addr = inet_addr(arg);
1099 node->ipe_mask.in4.s_addr = mask.s_addr;
1102 inet_pton(AF_INET6, arg,
1103 &node->ipe_addr.in6.__u6_addr.__u6_addr32);
1104 node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1106 node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1107 node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1108 node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;