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:Rt: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)
176 opts |= OPT_NORESOLVE;
181 "cannot set type after ip address\n");
184 type = gettype(optarg, NULL);
187 fprintf(stderr, "unknown type '%s'\n", optarg);
201 fprintf(stderr, "cannot set negative ttl\n");
213 break; /* keep compiler happy */
216 if (argc - 1 - optind > 0)
219 if (argv[optind] != NULL && ipset == 0) {
220 if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
224 if (opts & OPT_DEBUG)
225 fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
228 fprintf(stderr, "no IP address given with -i\n");
232 if (poolname == NULL) {
233 fprintf(stderr, "poolname not given with add/remove node\n");
240 err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
242 err = remove_poolnode(role, poolname, &pnode, ioctl);
246 err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
248 err = remove_hashnode(role, poolname, &hnode, ioctl);
258 poolcommand(remove, argc, argv)
262 int type, role, c, err;
272 bzero((char *)&iph, sizeof(iph));
273 bzero((char *)&pool, sizeof(pool));
275 while ((c = getopt(argc, argv, "dm:no:RS:v")) != -1)
286 opts |= OPT_DONOTHING|OPT_DONTOPEN;
289 role = getrole(optarg);
290 if (role == IPL_LOGNONE) {
291 fprintf(stderr, "unknown role '%s'\n", optarg);
296 opts |= OPT_NORESOLVE;
300 iph.iph_seed = atoi(optarg);
309 break; /* keep compiler happy */
312 if (argc - 1 - optind > 0)
315 if (opts & OPT_DEBUG)
316 fprintf(stderr, "poolcommand: opts = %#x\n", opts);
318 if (poolname == NULL) {
319 fprintf(stderr, "poolname not given with add/remove pool\n");
323 type = gettype(argv[optind], &iph.iph_type);
324 if (type == IPLT_NONE) {
325 fprintf(stderr, "unknown type '%s'\n", argv[optind]);
329 if (type == IPLT_HASH) {
330 strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
331 iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
333 } else if (type == IPLT_POOL) {
334 strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
335 pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
336 pool.ipo_unit = role;
343 err = load_hash(&iph, NULL, ioctl);
346 err = load_pool(&pool, ioctl);
353 err = remove_hash(&iph, ioctl);
356 err = remove_pool(&pool, ioctl);
365 loadpoolfile(argc, argv, infile)
367 char *argv[], *infile;
371 while ((c = getopt(argc, argv, "dnRuv")) != -1)
379 opts |= OPT_DONOTHING|OPT_DONTOPEN;
382 opts |= OPT_NORESOLVE;
392 break; /* keep compiler happy */
395 if (argc - 1 - optind > 0)
398 if (opts & OPT_DEBUG)
399 fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
401 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
402 fd = open(IPLOOKUP_NAME, O_RDWR);
404 perror("open(IPLOOKUP_NAME)");
409 if (ippool_parsefile(fd, infile, ioctl) != 0)
416 poolstats(argc, argv)
420 int c, type, role, live_kernel;
421 ipf_pool_stat_t plstat;
422 ipf_dstl_stat_t dlstat;
433 bzero((char *)&op, sizeof(op));
435 while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
450 role = getrole(optarg);
451 if (role == IPL_LOGNONE) {
452 fprintf(stderr, "unknown role '%s'\n", optarg);
457 type = gettype(optarg, NULL);
458 if (type != IPLT_POOL) {
460 "-s not supported for this type yet\n");
469 break; /* keep compiler happy */
472 if (argc - 1 - optind > 0)
475 if (opts & OPT_DEBUG)
476 fprintf(stderr, "poolstats: opts = %#x\n", opts);
478 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
479 fd = open(IPLOOKUP_NAME, O_RDWR);
481 perror("open(IPLOOKUP_NAME)");
486 if (type == IPLT_ALL || type == IPLT_POOL) {
487 op.iplo_type = IPLT_POOL;
488 op.iplo_struct = &plstat;
489 op.iplo_size = sizeof(plstat);
490 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
491 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
493 ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
496 printf("%lu\taddress pools\n", plstat.ipls_pools);
497 printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
501 if (type == IPLT_ALL || type == IPLT_HASH) {
502 op.iplo_type = IPLT_HASH;
503 op.iplo_struct = &htstat;
504 op.iplo_size = sizeof(htstat);
505 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
506 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
508 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
511 printf("%lu\thash tables\n", htstat.iphs_numtables);
512 printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
513 printf("%lu\thash table no memory \n",
518 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
519 op.iplo_type = IPLT_DSTLIST;
520 op.iplo_struct = &dlstat;
521 op.iplo_size = sizeof(dlstat);
522 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
523 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
525 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
528 printf("%u\tdestination lists\n",
529 dlstat.ipls_numlists);
530 printf("%u\tdestination list nodes\n",
531 dlstat.ipls_numnodes);
532 printf("%lu\tdestination list no memory\n",
534 printf("%u\tdestination list zombies\n",
535 dlstat.ipls_numdereflists);
536 printf("%u\tdesetination list node zombies\n",
537 dlstat.ipls_numderefnodes);
545 poolflush(argc, argv)
549 int c, role, type, arg;
550 iplookupflush_t flush;
556 while ((c = getopt(argc, argv, "do:t:v")) != -1)
563 role = getrole(optarg);
564 if (role == IPL_LOGNONE) {
565 fprintf(stderr, "unknown role '%s'\n", optarg);
570 type = gettype(optarg, NULL);
571 if (type == IPLT_NONE) {
572 fprintf(stderr, "unknown type '%s'\n", optarg);
581 break; /* keep compiler happy */
584 if (argc - optind > 0)
587 if (opts & OPT_DEBUG)
588 fprintf(stderr, "poolflush: opts = %#x\n", opts);
590 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
591 fd = open(IPLOOKUP_NAME, O_RDWR);
593 perror("open(IPLOOKUP_NAME)");
598 bzero((char *)&flush, sizeof(flush));
599 flush.iplf_type = type;
600 flush.iplf_unit = role;
601 flush.iplf_arg = arg;
603 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
604 if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
605 ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
610 printf("%u object%s flushed\n", flush.iplf_count,
611 (flush.iplf_count == 1) ? "" : "s");
623 if (!strcasecmp(rolename, "ipf")) {
626 } else if (!strcasecmp(rolename, "nat")) {
628 } else if (!strcasecmp(rolename, "state")) {
630 } else if (!strcasecmp(rolename, "auth")) {
632 } else if (!strcasecmp(rolename, "sync")) {
634 } else if (!strcasecmp(rolename, "scan")) {
636 } else if (!strcasecmp(rolename, "pool")) {
637 role = IPL_LOGLOOKUP;
638 } else if (!strcasecmp(rolename, "count")) {
650 gettype(typename, minor)
656 if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
658 } else if (!strcasecmp(typename, "hash")) {
661 *minor = IPHASH_LOOKUP;
662 } else if (!strcasecmp(typename, "group-map")) {
665 *minor = IPHASH_GROUPMAP;
678 char *kernel, *core, *poolname;
679 int c, role, type, live_kernel;
689 while ((c = getopt(argc, argv, "dm:M:N:o:t:v")) != -1)
707 role = getrole(optarg);
708 if (role == IPL_LOGNONE) {
709 fprintf(stderr, "unknown role '%s'\n", optarg);
715 /* XXX This option does not work. This function as */
716 /* XXX used by state and nat can be used to format */
717 /* XXX output especially useful for scripting. It */
718 /* XXX is left here with the intention of making */
719 /* XXX it work for the same purpose at some point. */
720 pool_fields = parsefields(poolfields, optarg);
724 type = gettype(optarg, NULL);
725 if (type == IPLT_NONE) {
726 fprintf(stderr, "unknown type '%s'\n", optarg);
735 break; /* keep compiler happy */
738 if (argc - optind > 0)
741 if (opts & OPT_DEBUG)
742 fprintf(stderr, "poollist: opts = %#x\n", opts);
744 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
745 fd = open(IPLOOKUP_NAME, O_RDWR);
747 perror("open(IPLOOKUP_NAME)");
752 bzero((char *)&op, sizeof(op));
753 if (poolname != NULL) {
754 strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
755 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
760 poollist_live(role, poolname, type, fd);
762 poollist_dead(role, poolname, type, kernel, core);
768 poollist_dead(role, poolname, type, kernel, core)
770 char *poolname, *kernel, *core;
775 if (openkmem(kernel, core) == -1)
778 if (type == IPLT_ALL || type == IPLT_POOL) {
779 ip_pool_t *pools[IPL_LOGSIZE];
780 struct nlist names[2] = { { "ip_pool_list" } , { "" } };
782 if (nlist(kernel, names) != 1)
785 bzero(&pools, sizeof(pools));
786 if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
789 if (role != IPL_LOGALL) {
791 while (ptr != NULL) {
792 ptr = printpool(ptr, kmemcpywrap, poolname,
796 for (role = 0; role <= IPL_LOGMAX; role++) {
798 while (ptr != NULL) {
799 ptr = printpool(ptr, kmemcpywrap,
807 if (type == IPLT_ALL || type == IPLT_HASH) {
808 iphtable_t *tables[IPL_LOGSIZE];
809 struct nlist names[2] = { { "ipf_htables" } , { "" } };
811 if (nlist(kernel, names) != 1)
814 bzero(&tables, sizeof(tables));
815 if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
818 if (role != IPL_LOGALL) {
820 while (hptr != NULL) {
821 hptr = printhash(hptr, kmemcpywrap,
822 poolname, opts, pool_fields);
825 for (role = 0; role <= IPL_LOGMAX; role++) {
827 while (hptr != NULL) {
828 hptr = printhash(hptr, kmemcpywrap,
839 poollist_live(role, poolname, type, fd)
843 ipf_pool_stat_t plstat;
847 if (type == IPLT_ALL || type == IPLT_POOL) {
848 op.iplo_type = IPLT_POOL;
849 op.iplo_size = sizeof(plstat);
850 op.iplo_struct = &plstat;
851 op.iplo_name[0] = '\0';
854 if (role != IPL_LOGALL) {
857 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
859 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
863 showpools_live(fd, role, &plstat, poolname);
865 for (role = -1; role <= IPL_LOGMAX; role++) {
868 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
870 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
874 showpools_live(fd, role, &plstat, poolname);
881 if (type == IPLT_ALL || type == IPLT_HASH) {
884 op.iplo_type = IPLT_HASH;
885 op.iplo_size = sizeof(htstat);
886 op.iplo_struct = &htstat;
887 op.iplo_name[0] = '\0';
890 if (role != IPL_LOGALL) {
893 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
895 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
898 showhashs_live(fd, role, &htstat, poolname);
900 for (role = 0; role <= IPL_LOGMAX; role++) {
903 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
905 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
909 showhashs_live(fd, role, &htstat, poolname);
915 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
916 ipf_dstl_stat_t dlstat;
918 op.iplo_type = IPLT_DSTLIST;
919 op.iplo_size = sizeof(dlstat);
920 op.iplo_struct = &dlstat;
921 op.iplo_name[0] = '\0';
924 if (role != IPL_LOGALL) {
927 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
929 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
932 showdstls_live(fd, role, &dlstat, poolname);
934 for (role = 0; role <= IPL_LOGMAX; role++) {
937 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
939 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
943 showdstls_live(fd, role, &dlstat, poolname);
952 showpools_live(fd, role, plstp, poolname)
954 ipf_pool_stat_t *plstp;
957 ipflookupiter_t iter;
961 obj.ipfo_rev = IPFILTER_VERSION;
962 obj.ipfo_type = IPFOBJ_LOOKUPITER;
963 obj.ipfo_size = sizeof(iter);
964 obj.ipfo_ptr = &iter;
966 iter.ili_type = IPLT_POOL;
967 iter.ili_otype = IPFLOOKUPITER_LIST;
968 iter.ili_ival = IPFGENITER_LOOKUP;
970 iter.ili_data = &pool;
971 iter.ili_unit = role;
972 *iter.ili_name = '\0';
974 bzero((char *)&pool, sizeof(pool));
976 while (plstp->ipls_list[role + 1] != NULL) {
977 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
978 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
981 if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
982 ((opts & OPT_DEBUG) != 0))
983 printpool_live(&pool, fd, poolname, opts, pool_fields);
985 plstp->ipls_list[role + 1] = pool.ipo_next;
991 showhashs_live(fd, role, htstp, poolname)
996 ipflookupiter_t iter;
1000 obj.ipfo_rev = IPFILTER_VERSION;
1001 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1002 obj.ipfo_size = sizeof(iter);
1003 obj.ipfo_ptr = &iter;
1005 iter.ili_type = IPLT_HASH;
1006 iter.ili_otype = IPFLOOKUPITER_LIST;
1007 iter.ili_ival = IPFGENITER_LOOKUP;
1008 iter.ili_nitems = 1;
1009 iter.ili_data = &table;
1010 iter.ili_unit = role;
1011 *iter.ili_name = '\0';
1013 while (htstp->iphs_tables != NULL) {
1014 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1015 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1019 printhash_live(&table, fd, poolname, opts, pool_fields);
1021 htstp->iphs_tables = table.iph_next;
1027 showdstls_live(fd, role, dlstp, poolname)
1029 ipf_dstl_stat_t *dlstp;
1032 ipflookupiter_t iter;
1036 obj.ipfo_rev = IPFILTER_VERSION;
1037 obj.ipfo_type = IPFOBJ_LOOKUPITER;
1038 obj.ipfo_size = sizeof(iter);
1039 obj.ipfo_ptr = &iter;
1041 iter.ili_type = IPLT_DSTLIST;
1042 iter.ili_otype = IPFLOOKUPITER_LIST;
1043 iter.ili_ival = IPFGENITER_LOOKUP;
1044 iter.ili_nitems = 1;
1045 iter.ili_data = &table;
1046 iter.ili_unit = role;
1047 *iter.ili_name = '\0';
1049 while (dlstp->ipls_list[role] != NULL) {
1050 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1051 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1055 printdstl_live(&table, fd, poolname, opts, pool_fields);
1057 dlstp->ipls_list[role] = table.ipld_next;
1063 setnodeaddr(int type, int role, void *ptr, char *arg)
1065 struct in_addr mask;
1069 if (strchr(arg, ':') == NULL) {
1071 s = strchr(arg, '/');
1073 mask.s_addr = 0xffffffff;
1074 else if (strchr(s, '.') == NULL) {
1075 if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1078 mask.s_addr = inet_addr(s + 1);
1085 /* XXX for now we use mask for IPv6 prefix length */
1086 /* XXX mask should be a union with prefix */
1087 /* XXX Currently address handling is sloppy. */
1089 if ((s = strchr(arg, '/')) == NULL)
1092 mask.s_addr = atoi(s + 1);
1095 if (type == IPLT_POOL) {
1096 ip_pool_node_t *node = ptr;
1098 node->ipn_addr.adf_family = family;
1101 if (node->ipn_addr.adf_family == AF_INET) {
1103 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1105 sizeof(struct in_addr);
1106 node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1109 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1111 sizeof(struct in6_addr);
1112 inet_pton(AF_INET6, arg,
1113 &node->ipn_addr.adf_addr.in6.s6_addr);
1116 node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1117 node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1118 } else if (type == IPLT_HASH) {
1119 iphtent_t *node = ptr;
1121 node->ipe_family = family;
1122 node->ipe_unit = role;
1125 if (node->ipe_family == AF_INET) {
1127 node->ipe_addr.in4.s_addr = inet_addr(arg);
1128 node->ipe_mask.in4.s_addr = mask.s_addr;
1131 inet_pton(AF_INET6, arg,
1132 &node->ipe_addr.in6.__u6_addr.__u6_addr32);
1133 node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
1135 node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
1136 node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
1137 node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;