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 #if __FreeBSD_version >= 300000
19 # include <net/if_var.h>
21 #include <netinet/in.h>
23 #include <arpa/inet.h>
33 # include <linux/a.out.h>
39 #include "netinet/ipl.h"
40 #include "netinet/ip_lookup.h"
41 #include "netinet/ip_pool.h"
42 #include "netinet/ip_htable.h"
46 extern int ippool_yyparse __P((void));
47 extern int ippool_yydebug;
48 extern FILE *ippool_yyin;
52 void usage __P((char *));
53 int main __P((int, char **));
54 int poolcommand __P((int, int, char *[]));
55 int poolnodecommand __P((int, int, char *[]));
56 int loadpoolfile __P((int, char *[], char *));
57 int poollist __P((int, char *[]));
58 void poollist_dead __P((int, char *, int, char *, char *));
59 void poollist_live __P((int, char *, int, int));
60 int poolflush __P((int, char *[]));
61 int poolstats __P((int, char *[]));
62 int gettype __P((char *, u_int *));
63 int getrole __P((char *));
64 int setnodeaddr __P((int, int, void *ptr, char *arg));
65 void showpools_live __P((int, int, ipf_pool_stat_t *, char *));
66 void showhashs_live __P((int, int, iphtstat_t *, char *));
67 void showdstls_live __P((int, int, ipf_dstl_stat_t *, char *));
72 wordtab_t *pool_fields = NULL;
80 fprintf(stderr, "Usage:\t%s\n", prog);
81 fprintf(stderr, "\t-a [-dnv] [-m <name>] [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
82 fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
83 fprintf(stderr, "\t-f <file> [-dnuv]\n");
84 fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
85 fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-O <fields>]\n");
86 fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
87 fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
88 fprintf(stderr, "\t-s [-dtv] [-M <core>] [-N <namelist>]\n");
103 assigndefined(getenv("IPPOOL_PREDEFINED"));
105 switch (getopt(argc, argv, "aAf:FlnrRsv"))
108 err = poolnodecommand(0, argc, argv);
111 err = poolcommand(0, argc, argv);
114 err = loadpoolfile(argc, argv, optarg);
117 err = poolflush(argc, argv);
120 err = poollist(argc, argv);
123 opts |= OPT_DONOTHING|OPT_DONTOPEN;
126 err = poolnodecommand(1, argc, argv);
129 err = poolcommand(1, argc, argv);
132 err = poolstats(argc, argv);
148 poolnodecommand(remove, argc, argv)
152 int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
153 char *poolname = NULL;
154 ip_pool_node_t pnode;
160 bzero((char *)&pnode, sizeof(pnode));
161 bzero((char *)&hnode, sizeof(hnode));
163 while ((c = getopt(argc, argv, "di:m:no:Rt:T:v")) != -1)
171 if (setnodeaddr(type, role, ptr, optarg) == 0)
178 opts |= OPT_DONOTHING|OPT_DONTOPEN;
183 "cannot set role after ip address\n");
186 role = getrole(optarg);
187 if (role == IPL_LOGNONE)
191 opts |= OPT_NORESOLVE;
196 "cannot set type after ip address\n");
199 type = gettype(optarg, NULL);
202 fprintf(stderr, "unknown type '%s'\n", optarg);
215 fprintf(stderr, "cannot set negative ttl\n");
224 if (argv[optind] != NULL && ipset == 0) {
225 if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
229 if (opts & OPT_DEBUG)
230 fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
233 fprintf(stderr, "no IP address given with -i\n");
237 if (poolname == NULL) {
238 fprintf(stderr, "poolname not given with add/remove node\n");
245 err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
247 err = remove_poolnode(role, poolname, &pnode, ioctl);
251 err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
253 err = remove_hashnode(role, poolname, &hnode, ioctl);
263 poolcommand(remove, argc, argv)
267 int type, role, c, err;
277 bzero((char *)&iph, sizeof(iph));
278 bzero((char *)&pool, sizeof(pool));
280 while ((c = getopt(argc, argv, "dm:no:RSv")) != -1)
291 opts |= OPT_DONOTHING|OPT_DONTOPEN;
294 role = getrole(optarg);
295 if (role == IPL_LOGNONE) {
296 fprintf(stderr, "unknown role '%s'\n", optarg);
301 opts |= OPT_NORESOLVE;
304 iph.iph_seed = atoi(optarg);
311 if (opts & OPT_DEBUG)
312 fprintf(stderr, "poolcommand: opts = %#x\n", opts);
314 if (poolname == NULL) {
315 fprintf(stderr, "poolname not given with add/remove pool\n");
319 type = gettype(argv[optind], &iph.iph_type);
320 if (type == IPLT_NONE) {
321 fprintf(stderr, "unknown type '%s'\n", argv[optind]);
325 if (type == IPLT_HASH) {
326 strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
327 iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
329 } else if (type == IPLT_POOL) {
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);
361 loadpoolfile(argc, argv, infile)
363 char *argv[], *infile;
369 while ((c = getopt(argc, argv, "dnRuv")) != -1)
377 opts |= OPT_DONOTHING|OPT_DONTOPEN;
380 opts |= OPT_NORESOLVE;
390 if (opts & OPT_DEBUG)
391 fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
393 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
394 fd = open(IPLOOKUP_NAME, O_RDWR);
396 perror("open(IPLOOKUP_NAME)");
401 if (ippool_parsefile(fd, infile, ioctl) != 0)
408 poolstats(argc, argv)
412 int c, type, role, live_kernel;
413 ipf_pool_stat_t plstat;
414 ipf_dstl_stat_t dlstat;
425 bzero((char *)&op, sizeof(op));
427 while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
442 role = getrole(optarg);
443 if (role == IPL_LOGNONE) {
444 fprintf(stderr, "unknown role '%s'\n", optarg);
449 type = gettype(optarg, NULL);
450 if (type != IPLT_POOL) {
452 "-s not supported for this type yet\n");
461 if (opts & OPT_DEBUG)
462 fprintf(stderr, "poolstats: opts = %#x\n", opts);
464 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
465 fd = open(IPLOOKUP_NAME, O_RDWR);
467 perror("open(IPLOOKUP_NAME)");
472 if (type == IPLT_ALL || type == IPLT_POOL) {
473 op.iplo_type = IPLT_POOL;
474 op.iplo_struct = &plstat;
475 op.iplo_size = sizeof(plstat);
476 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
477 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
479 ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
482 printf("%lu\taddress pools\n", plstat.ipls_pools);
483 printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
487 if (type == IPLT_ALL || type == IPLT_HASH) {
488 op.iplo_type = IPLT_HASH;
489 op.iplo_struct = &htstat;
490 op.iplo_size = sizeof(htstat);
491 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
492 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
494 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
497 printf("%lu\thash tables\n", htstat.iphs_numtables);
498 printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
499 printf("%lu\thash table no memory \n",
504 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
505 op.iplo_type = IPLT_DSTLIST;
506 op.iplo_struct = &dlstat;
507 op.iplo_size = sizeof(dlstat);
508 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
509 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
511 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
514 printf("%u\tdestination lists\n",
515 dlstat.ipls_numlists);
516 printf("%u\tdestination list nodes\n",
517 dlstat.ipls_numnodes);
518 printf("%lu\tdestination list no memory\n",
520 printf("%u\tdestination list zombies\n",
521 dlstat.ipls_numdereflists);
522 printf("%u\tdesetination list node zombies\n",
523 dlstat.ipls_numderefnodes);
531 poolflush(argc, argv)
535 int c, role, type, arg;
536 iplookupflush_t flush;
542 while ((c = getopt(argc, argv, "do:t:v")) != -1)
549 role = getrole(optarg);
550 if (role == IPL_LOGNONE) {
551 fprintf(stderr, "unknown role '%s'\n", optarg);
556 type = gettype(optarg, NULL);
557 if (type == IPLT_NONE) {
558 fprintf(stderr, "unknown type '%s'\n", optarg);
567 if (opts & OPT_DEBUG)
568 fprintf(stderr, "poolflush: opts = %#x\n", opts);
570 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
571 fd = open(IPLOOKUP_NAME, O_RDWR);
573 perror("open(IPLOOKUP_NAME)");
578 bzero((char *)&flush, sizeof(flush));
579 flush.iplf_type = type;
580 flush.iplf_unit = role;
581 flush.iplf_arg = arg;
583 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
584 if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
585 ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
590 printf("%u object%s flushed\n", flush.iplf_count,
591 (flush.iplf_count == 1) ? "" : "s");
603 if (!strcasecmp(rolename, "ipf")) {
606 } else if (!strcasecmp(rolename, "nat")) {
608 } else if (!strcasecmp(rolename, "state")) {
610 } else if (!strcasecmp(rolename, "auth")) {
612 } else if (!strcasecmp(rolename, "sync")) {
614 } else if (!strcasecmp(rolename, "scan")) {
616 } else if (!strcasecmp(rolename, "pool")) {
617 role = IPL_LOGLOOKUP;
618 } else if (!strcasecmp(rolename, "count")) {
630 gettype(typename, minor)
636 if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
638 } else if (!strcasecmp(typename, "hash")) {
641 *minor = IPHASH_LOOKUP;
642 } else if (!strcasecmp(typename, "group-map")) {
645 *minor = IPHASH_GROUPMAP;
658 char *kernel, *core, *poolname;
659 int c, role, type, live_kernel;
669 while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1)
687 role = getrole(optarg);
688 if (role == IPL_LOGNONE) {
689 fprintf(stderr, "unknown role '%s'\n", optarg);
694 pool_fields = parsefields(poolfields, optarg);
697 opts |= OPT_NORESOLVE;
700 type = gettype(optarg, NULL);
701 if (type == IPLT_NONE) {
702 fprintf(stderr, "unknown type '%s'\n", optarg);
711 if (opts & OPT_DEBUG)
712 fprintf(stderr, "poollist: opts = %#x\n", opts);
714 if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
715 fd = open(IPLOOKUP_NAME, O_RDWR);
717 perror("open(IPLOOKUP_NAME)");
722 bzero((char *)&op, sizeof(op));
723 if (poolname != NULL) {
724 strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
725 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
730 poollist_live(role, poolname, type, fd);
732 poollist_dead(role, poolname, type, kernel, core);
738 poollist_dead(role, poolname, type, kernel, core)
740 char *poolname, *kernel, *core;
745 if (openkmem(kernel, core) == -1)
748 if (type == IPLT_ALL || type == IPLT_POOL) {
749 ip_pool_t *pools[IPL_LOGSIZE];
750 struct nlist names[2] = { { "ip_pool_list" } , { "" } };
752 if (nlist(kernel, names) != 1)
755 bzero(&pools, sizeof(pools));
756 if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
759 if (role != IPL_LOGALL) {
761 while (ptr != NULL) {
762 ptr = printpool(ptr, kmemcpywrap, poolname,
766 for (role = 0; role <= IPL_LOGMAX; role++) {
768 while (ptr != NULL) {
769 ptr = printpool(ptr, kmemcpywrap,
777 if (type == IPLT_ALL || type == IPLT_HASH) {
778 iphtable_t *tables[IPL_LOGSIZE];
779 struct nlist names[2] = { { "ipf_htables" } , { "" } };
781 if (nlist(kernel, names) != 1)
784 bzero(&tables, sizeof(tables));
785 if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
788 if (role != IPL_LOGALL) {
790 while (hptr != NULL) {
791 hptr = printhash(hptr, kmemcpywrap,
792 poolname, opts, pool_fields);
795 for (role = 0; role <= IPL_LOGMAX; role++) {
797 while (hptr != NULL) {
798 hptr = printhash(hptr, kmemcpywrap,
809 poollist_live(role, poolname, type, fd)
813 ipf_pool_stat_t plstat;
817 if (type == IPLT_ALL || type == IPLT_POOL) {
818 op.iplo_type = IPLT_POOL;
819 op.iplo_size = sizeof(plstat);
820 op.iplo_struct = &plstat;
821 op.iplo_name[0] = '\0';
824 if (role != IPL_LOGALL) {
827 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
829 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
833 showpools_live(fd, role, &plstat, poolname);
835 for (role = -1; role <= IPL_LOGMAX; role++) {
838 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
840 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
844 showpools_live(fd, role, &plstat, poolname);
851 if (type == IPLT_ALL || type == IPLT_HASH) {
854 op.iplo_type = IPLT_HASH;
855 op.iplo_size = sizeof(htstat);
856 op.iplo_struct = &htstat;
857 op.iplo_name[0] = '\0';
860 if (role != IPL_LOGALL) {
863 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
865 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
868 showhashs_live(fd, role, &htstat, poolname);
870 for (role = 0; role <= IPL_LOGMAX; role++) {
873 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
875 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
879 showhashs_live(fd, role, &htstat, poolname);
885 if (type == IPLT_ALL || type == IPLT_DSTLIST) {
886 ipf_dstl_stat_t dlstat;
888 op.iplo_type = IPLT_DSTLIST;
889 op.iplo_size = sizeof(dlstat);
890 op.iplo_struct = &dlstat;
891 op.iplo_name[0] = '\0';
894 if (role != IPL_LOGALL) {
897 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
899 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
902 showdstls_live(fd, role, &dlstat, poolname);
904 for (role = 0; role <= IPL_LOGMAX; role++) {
907 c = ioctl(fd, SIOCLOOKUPSTAT, &op);
909 ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
913 showdstls_live(fd, role, &dlstat, poolname);
922 showpools_live(fd, role, plstp, poolname)
924 ipf_pool_stat_t *plstp;
927 ipflookupiter_t iter;
931 obj.ipfo_rev = IPFILTER_VERSION;
932 obj.ipfo_type = IPFOBJ_LOOKUPITER;
933 obj.ipfo_size = sizeof(iter);
934 obj.ipfo_ptr = &iter;
936 iter.ili_type = IPLT_POOL;
937 iter.ili_otype = IPFLOOKUPITER_LIST;
938 iter.ili_ival = IPFGENITER_LOOKUP;
940 iter.ili_data = &pool;
941 iter.ili_unit = role;
942 *iter.ili_name = '\0';
944 bzero((char *)&pool, sizeof(pool));
946 while (plstp->ipls_list[role + 1] != NULL) {
947 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
948 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
951 if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
952 ((opts & OPT_DEBUG) != 0))
953 printpool_live(&pool, fd, poolname, opts, pool_fields);
955 plstp->ipls_list[role + 1] = pool.ipo_next;
961 showhashs_live(fd, role, htstp, poolname)
966 ipflookupiter_t iter;
970 obj.ipfo_rev = IPFILTER_VERSION;
971 obj.ipfo_type = IPFOBJ_LOOKUPITER;
972 obj.ipfo_size = sizeof(iter);
973 obj.ipfo_ptr = &iter;
975 iter.ili_type = IPLT_HASH;
976 iter.ili_otype = IPFLOOKUPITER_LIST;
977 iter.ili_ival = IPFGENITER_LOOKUP;
979 iter.ili_data = &table;
980 iter.ili_unit = role;
981 *iter.ili_name = '\0';
983 while (htstp->iphs_tables != NULL) {
984 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
985 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
989 printhash_live(&table, fd, poolname, opts, pool_fields);
991 htstp->iphs_tables = table.iph_next;
997 showdstls_live(fd, role, dlstp, poolname)
999 ipf_dstl_stat_t *dlstp;
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_DSTLIST;
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 (dlstp->ipls_list[role] != NULL) {
1020 if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
1021 ipferror(fd, "ioctl(SIOCLOOKUPITER)");
1025 printdstl_live(&table, fd, poolname, opts, pool_fields);
1027 dlstp->ipls_list[role] = table.ipld_next;
1033 setnodeaddr(int type, int role, void *ptr, char *arg)
1035 struct in_addr mask;
1038 s = strchr(arg, '/');
1040 mask.s_addr = 0xffffffff;
1041 else if (strchr(s, '.') == NULL) {
1042 if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
1045 mask.s_addr = inet_addr(s + 1);
1050 if (type == IPLT_POOL) {
1051 ip_pool_node_t *node = ptr;
1053 if (node->ipn_addr.adf_family == AF_INET)
1054 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1056 sizeof(struct in_addr);
1059 node->ipn_addr.adf_len = offsetof(addrfamily_t,
1061 sizeof(struct in6_addr);
1063 node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
1064 node->ipn_mask.adf_len = node->ipn_addr.adf_len;
1065 node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
1066 } else if (type == IPLT_HASH) {
1067 iphtent_t *node = ptr;
1069 node->ipe_addr.in4.s_addr = inet_addr(arg);
1070 node->ipe_mask.in4.s_addr = mask.s_addr;
1071 node->ipe_family = AF_INET;
1072 node->ipe_unit = role;