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, "dnuvf:")) != -1)
392 if (loadpoolfile(argc, argv, optarg) != 0)
396 opts |= OPT_DONOTHING|OPT_DONTOPEN;
406 break; /* keep compiler happy */
409 if (argc - 1 - optind > 0)
412 if (opts & OPT_DEBUG)
413 fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
415 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
416 fd = open(IPLOOKUP_NAME, O_RDWR);
418 perror("open(IPLOOKUP_NAME)");
423 if (ippool_parsefile(fd, infile, ioctl) != 0)
430 poolstats(argc, argv)
434 int c, type, role, live_kernel;
435 ipf_pool_stat_t plstat;
436 ipf_dstl_stat_t dlstat;
447 bzero((char *)&op, sizeof(op));
449 while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
464 role = getrole(optarg);
465 if (role == IPL_LOGNONE) {
466 fprintf(stderr, "unknown role '%s'\n", optarg);
471 type = gettype(optarg, NULL);
472 if (type != IPLT_POOL) {
474 "-s not supported for this type yet\n");
483 break; /* keep compiler happy */
486 if (argc - 1 - optind > 0)
489 if (opts & OPT_DEBUG)
490 fprintf(stderr, "poolstats: opts = %#x\n", opts);
492 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
493 fd = open(IPLOOKUP_NAME, O_RDWR);
495 perror("open(IPLOOKUP_NAME)");
500 if (type == IPLT_ALL || type == IPLT_POOL) {
501 op.iplo_type = IPLT_POOL;
502 op.iplo_struct = &plstat;
503 op.iplo_size = sizeof(plstat);
504 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
505 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
507 ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
510 printf("%lu\taddress pools\n", plstat.ipls_pools);
511 printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
515 if (type == IPLT_ALL || type == IPLT_HASH) {
516 op.iplo_type = IPLT_HASH;
517 op.iplo_struct = &htstat;
518 op.iplo_size = sizeof(htstat);
519 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
520 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
522 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
525 printf("%lu\thash tables\n", htstat.iphs_numtables);
526 printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
527 printf("%lu\thash table no memory \n",
532 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
533 op.iplo_type = IPLT_DSTLIST;
534 op.iplo_struct = &dlstat;
535 op.iplo_size = sizeof(dlstat);
536 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
537 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
539 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
542 printf("%u\tdestination lists\n",
543 dlstat.ipls_numlists);
544 printf("%u\tdestination list nodes\n",
545 dlstat.ipls_numnodes);
546 printf("%lu\tdestination list no memory\n",
548 printf("%u\tdestination list zombies\n",
549 dlstat.ipls_numdereflists);
550 printf("%u\tdesetination list node zombies\n",
551 dlstat.ipls_numderefnodes);
559 poolflush(argc, argv)
563 int c, role, type, arg;
564 iplookupflush_t flush;
570 while ((c = getopt(argc, argv, "do:t:v")) != -1)
577 role = getrole(optarg);
578 if (role == IPL_LOGNONE) {
579 fprintf(stderr, "unknown role '%s'\n", optarg);
584 type = gettype(optarg, NULL);
585 if (type == IPLT_NONE) {
586 fprintf(stderr, "unknown type '%s'\n", optarg);
595 break; /* keep compiler happy */
598 if (argc - optind > 0)
601 if (opts & OPT_DEBUG)
602 fprintf(stderr, "poolflush: opts = %#x\n", opts);
604 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
605 fd = open(IPLOOKUP_NAME, O_RDWR);
607 perror("open(IPLOOKUP_NAME)");
612 bzero((char *)&flush, sizeof(flush));
613 flush.iplf_type = type;
614 flush.iplf_unit = role;
615 flush.iplf_arg = arg;
617 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
618 if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
619 ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
624 printf("%u object%s flushed\n", flush.iplf_count,
625 (flush.iplf_count == 1) ? "" : "s");
637 if (!strcasecmp(rolename, "ipf")) {
640 } else if (!strcasecmp(rolename, "nat")) {
642 } else if (!strcasecmp(rolename, "state")) {
644 } else if (!strcasecmp(rolename, "auth")) {
646 } else if (!strcasecmp(rolename, "sync")) {
648 } else if (!strcasecmp(rolename, "scan")) {
650 } else if (!strcasecmp(rolename, "pool")) {
651 role = IPL_LOGLOOKUP;
652 } else if (!strcasecmp(rolename, "count")) {
664 gettype(typename, minor)
670 if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
672 } else if (!strcasecmp(typename, "hash")) {
675 *minor = IPHASH_LOOKUP;
676 } else if (!strcasecmp(typename, "group-map")) {
679 *minor = IPHASH_GROUPMAP;
692 char *kernel, *core, *poolname;
693 int c, role, type, live_kernel;
703 while ((c = getopt(argc, argv, "dm:M:N:o:t:v")) != -1)
721 role = getrole(optarg);
722 if (role == IPL_LOGNONE) {
723 fprintf(stderr, "unknown role '%s'\n", optarg);
729 /* XXX This option does not work. This function as */
730 /* XXX used by state and nat can be used to format */
731 /* XXX output especially useful for scripting. It */
732 /* XXX is left here with the intention of making */
733 /* XXX it work for the same purpose at some point. */
734 pool_fields = parsefields(poolfields, optarg);
738 type = gettype(optarg, NULL);
739 if (type == IPLT_NONE) {
740 fprintf(stderr, "unknown type '%s'\n", optarg);
749 break; /* keep compiler happy */
752 if (argc - optind > 0)
755 if (opts & OPT_DEBUG)
756 fprintf(stderr, "poollist: opts = %#x\n", opts);
758 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
759 fd = open(IPLOOKUP_NAME, O_RDWR);
761 perror("open(IPLOOKUP_NAME)");
766 bzero((char *)&op, sizeof(op));
767 if (poolname != NULL) {
768 strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
769 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
774 poollist_live(role, poolname, type, fd);
776 poollist_dead(role, poolname, type, kernel, core);
782 poollist_dead(role, poolname, type, kernel, core)
784 char *poolname, *kernel, *core;
789 if (openkmem(kernel, core) == -1)
792 if (type == IPLT_ALL || type == IPLT_POOL) {
793 ip_pool_t *pools[IPL_LOGSIZE];
794 struct nlist names[2] = { { "ip_pool_list" } , { "" } };
796 if (nlist(kernel, names) != 1)
799 bzero(&pools, sizeof(pools));
800 if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
803 if (role != IPL_LOGALL) {
805 while (ptr != NULL) {
806 ptr = printpool(ptr, kmemcpywrap, poolname,
810 for (role = 0; role <= IPL_LOGMAX; role++) {
812 while (ptr != NULL) {
813 ptr = printpool(ptr, kmemcpywrap,
821 if (type == IPLT_ALL || type == IPLT_HASH) {
822 iphtable_t *tables[IPL_LOGSIZE];
823 struct nlist names[2] = { { "ipf_htables" } , { "" } };
825 if (nlist(kernel, names) != 1)
828 bzero(&tables, sizeof(tables));
829 if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
832 if (role != IPL_LOGALL) {
834 while (hptr != NULL) {
835 hptr = printhash(hptr, kmemcpywrap,
836 poolname, opts, pool_fields);
839 for (role = 0; role <= IPL_LOGMAX; role++) {
841 while (hptr != NULL) {
842 hptr = printhash(hptr, kmemcpywrap,
853 poollist_live(role, poolname, type, fd)
857 ipf_pool_stat_t plstat;
861 if (type == IPLT_ALL || type == IPLT_POOL) {
862 op.iplo_type = IPLT_POOL;
863 op.iplo_size = sizeof(plstat);
864 op.iplo_struct = &plstat;
865 op.iplo_name[0] = '\0';
868 if (role != IPL_LOGALL) {
871 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
873 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
877 showpools_live(fd, role, &plstat, poolname);
879 for (role = -1; role <= IPL_LOGMAX; role++) {
882 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
884 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
888 showpools_live(fd, role, &plstat, poolname);
895 if (type == IPLT_ALL || type == IPLT_HASH) {
898 op.iplo_type = IPLT_HASH;
899 op.iplo_size = sizeof(htstat);
900 op.iplo_struct = &htstat;
901 op.iplo_name[0] = '\0';
904 if (role != IPL_LOGALL) {
907 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
909 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
912 showhashs_live(fd, role, &htstat, poolname);
914 for (role = 0; role <= IPL_LOGMAX; role++) {
917 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
919 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
923 showhashs_live(fd, role, &htstat, poolname);
929 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
930 ipf_dstl_stat_t dlstat;
932 op.iplo_type = IPLT_DSTLIST;
933 op.iplo_size = sizeof(dlstat);
934 op.iplo_struct = &dlstat;
935 op.iplo_name[0] = '\0';
938 if (role != IPL_LOGALL) {
941 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
943 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
946 showdstls_live(fd, role, &dlstat, poolname);
948 for (role = 0; role <= IPL_LOGMAX; role++) {
951 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
953 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
957 showdstls_live(fd, role, &dlstat, poolname);
966 showpools_live(fd, role, plstp, poolname)
968 ipf_pool_stat_t *plstp;
971 ipflookupiter_t iter;
975 obj.ipfo_rev = IPFILTER_VERSION;
976 obj.ipfo_type = IPFOBJ_LOOKUPITER;
977 obj.ipfo_size = sizeof(iter);
978 obj.ipfo_ptr = &iter;
980 iter.ili_type = IPLT_POOL;
981 iter.ili_otype = IPFLOOKUPITER_LIST;
982 iter.ili_ival = IPFGENITER_LOOKUP;
984 iter.ili_data = &pool;
985 iter.ili_unit = role;
986 *iter.ili_name = '\0';
988 bzero((char *)&pool, sizeof(pool));
990 while (plstp->ipls_list[role + 1] != NULL) {
991 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
992 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
995 if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
996 ((opts & OPT_DEBUG) != 0))
997 printpool_live(&pool, fd, poolname, opts, pool_fields);
999 plstp->ipls_list[role + 1] = pool.ipo_next;
1005 showhashs_live(fd, role, htstp, poolname)
1010 ipflookupiter_t iter;
1014 obj.ipfo_rev = IPFILTER_VERSION;
1015 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1016 obj.ipfo_size = sizeof(iter);
1017 obj.ipfo_ptr = &iter;
1019 iter.ili_type = IPLT_HASH;
1020 iter.ili_otype = IPFLOOKUPITER_LIST;
1021 iter.ili_ival = IPFGENITER_LOOKUP;
1022 iter.ili_nitems = 1;
1023 iter.ili_data = &table;
1024 iter.ili_unit = role;
1025 *iter.ili_name = '\0';
1027 while (htstp->iphs_tables != NULL) {
1028 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1029 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1033 printhash_live(&table, fd, poolname, opts, pool_fields);
1035 htstp->iphs_tables = table.iph_next;
1041 showdstls_live(fd, role, dlstp, poolname)
1043 ipf_dstl_stat_t *dlstp;
1046 ipflookupiter_t iter;
1050 obj.ipfo_rev = IPFILTER_VERSION;
1051 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1052 obj.ipfo_size = sizeof(iter);
1053 obj.ipfo_ptr = &iter;
1055 iter.ili_type = IPLT_DSTLIST;
1056 iter.ili_otype = IPFLOOKUPITER_LIST;
1057 iter.ili_ival = IPFGENITER_LOOKUP;
1058 iter.ili_nitems = 1;
1059 iter.ili_data = &table;
1060 iter.ili_unit = role;
1061 *iter.ili_name = '\0';
1063 while (dlstp->ipls_list[role] != NULL) {
1064 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1065 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1069 printdstl_live(&table, fd, poolname, opts, pool_fields);
1071 dlstp->ipls_list[role] = table.ipld_next;
1077 setnodeaddr(int type, int role, void *ptr, char *arg)
1079 struct in_addr mask;
1083 if (strchr(arg, ':') == NULL) {
1085 s = strchr(arg, '/');
1087 mask.s_addr = 0xffffffff;
1088 else if (strchr(s, '.') == NULL) {
1089 if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1092 mask.s_addr = inet_addr(s + 1);
1099 /* XXX for now we use mask for IPv6 prefix length */
1100 /* XXX mask should be a union with prefix */
1101 /* XXX Currently address handling is sloppy. */
1103 if ((s = strchr(arg, '/')) == NULL)
1106 mask.s_addr = atoi(s + 1);
1109 if (type == IPLT_POOL) {
1110 ip_pool_node_t *node = ptr;
1112 node->ipn_addr.adf_family = family;
1115 if (node->ipn_addr.adf_family == AF_INET) {
1117 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1119 sizeof(struct in_addr);
1120 node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1123 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1125 sizeof(struct in6_addr);
1126 inet_pton(AF_INET6, arg,
1127 &node->ipn_addr.adf_addr.in6.s6_addr);
1130 node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1131 node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1132 } else if (type == IPLT_HASH) {
1133 iphtent_t *node = ptr;
1135 node->ipe_family = family;
1136 node->ipe_unit = role;
1139 if (node->ipe_family == AF_INET) {
1141 node->ipe_addr.in4.s_addr = inet_addr(arg);
1142 node->ipe_mask.in4.s_addr = mask.s_addr;
1145 inet_pton(AF_INET6, arg,
1146 &node->ipe_addr.in6.__u6_addr.__u6_addr32);
1147 node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1149 node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1150 node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1151 node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;