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 __P((void));
38 extern int ippool_yydebug;
39 extern FILE *ippool_yyin;
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 *));
63 wordtab_t *pool_fields = NULL;
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");
94 assigndefined(getenv("IPPOOL_PREDEFINED"));
96 switch (getopt(argc, argv, "aAf:FlrRs"))
99 err = poolnodecommand(0, argc, argv);
102 err = poolcommand(0, argc, argv);
105 err = loadpoolfile(argc, argv, optarg);
108 err = poolflush(argc, argv);
111 err = poollist(argc, argv);
114 err = poolnodecommand(1, argc, argv);
117 err = poolcommand(1, argc, argv);
120 err = poolstats(argc, argv);
133 poolnodecommand(remove, argc, argv)
137 int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
138 char *poolname = NULL;
139 ip_pool_node_t pnode;
145 bzero((char *)&pnode, sizeof(pnode));
146 bzero((char *)&hnode, sizeof(hnode));
148 while ((c = getopt(argc, argv, "di:m:no:t:T:v")) != -1)
156 if (setnodeaddr(type, role, ptr, optarg) == 0)
163 opts |= OPT_DONOTHING|OPT_DONTOPEN;
168 "cannot set role after ip address\n");
171 role = getrole(optarg);
172 if (role == IPL_LOGNONE)
178 "cannot set type after ip address\n");
181 type = gettype(optarg, NULL);
184 fprintf(stderr, "unknown type '%s'\n", optarg);
198 fprintf(stderr, "cannot set negative ttl\n");
210 break; /* keep compiler happy */
213 if (argc - 1 - optind > 0)
216 if (argv[optind] != NULL && ipset == 0) {
217 if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
221 if (opts & OPT_DEBUG)
222 fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
225 fprintf(stderr, "no IP address given with -i\n");
229 if (poolname == NULL) {
230 fprintf(stderr, "poolname not given with add/remove node\n");
237 err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
239 err = remove_poolnode(role, poolname, &pnode, ioctl);
243 err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
245 err = remove_hashnode(role, poolname, &hnode, ioctl);
255 poolcommand(remove, argc, argv)
259 int type, role, c, err;
260 char *poolname, *typearg = NULL;
269 bzero((char *)&iph, sizeof(iph));
270 bzero((char *)&pool, sizeof(pool));
272 while ((c = getopt(argc, argv, "dm:no:S:vt:")) != -1)
283 opts |= OPT_DONOTHING|OPT_DONTOPEN;
286 role = getrole(optarg);
287 if (role == IPL_LOGNONE) {
288 fprintf(stderr, "unknown role '%s'\n", optarg);
294 iph.iph_seed = atoi(optarg);
299 type = gettype(optarg, &iph.iph_type);
307 break; /* keep compiler happy */
310 if (argc - 1 - optind > 0)
313 if (opts & OPT_DEBUG)
314 fprintf(stderr, "poolcommand: opts = %#x\n", opts);
316 if (poolname == NULL) {
317 fprintf(stderr, "poolname not given with add/remove pool\n");
321 if (type == IPLT_NONE && remove == 0) {
322 if (typearg == NULL) {
323 fprintf(stderr, "type must be specified\n");
326 fprintf(stderr, "unknown type '%s'\n", typearg);
331 if (type == IPLT_HASH || (type == IPLT_NONE && remove == 1)) {
332 strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
333 iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
336 if (type == IPLT_POOL || (type == IPLT_NONE && remove == 1)) {
337 strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
338 pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
339 pool.ipo_unit = role;
346 err = load_hash(&iph, NULL, ioctl);
349 err = load_pool(&pool, ioctl);
356 err = remove_hash(&iph, ioctl);
359 err = remove_pool(&pool, ioctl);
365 err_h = remove_hash(&iph, ioctl);
366 err_p = remove_pool(&pool, ioctl);
367 if (err_h == 0 || err_p == 0)
378 loadpoolfile(argc, argv, infile)
380 char *argv[], *infile;
384 while ((c = getopt(argc, argv, "dnuv")) != -1)
392 opts |= OPT_DONOTHING|OPT_DONTOPEN;
402 break; /* keep compiler happy */
405 if (argc - 1 - optind > 0)
408 if (opts & OPT_DEBUG)
409 fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
411 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
412 fd = open(IPLOOKUP_NAME, O_RDWR);
414 perror("open(IPLOOKUP_NAME)");
419 if (ippool_parsefile(fd, infile, ioctl) != 0)
426 poolstats(argc, argv)
430 int c, type, role, live_kernel;
431 ipf_pool_stat_t plstat;
432 ipf_dstl_stat_t dlstat;
443 bzero((char *)&op, sizeof(op));
445 while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
460 role = getrole(optarg);
461 if (role == IPL_LOGNONE) {
462 fprintf(stderr, "unknown role '%s'\n", optarg);
467 type = gettype(optarg, NULL);
468 if (type != IPLT_POOL) {
470 "-s not supported for this type yet\n");
479 break; /* keep compiler happy */
482 if (argc - 1 - optind > 0)
485 if (opts & OPT_DEBUG)
486 fprintf(stderr, "poolstats: opts = %#x\n", opts);
488 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
489 fd = open(IPLOOKUP_NAME, O_RDWR);
491 perror("open(IPLOOKUP_NAME)");
496 if (type == IPLT_ALL || type == IPLT_POOL) {
497 op.iplo_type = IPLT_POOL;
498 op.iplo_struct = &plstat;
499 op.iplo_size = sizeof(plstat);
500 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
501 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
503 ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
506 printf("%lu\taddress pools\n", plstat.ipls_pools);
507 printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
511 if (type == IPLT_ALL || type == IPLT_HASH) {
512 op.iplo_type = IPLT_HASH;
513 op.iplo_struct = &htstat;
514 op.iplo_size = sizeof(htstat);
515 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
516 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
518 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
521 printf("%lu\thash tables\n", htstat.iphs_numtables);
522 printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
523 printf("%lu\thash table no memory \n",
528 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
529 op.iplo_type = IPLT_DSTLIST;
530 op.iplo_struct = &dlstat;
531 op.iplo_size = sizeof(dlstat);
532 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
533 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
535 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
538 printf("%u\tdestination lists\n",
539 dlstat.ipls_numlists);
540 printf("%u\tdestination list nodes\n",
541 dlstat.ipls_numnodes);
542 printf("%lu\tdestination list no memory\n",
544 printf("%u\tdestination list zombies\n",
545 dlstat.ipls_numdereflists);
546 printf("%u\tdesetination list node zombies\n",
547 dlstat.ipls_numderefnodes);
555 poolflush(argc, argv)
559 int c, role, type, arg;
560 iplookupflush_t flush;
566 while ((c = getopt(argc, argv, "do:t:v")) != -1)
573 role = getrole(optarg);
574 if (role == IPL_LOGNONE) {
575 fprintf(stderr, "unknown role '%s'\n", optarg);
580 type = gettype(optarg, NULL);
581 if (type == IPLT_NONE) {
582 fprintf(stderr, "unknown type '%s'\n", optarg);
591 break; /* keep compiler happy */
594 if (argc - optind > 0)
597 if (opts & OPT_DEBUG)
598 fprintf(stderr, "poolflush: opts = %#x\n", opts);
600 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
601 fd = open(IPLOOKUP_NAME, O_RDWR);
603 perror("open(IPLOOKUP_NAME)");
608 bzero((char *)&flush, sizeof(flush));
609 flush.iplf_type = type;
610 flush.iplf_unit = role;
611 flush.iplf_arg = arg;
613 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
614 if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
615 ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
620 printf("%u object%s flushed\n", flush.iplf_count,
621 (flush.iplf_count == 1) ? "" : "s");
633 if (!strcasecmp(rolename, "ipf")) {
636 } else if (!strcasecmp(rolename, "nat")) {
638 } else if (!strcasecmp(rolename, "state")) {
640 } else if (!strcasecmp(rolename, "auth")) {
642 } else if (!strcasecmp(rolename, "sync")) {
644 } else if (!strcasecmp(rolename, "scan")) {
646 } else if (!strcasecmp(rolename, "pool")) {
647 role = IPL_LOGLOOKUP;
648 } else if (!strcasecmp(rolename, "count")) {
660 gettype(typename, minor)
666 if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
668 } else if (!strcasecmp(typename, "hash")) {
671 *minor = IPHASH_LOOKUP;
672 } else if (!strcasecmp(typename, "group-map")) {
675 *minor = IPHASH_GROUPMAP;
688 char *kernel, *core, *poolname;
689 int c, role, type, live_kernel;
699 while ((c = getopt(argc, argv, "dm:M:N:o:t:v")) != -1)
717 role = getrole(optarg);
718 if (role == IPL_LOGNONE) {
719 fprintf(stderr, "unknown role '%s'\n", optarg);
725 /* XXX This option does not work. This function as */
726 /* XXX used by state and nat can be used to format */
727 /* XXX output especially useful for scripting. It */
728 /* XXX is left here with the intention of making */
729 /* XXX it work for the same purpose at some point. */
730 pool_fields = parsefields(poolfields, optarg);
734 type = gettype(optarg, NULL);
735 if (type == IPLT_NONE) {
736 fprintf(stderr, "unknown type '%s'\n", optarg);
745 break; /* keep compiler happy */
748 if (argc - optind > 0)
751 if (opts & OPT_DEBUG)
752 fprintf(stderr, "poollist: opts = %#x\n", opts);
754 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
755 fd = open(IPLOOKUP_NAME, O_RDWR);
757 perror("open(IPLOOKUP_NAME)");
762 bzero((char *)&op, sizeof(op));
763 if (poolname != NULL) {
764 strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
765 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
770 poollist_live(role, poolname, type, fd);
772 poollist_dead(role, poolname, type, kernel, core);
778 poollist_dead(role, poolname, type, kernel, core)
780 char *poolname, *kernel, *core;
785 if (openkmem(kernel, core) == -1)
788 if (type == IPLT_ALL || type == IPLT_POOL) {
789 ip_pool_t *pools[IPL_LOGSIZE];
790 struct nlist names[2] = { { "ip_pool_list" } , { "" } };
792 if (nlist(kernel, names) != 1)
795 bzero(&pools, sizeof(pools));
796 if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
799 if (role != IPL_LOGALL) {
801 while (ptr != NULL) {
802 ptr = printpool(ptr, kmemcpywrap, poolname,
806 for (role = 0; role <= IPL_LOGMAX; role++) {
808 while (ptr != NULL) {
809 ptr = printpool(ptr, kmemcpywrap,
817 if (type == IPLT_ALL || type == IPLT_HASH) {
818 iphtable_t *tables[IPL_LOGSIZE];
819 struct nlist names[2] = { { "ipf_htables" } , { "" } };
821 if (nlist(kernel, names) != 1)
824 bzero(&tables, sizeof(tables));
825 if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
828 if (role != IPL_LOGALL) {
830 while (hptr != NULL) {
831 hptr = printhash(hptr, kmemcpywrap,
832 poolname, opts, pool_fields);
835 for (role = 0; role <= IPL_LOGMAX; role++) {
837 while (hptr != NULL) {
838 hptr = printhash(hptr, kmemcpywrap,
849 poollist_live(role, poolname, type, fd)
853 ipf_pool_stat_t plstat;
857 if (type == IPLT_ALL || type == IPLT_POOL) {
858 op.iplo_type = IPLT_POOL;
859 op.iplo_size = sizeof(plstat);
860 op.iplo_struct = &plstat;
861 op.iplo_name[0] = '\0';
864 if (role != IPL_LOGALL) {
867 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
869 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
873 showpools_live(fd, role, &plstat, poolname);
875 for (role = -1; role <= IPL_LOGMAX; role++) {
878 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
880 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
884 showpools_live(fd, role, &plstat, poolname);
891 if (type == IPLT_ALL || type == IPLT_HASH) {
894 op.iplo_type = IPLT_HASH;
895 op.iplo_size = sizeof(htstat);
896 op.iplo_struct = &htstat;
897 op.iplo_name[0] = '\0';
900 if (role != IPL_LOGALL) {
903 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
905 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
908 showhashs_live(fd, role, &htstat, poolname);
910 for (role = 0; role <= IPL_LOGMAX; role++) {
913 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
915 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
919 showhashs_live(fd, role, &htstat, poolname);
925 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
926 ipf_dstl_stat_t dlstat;
928 op.iplo_type = IPLT_DSTLIST;
929 op.iplo_size = sizeof(dlstat);
930 op.iplo_struct = &dlstat;
931 op.iplo_name[0] = '\0';
934 if (role != IPL_LOGALL) {
937 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
939 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
942 showdstls_live(fd, role, &dlstat, poolname);
944 for (role = 0; role <= IPL_LOGMAX; role++) {
947 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
949 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
953 showdstls_live(fd, role, &dlstat, poolname);
962 showpools_live(fd, role, plstp, poolname)
964 ipf_pool_stat_t *plstp;
967 ipflookupiter_t iter;
971 obj.ipfo_rev = IPFILTER_VERSION;
972 obj.ipfo_type = IPFOBJ_LOOKUPITER;
973 obj.ipfo_size = sizeof(iter);
974 obj.ipfo_ptr = &iter;
976 iter.ili_type = IPLT_POOL;
977 iter.ili_otype = IPFLOOKUPITER_LIST;
978 iter.ili_ival = IPFGENITER_LOOKUP;
980 iter.ili_data = &pool;
981 iter.ili_unit = role;
982 *iter.ili_name = '\0';
984 bzero((char *)&pool, sizeof(pool));
986 while (plstp->ipls_list[role + 1] != NULL) {
987 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
988 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
991 if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
992 ((opts & OPT_DEBUG) != 0))
993 printpool_live(&pool, fd, poolname, opts, pool_fields);
995 plstp->ipls_list[role + 1] = pool.ipo_next;
1001 showhashs_live(fd, role, htstp, poolname)
1006 ipflookupiter_t iter;
1010 obj.ipfo_rev = IPFILTER_VERSION;
1011 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1012 obj.ipfo_size = sizeof(iter);
1013 obj.ipfo_ptr = &iter;
1015 iter.ili_type = IPLT_HASH;
1016 iter.ili_otype = IPFLOOKUPITER_LIST;
1017 iter.ili_ival = IPFGENITER_LOOKUP;
1018 iter.ili_nitems = 1;
1019 iter.ili_data = &table;
1020 iter.ili_unit = role;
1021 *iter.ili_name = '\0';
1023 while (htstp->iphs_tables != NULL) {
1024 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1025 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1029 printhash_live(&table, fd, poolname, opts, pool_fields);
1031 htstp->iphs_tables = table.iph_next;
1037 showdstls_live(fd, role, dlstp, poolname)
1039 ipf_dstl_stat_t *dlstp;
1042 ipflookupiter_t iter;
1046 obj.ipfo_rev = IPFILTER_VERSION;
1047 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1048 obj.ipfo_size = sizeof(iter);
1049 obj.ipfo_ptr = &iter;
1051 iter.ili_type = IPLT_DSTLIST;
1052 iter.ili_otype = IPFLOOKUPITER_LIST;
1053 iter.ili_ival = IPFGENITER_LOOKUP;
1054 iter.ili_nitems = 1;
1055 iter.ili_data = &table;
1056 iter.ili_unit = role;
1057 *iter.ili_name = '\0';
1059 while (dlstp->ipls_list[role] != NULL) {
1060 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1061 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1065 printdstl_live(&table, fd, poolname, opts, pool_fields);
1067 dlstp->ipls_list[role] = table.ipld_next;
1073 setnodeaddr(int type, int role, void *ptr, char *arg)
1075 struct in_addr mask;
1079 if (strchr(arg, ':') == NULL) {
1081 s = strchr(arg, '/');
1083 mask.s_addr = 0xffffffff;
1084 else if (strchr(s, '.') == NULL) {
1085 if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1088 mask.s_addr = inet_addr(s + 1);
1095 /* XXX for now we use mask for IPv6 prefix length */
1096 /* XXX mask should be a union with prefix */
1097 /* XXX Currently address handling is sloppy. */
1099 if ((s = strchr(arg, '/')) == NULL)
1102 mask.s_addr = atoi(s + 1);
1105 if (type == IPLT_POOL) {
1106 ip_pool_node_t *node = ptr;
1108 node->ipn_addr.adf_family = family;
1111 if (node->ipn_addr.adf_family == AF_INET) {
1113 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1115 sizeof(struct in_addr);
1116 node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1119 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1121 sizeof(struct in6_addr);
1122 inet_pton(AF_INET6, arg,
1123 &node->ipn_addr.adf_addr.in6.s6_addr);
1126 node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1127 node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1128 } else if (type == IPLT_HASH) {
1129 iphtent_t *node = ptr;
1131 node->ipe_family = family;
1132 node->ipe_unit = role;
1135 if (node->ipe_family == AF_INET) {
1137 node->ipe_addr.in4.s_addr = inet_addr(arg);
1138 node->ipe_mask.in4.s_addr = mask.s_addr;
1141 inet_pton(AF_INET6, arg,
1142 &node->ipe_addr.in6.__u6_addr.__u6_addr32);
1143 node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1145 node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1146 node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1147 node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;