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 #if defined(BSD) && (BSD >= 199306)
13 # include <sys/cdefs.h>
15 #include <sys/ioctl.h>
18 #include <netinet/in.h>
20 #include <arpa/inet.h>
30 # include <linux/a.out.h>
36 #include "netinet/ipl.h"
37 #include "netinet/ip_lookup.h"
38 #include "netinet/ip_pool.h"
39 #include "netinet/ip_htable.h"
43 extern int ippool_yyparse __P((void));
44 extern int ippool_yydebug;
45 extern FILE *ippool_yyin;
49 void usage __P((char *));
50 int main __P((int, char **));
51 int poolcommand __P((int, int, char *[]));
52 int poolnodecommand __P((int, int, char *[]));
53 int loadpoolfile __P((int, char *[], char *));
54 int poollist __P((int, char *[]));
55 void poollist_dead __P((int, char *, int, char *, char *));
56 void poollist_live __P((int, char *, int, int));
57 int poolflush __P((int, char *[]));
58 int poolstats __P((int, char *[]));
59 int gettype __P((char *, u_int *));
60 int getrole __P((char *));
61 int setnodeaddr __P((int, int, void *ptr, char *arg));
62 void showpools_live __P((int, int, ipf_pool_stat_t *, char *));
63 void showhashs_live __P((int, int, iphtstat_t *, char *));
64 void showdstls_live __P((int, int, ipf_dstl_stat_t *, char *));
69 wordtab_t *pool_fields = NULL;
77 fprintf(stderr, "Usage:\t%s\n", prog);
78 fprintf(stderr, "\t-a [-dnv] -m <name> [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
79 fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
80 fprintf(stderr, "\t-f <file> [-dnuvR]\n");
81 fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
82 fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-o <role>] [-M <core>] [-N <namelist>]\n");
83 fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
84 fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
85 fprintf(stderr, "\t-s [-dtv] [-M <core>] [-N <namelist>]\n");
100 assigndefined(getenv("IPPOOL_PREDEFINED"));
102 switch (getopt(argc, argv, "aAf:FlrRs"))
105 err = poolnodecommand(0, argc, argv);
108 err = poolcommand(0, argc, argv);
111 err = loadpoolfile(argc, argv, optarg);
114 err = poolflush(argc, argv);
117 err = poollist(argc, argv);
120 err = poolnodecommand(1, argc, argv);
123 err = poolcommand(1, argc, argv);
126 err = poolstats(argc, argv);
139 poolnodecommand(remove, argc, argv)
143 int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
144 char *poolname = NULL;
145 ip_pool_node_t pnode;
151 bzero((char *)&pnode, sizeof(pnode));
152 bzero((char *)&hnode, sizeof(hnode));
154 while ((c = getopt(argc, argv, "di:m:no:Rt:T:v")) != -1)
162 if (setnodeaddr(type, role, ptr, optarg) == 0)
169 opts |= OPT_DONOTHING|OPT_DONTOPEN;
174 "cannot set role after ip address\n");
177 role = getrole(optarg);
178 if (role == IPL_LOGNONE)
182 opts |= OPT_NORESOLVE;
187 "cannot set type after ip address\n");
190 type = gettype(optarg, NULL);
193 fprintf(stderr, "unknown type '%s'\n", optarg);
207 fprintf(stderr, "cannot set negative ttl\n");
219 break; /* keep compiler happy */
222 if (argc - 1 - optind > 0)
225 if (argv[optind] != NULL && ipset == 0) {
226 if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
230 if (opts & OPT_DEBUG)
231 fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
234 fprintf(stderr, "no IP address given with -i\n");
238 if (poolname == NULL) {
239 fprintf(stderr, "poolname not given with add/remove node\n");
246 err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
248 err = remove_poolnode(role, poolname, &pnode, ioctl);
252 err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
254 err = remove_hashnode(role, poolname, &hnode, ioctl);
264 poolcommand(remove, argc, argv)
268 int type, role, c, err;
278 bzero((char *)&iph, sizeof(iph));
279 bzero((char *)&pool, sizeof(pool));
281 while ((c = getopt(argc, argv, "dm:no:RS:v")) != -1)
292 opts |= OPT_DONOTHING|OPT_DONTOPEN;
295 role = getrole(optarg);
296 if (role == IPL_LOGNONE) {
297 fprintf(stderr, "unknown role '%s'\n", optarg);
302 opts |= OPT_NORESOLVE;
306 iph.iph_seed = atoi(optarg);
315 break; /* keep compiler happy */
318 if (argc - 1 - optind > 0)
321 if (opts & OPT_DEBUG)
322 fprintf(stderr, "poolcommand: opts = %#x\n", opts);
324 if (poolname == NULL) {
325 fprintf(stderr, "poolname not given with add/remove pool\n");
329 type = gettype(argv[optind], &iph.iph_type);
330 if (type == IPLT_NONE) {
331 fprintf(stderr, "unknown type '%s'\n", argv[optind]);
335 if (type == IPLT_HASH) {
336 strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
337 iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
339 } else if (type == IPLT_POOL) {
340 strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
341 pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
342 pool.ipo_unit = role;
349 err = load_hash(&iph, NULL, ioctl);
352 err = load_pool(&pool, ioctl);
359 err = remove_hash(&iph, ioctl);
362 err = remove_pool(&pool, ioctl);
371 loadpoolfile(argc, argv, infile)
373 char *argv[], *infile;
377 while ((c = getopt(argc, argv, "dnRuv")) != -1)
385 opts |= OPT_DONOTHING|OPT_DONTOPEN;
388 opts |= OPT_NORESOLVE;
398 break; /* keep compiler happy */
401 if (argc - 1 - optind > 0)
404 if (opts & OPT_DEBUG)
405 fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
407 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
408 fd = open(IPLOOKUP_NAME, O_RDWR);
410 perror("open(IPLOOKUP_NAME)");
415 if (ippool_parsefile(fd, infile, ioctl) != 0)
422 poolstats(argc, argv)
426 int c, type, role, live_kernel;
427 ipf_pool_stat_t plstat;
428 ipf_dstl_stat_t dlstat;
439 bzero((char *)&op, sizeof(op));
441 while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
456 role = getrole(optarg);
457 if (role == IPL_LOGNONE) {
458 fprintf(stderr, "unknown role '%s'\n", optarg);
463 type = gettype(optarg, NULL);
464 if (type != IPLT_POOL) {
466 "-s not supported for this type yet\n");
475 break; /* keep compiler happy */
478 if (argc - 1 - optind > 0)
481 if (opts & OPT_DEBUG)
482 fprintf(stderr, "poolstats: opts = %#x\n", opts);
484 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
485 fd = open(IPLOOKUP_NAME, O_RDWR);
487 perror("open(IPLOOKUP_NAME)");
492 if (type == IPLT_ALL || type == IPLT_POOL) {
493 op.iplo_type = IPLT_POOL;
494 op.iplo_struct = &plstat;
495 op.iplo_size = sizeof(plstat);
496 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
497 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
499 ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
502 printf("%lu\taddress pools\n", plstat.ipls_pools);
503 printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
507 if (type == IPLT_ALL || type == IPLT_HASH) {
508 op.iplo_type = IPLT_HASH;
509 op.iplo_struct = &htstat;
510 op.iplo_size = sizeof(htstat);
511 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
512 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
514 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
517 printf("%lu\thash tables\n", htstat.iphs_numtables);
518 printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
519 printf("%lu\thash table no memory \n",
524 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
525 op.iplo_type = IPLT_DSTLIST;
526 op.iplo_struct = &dlstat;
527 op.iplo_size = sizeof(dlstat);
528 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
529 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
531 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
534 printf("%u\tdestination lists\n",
535 dlstat.ipls_numlists);
536 printf("%u\tdestination list nodes\n",
537 dlstat.ipls_numnodes);
538 printf("%lu\tdestination list no memory\n",
540 printf("%u\tdestination list zombies\n",
541 dlstat.ipls_numdereflists);
542 printf("%u\tdesetination list node zombies\n",
543 dlstat.ipls_numderefnodes);
551 poolflush(argc, argv)
555 int c, role, type, arg;
556 iplookupflush_t flush;
562 while ((c = getopt(argc, argv, "do:t:v")) != -1)
569 role = getrole(optarg);
570 if (role == IPL_LOGNONE) {
571 fprintf(stderr, "unknown role '%s'\n", optarg);
576 type = gettype(optarg, NULL);
577 if (type == IPLT_NONE) {
578 fprintf(stderr, "unknown type '%s'\n", optarg);
587 break; /* keep compiler happy */
590 if (argc - optind > 0)
593 if (opts & OPT_DEBUG)
594 fprintf(stderr, "poolflush: opts = %#x\n", opts);
596 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
597 fd = open(IPLOOKUP_NAME, O_RDWR);
599 perror("open(IPLOOKUP_NAME)");
604 bzero((char *)&flush, sizeof(flush));
605 flush.iplf_type = type;
606 flush.iplf_unit = role;
607 flush.iplf_arg = arg;
609 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
610 if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
611 ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
616 printf("%u object%s flushed\n", flush.iplf_count,
617 (flush.iplf_count == 1) ? "" : "s");
629 if (!strcasecmp(rolename, "ipf")) {
632 } else if (!strcasecmp(rolename, "nat")) {
634 } else if (!strcasecmp(rolename, "state")) {
636 } else if (!strcasecmp(rolename, "auth")) {
638 } else if (!strcasecmp(rolename, "sync")) {
640 } else if (!strcasecmp(rolename, "scan")) {
642 } else if (!strcasecmp(rolename, "pool")) {
643 role = IPL_LOGLOOKUP;
644 } else if (!strcasecmp(rolename, "count")) {
656 gettype(typename, minor)
662 if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
664 } else if (!strcasecmp(typename, "hash")) {
667 *minor = IPHASH_LOOKUP;
668 } else if (!strcasecmp(typename, "group-map")) {
671 *minor = IPHASH_GROUPMAP;
684 char *kernel, *core, *poolname;
685 int c, role, type, live_kernel;
695 while ((c = getopt(argc, argv, "dm:M:N:o:t:v")) != -1)
713 role = getrole(optarg);
714 if (role == IPL_LOGNONE) {
715 fprintf(stderr, "unknown role '%s'\n", optarg);
721 /* XXX This option does not work. This function as */
722 /* XXX used by state and nat can be used to format */
723 /* XXX output especially useful for scripting. It */
724 /* XXX is left here with the intention of making */
725 /* XXX it work for the same purpose at some point. */
726 pool_fields = parsefields(poolfields, optarg);
730 type = gettype(optarg, NULL);
731 if (type == IPLT_NONE) {
732 fprintf(stderr, "unknown type '%s'\n", optarg);
741 break; /* keep compiler happy */
744 if (argc - optind > 0)
747 if (opts & OPT_DEBUG)
748 fprintf(stderr, "poollist: opts = %#x\n", opts);
750 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
751 fd = open(IPLOOKUP_NAME, O_RDWR);
753 perror("open(IPLOOKUP_NAME)");
758 bzero((char *)&op, sizeof(op));
759 if (poolname != NULL) {
760 strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
761 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
766 poollist_live(role, poolname, type, fd);
768 poollist_dead(role, poolname, type, kernel, core);
774 poollist_dead(role, poolname, type, kernel, core)
776 char *poolname, *kernel, *core;
781 if (openkmem(kernel, core) == -1)
784 if (type == IPLT_ALL || type == IPLT_POOL) {
785 ip_pool_t *pools[IPL_LOGSIZE];
786 struct nlist names[2] = { { "ip_pool_list" } , { "" } };
788 if (nlist(kernel, names) != 1)
791 bzero(&pools, sizeof(pools));
792 if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
795 if (role != IPL_LOGALL) {
797 while (ptr != NULL) {
798 ptr = printpool(ptr, kmemcpywrap, poolname,
802 for (role = 0; role <= IPL_LOGMAX; role++) {
804 while (ptr != NULL) {
805 ptr = printpool(ptr, kmemcpywrap,
813 if (type == IPLT_ALL || type == IPLT_HASH) {
814 iphtable_t *tables[IPL_LOGSIZE];
815 struct nlist names[2] = { { "ipf_htables" } , { "" } };
817 if (nlist(kernel, names) != 1)
820 bzero(&tables, sizeof(tables));
821 if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
824 if (role != IPL_LOGALL) {
826 while (hptr != NULL) {
827 hptr = printhash(hptr, kmemcpywrap,
828 poolname, opts, pool_fields);
831 for (role = 0; role <= IPL_LOGMAX; role++) {
833 while (hptr != NULL) {
834 hptr = printhash(hptr, kmemcpywrap,
845 poollist_live(role, poolname, type, fd)
849 ipf_pool_stat_t plstat;
853 if (type == IPLT_ALL || type == IPLT_POOL) {
854 op.iplo_type = IPLT_POOL;
855 op.iplo_size = sizeof(plstat);
856 op.iplo_struct = &plstat;
857 op.iplo_name[0] = '\0';
860 if (role != IPL_LOGALL) {
863 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
865 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
869 showpools_live(fd, role, &plstat, poolname);
871 for (role = -1; role <= IPL_LOGMAX; role++) {
874 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
876 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
880 showpools_live(fd, role, &plstat, poolname);
887 if (type == IPLT_ALL || type == IPLT_HASH) {
890 op.iplo_type = IPLT_HASH;
891 op.iplo_size = sizeof(htstat);
892 op.iplo_struct = &htstat;
893 op.iplo_name[0] = '\0';
896 if (role != IPL_LOGALL) {
899 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
901 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
904 showhashs_live(fd, role, &htstat, poolname);
906 for (role = 0; role <= IPL_LOGMAX; role++) {
909 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
911 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
915 showhashs_live(fd, role, &htstat, poolname);
921 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
922 ipf_dstl_stat_t dlstat;
924 op.iplo_type = IPLT_DSTLIST;
925 op.iplo_size = sizeof(dlstat);
926 op.iplo_struct = &dlstat;
927 op.iplo_name[0] = '\0';
930 if (role != IPL_LOGALL) {
933 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
935 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
938 showdstls_live(fd, role, &dlstat, poolname);
940 for (role = 0; role <= IPL_LOGMAX; role++) {
943 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
945 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
949 showdstls_live(fd, role, &dlstat, poolname);
958 showpools_live(fd, role, plstp, poolname)
960 ipf_pool_stat_t *plstp;
963 ipflookupiter_t iter;
967 obj.ipfo_rev = IPFILTER_VERSION;
968 obj.ipfo_type = IPFOBJ_LOOKUPITER;
969 obj.ipfo_size = sizeof(iter);
970 obj.ipfo_ptr = &iter;
972 iter.ili_type = IPLT_POOL;
973 iter.ili_otype = IPFLOOKUPITER_LIST;
974 iter.ili_ival = IPFGENITER_LOOKUP;
976 iter.ili_data = &pool;
977 iter.ili_unit = role;
978 *iter.ili_name = '\0';
980 bzero((char *)&pool, sizeof(pool));
982 while (plstp->ipls_list[role + 1] != NULL) {
983 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
984 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
987 if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
988 ((opts & OPT_DEBUG) != 0))
989 printpool_live(&pool, fd, poolname, opts, pool_fields);
991 plstp->ipls_list[role + 1] = pool.ipo_next;
997 showhashs_live(fd, role, htstp, poolname)
1002 ipflookupiter_t iter;
1006 obj.ipfo_rev = IPFILTER_VERSION;
1007 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1008 obj.ipfo_size = sizeof(iter);
1009 obj.ipfo_ptr = &iter;
1011 iter.ili_type = IPLT_HASH;
1012 iter.ili_otype = IPFLOOKUPITER_LIST;
1013 iter.ili_ival = IPFGENITER_LOOKUP;
1014 iter.ili_nitems = 1;
1015 iter.ili_data = &table;
1016 iter.ili_unit = role;
1017 *iter.ili_name = '\0';
1019 while (htstp->iphs_tables != NULL) {
1020 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1021 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1025 printhash_live(&table, fd, poolname, opts, pool_fields);
1027 htstp->iphs_tables = table.iph_next;
1033 showdstls_live(fd, role, dlstp, poolname)
1035 ipf_dstl_stat_t *dlstp;
1038 ipflookupiter_t iter;
1042 obj.ipfo_rev = IPFILTER_VERSION;
1043 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1044 obj.ipfo_size = sizeof(iter);
1045 obj.ipfo_ptr = &iter;
1047 iter.ili_type = IPLT_DSTLIST;
1048 iter.ili_otype = IPFLOOKUPITER_LIST;
1049 iter.ili_ival = IPFGENITER_LOOKUP;
1050 iter.ili_nitems = 1;
1051 iter.ili_data = &table;
1052 iter.ili_unit = role;
1053 *iter.ili_name = '\0';
1055 while (dlstp->ipls_list[role] != NULL) {
1056 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1057 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1061 printdstl_live(&table, fd, poolname, opts, pool_fields);
1063 dlstp->ipls_list[role] = table.ipld_next;
1069 setnodeaddr(int type, int role, void *ptr, char *arg)
1071 struct in_addr mask;
1075 if (strchr(arg, ':') == NULL) {
1077 s = strchr(arg, '/');
1079 mask.s_addr = 0xffffffff;
1080 else if (strchr(s, '.') == NULL) {
1081 if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1084 mask.s_addr = inet_addr(s + 1);
1091 /* XXX for now we use mask for IPv6 prefix length */
1092 /* XXX mask should be a union with prefix */
1093 /* XXX Currently address handling is sloppy. */
1095 if ((s = strchr(arg, '/')) == NULL)
1098 mask.s_addr = atoi(s + 1);
1101 if (type == IPLT_POOL) {
1102 ip_pool_node_t *node = ptr;
1104 node->ipn_addr.adf_family = family;
1107 if (node->ipn_addr.adf_family == AF_INET) {
1109 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1111 sizeof(struct in_addr);
1112 node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1115 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1117 sizeof(struct in6_addr);
1118 inet_pton(AF_INET6, arg,
1119 &node->ipn_addr.adf_addr.in6.s6_addr);
1122 node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1123 node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1124 } else if (type == IPLT_HASH) {
1125 iphtent_t *node = ptr;
1127 node->ipe_family = family;
1128 node->ipe_unit = role;
1131 if (node->ipe_family == AF_INET) {
1133 node->ipe_addr.in4.s_addr = inet_addr(arg);
1134 node->ipe_mask.in4.s_addr = mask.s_addr;
1137 inet_pton(AF_INET6, arg,
1138 &node->ipe_addr.in6.__u6_addr.__u6_addr32);
1139 node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1141 node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1142 node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1143 node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;