From 9d099b4f3887700ed2a3c58875bde79c2ba1a4a3 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Tue, 29 Jul 2014 22:44:26 +0000 Subject: [PATCH] * Dump available table algorithms via "ipfw talist" cmd. Kernel changes: * Add type/refcount fields to table algo instances. * Add IP_FW_TABLES_ALIST opcode to export available algorihms to userland. Userland changes: * Fix cores on empty input inside "ipfw table" handler. * Add "ipfw talist" cmd to print availabled kernel algorithms. * Change "table info" output to reflect long algorithm config lines. --- sbin/ipfw/ipfw2.h | 1 + sbin/ipfw/main.c | 2 + sbin/ipfw/tables.c | 60 +++++++++++++++++++++++++++-- sys/netinet/ip_fw.h | 10 +++++ sys/netpfil/ipfw/ip_fw_sockopt.c | 3 ++ sys/netpfil/ipfw/ip_fw_table.c | 55 ++++++++++++++++++++++++++ sys/netpfil/ipfw/ip_fw_table.h | 4 ++ sys/netpfil/ipfw/ip_fw_table_algo.c | 3 ++ 8 files changed, 135 insertions(+), 3 deletions(-) diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 51a31186916d..cabc12cf8e33 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -297,6 +297,7 @@ void ipfw_flush(int force); void ipfw_zero(int ac, char *av[], int optname); void ipfw_list(int ac, char *av[], int show_counters); void ipfw_list_tifaces(void); +void ipfw_list_ta(int ac, char *av[]); #ifdef PF /* altq.c */ diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c index 4dbe7b7b64dd..476036031d0a 100644 --- a/sbin/ipfw/main.c +++ b/sbin/ipfw/main.c @@ -440,6 +440,8 @@ ipfw_main(int oldac, char **oldav) ipfw_table_handler(ac, av); else if (_substrcmp(*av, "iflist") == 0) ipfw_list_tifaces(); + else if (_substrcmp(*av, "talist") == 0) + ipfw_list_ta(ac, av); else errx(EX_USAGE, "bad command `%s'", *av); } diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index bd46dc317bd9..ddb6e48964a0 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -146,6 +146,7 @@ ipfw_table_handler(int ac, char *av[]) set = 0; ac--; av++; + NEED1("table needs name"); tablename = *av; if (table_check_name(tablename) == 0) { @@ -158,11 +159,11 @@ ipfw_table_handler(int ac, char *av[]) errx(EX_USAGE, "table name %s is invalid", tablename); } ac--; av++; + NEED1("table needs command"); if ((tcmd = match_token(tablecmds, *av)) == -1) errx(EX_USAGE, "invalid table command %s", *av); - NEED1("table needs command"); switch (tcmd) { case TOK_LIST: case TOK_INFO: @@ -416,8 +417,8 @@ table_show_info(ipfw_xtable_info *i, void *arg) vtype = "unknown"; printf(" type: %s, kindex: %d\n", ttype, i->kidx); - printf(" valtype: %s, algorithm: %s\n", vtype, i->algoname); - printf(" references: %u\n", i->refcnt); + printf(" valtype: %s, references: %u\n", vtype, i->refcnt); + printf(" algorithm: %s\n", i->algoname); printf(" items: %u, size: %u\n", i->count, i->size); return (0); @@ -901,6 +902,59 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) } } +static int +table_do_get_algolist(ipfw_obj_lheader **polh) +{ + ipfw_obj_lheader req, *olh; + size_t sz; + int error; + + memset(&req, 0, sizeof(req)); + sz = sizeof(req); + + error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); + if (error != 0 && error != ENOMEM) + return (error); + + sz = req.size; + if ((olh = calloc(1, sz)) == NULL) + return (ENOMEM); + + olh->size = sz; + if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { + free(olh); + return (error); + } + + *polh = olh; + return (0); +} + +void +ipfw_list_ta(int ac, char *av[]) +{ + ipfw_obj_lheader *olh; + ipfw_ta_info *info; + int error, i; + const char *atype; + + error = table_do_get_algolist(&olh); + if (error != 0) + err(EX_OSERR, "Unable to request algorithm list"); + + info = (ipfw_ta_info *)(olh + 1); + for (i = 0; i < olh->count; i++) { + if ((atype = match_value(tabletypes, info->type)) == NULL) + atype = "unknown"; + + printf("%s type: %s references: %u\n", info->algoname, + atype, info->refcnt); + info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); + } + + free(olh); +} + int compare_ntlv(const void *_a, const void *_b) { diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index d25b48828407..068ec40968ac 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -89,6 +89,7 @@ typedef struct _ip_fw3_opheader { #define IP_FW_XADD 98 /* add entry */ #define IP_FW_TABLE_XFIND 99 /* finds an entry */ #define IP_FW_XIFLIST 100 /* list tracked interfaces */ +#define IP_FW_TABLES_ALIST 101 /* list table algorithms */ /* * Usage guidelines: @@ -799,6 +800,15 @@ typedef struct _ipfw_iface_info { } ipfw_iface_info; #define IPFW_IFFLAG_RESOLVED 0x01 /* Interface exists */ +typedef struct _ipfw_ta_info { + char algoname[32]; /* algorithm name */ + uint32_t type; /* lookup type */ + uint32_t flags; + uint32_t refcnt; + uint32_t spare0; + uint64_t spare1; +} ipfw_ta_info; + #define IPFW_OBJTYPE_TABLE 1 typedef struct _ipfw_obj_header { ip_fw3_opheader opheader; /* IP_FW3 opcode */ diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 17b6f5bc24e1..06578a64ec50 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -2001,6 +2001,9 @@ ipfw_ctl(struct sockopt *sopt) case IP_FW_TABLE_XFIND: /* IP_FW3 */ error = ipfw_find_table_entry(chain, op3, &sdata); break; + case IP_FW_TABLES_ALIST: /* IP_FW3 */ + error = ipfw_list_table_algo(chain, &sdata); + break; /*--- LEGACY API ---*/ case IP_FW_TABLE_ADD: diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index 0b382b4b9a01..9ed9ed2a08eb 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -1641,6 +1641,59 @@ ipfw_del_table_algo(struct ip_fw_chain *ch, int idx) free(ta, M_IPFW); } +/* + * Lists all table algorithms currently available. + * Data layout (v0)(current): + * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size + * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ] + * + * Returns 0 on success + */ +int +ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd) +{ + struct _ipfw_obj_lheader *olh; + struct tables_config *tcfg; + ipfw_ta_info *i; + struct table_algo *ta; + uint32_t count, n, size; + + olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); + if (olh == NULL) + return (EINVAL); + if (sd->valsize < olh->size) + return (EINVAL); + + IPFW_UH_RLOCK(ch); + tcfg = CHAIN_TO_TCFG(ch); + count = tcfg->algo_count; + size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader); + + /* Fill in header regadless of buffer size */ + olh->count = count; + olh->objsize = sizeof(ipfw_ta_info); + + if (size > olh->size) { + olh->size = size; + IPFW_UH_RUNLOCK(ch); + return (ENOMEM); + } + olh->size = size; + + for (n = 1; n <= count; n++) { + i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i)); + KASSERT(i != 0, ("previously checked buffer is not enough")); + ta = tcfg->algo[n]; + strlcpy(i->algoname, ta->name, sizeof(i->algoname)); + i->type = ta->type; + i->refcnt = ta->refcnt; + } + + IPFW_UH_RUNLOCK(ch); + + return (0); +} + /* * Tables rewriting code @@ -1925,6 +1978,7 @@ link_table(struct ip_fw_chain *ch, struct table_config *tc) tc->ta->change_ti(tc->astate, ti); tc->linked = 1; + tc->ta->refcnt++; } /* @@ -1949,6 +2003,7 @@ unlink_table(struct ip_fw_chain *ch, struct table_config *tc) ti = KIDX_TO_TI(ch, kidx); memset(ti, 0, sizeof(struct table_info)); tc->linked = 0; + tc->ta->refcnt--; /* Notify algo on real @ti address */ if (tc->ta->change_ti != NULL) diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h index 079aac50aa1d..37e724b05aca 100644 --- a/sys/netpfil/ipfw/ip_fw_table.h +++ b/sys/netpfil/ipfw/ip_fw_table.h @@ -98,6 +98,9 @@ typedef int ta_find_tentry(void *ta_state, struct table_info *ti, void *key, struct table_algo { char name[16]; int idx; + int type; + int refcnt; + int spare; ta_init *init; ta_destroy *destroy; ta_prepare_add *prepare_add; @@ -140,6 +143,7 @@ int ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); int ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); +int ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd); /* Exported to support legacy opcodes */ int add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, struct tentry_info *tei); diff --git a/sys/netpfil/ipfw/ip_fw_table_algo.c b/sys/netpfil/ipfw/ip_fw_table_algo.c index 9b7c2b6ee849..4f412654d7a3 100644 --- a/sys/netpfil/ipfw/ip_fw_table_algo.c +++ b/sys/netpfil/ipfw/ip_fw_table_algo.c @@ -516,6 +516,7 @@ ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei, struct table_algo cidr_radix = { .name = "cidr:radix", + .type = IPFW_TABLE_CIDR, .init = ta_init_radix, .destroy = ta_destroy_radix, .prepare_add = ta_prepare_add_cidr, @@ -1194,6 +1195,7 @@ ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, struct table_algo cidr_hash = { .name = "cidr:hash", + .type = IPFW_TABLE_CIDR, .init = ta_init_chash, .destroy = ta_destroy_chash, .prepare_add = ta_prepare_add_chash, @@ -1846,6 +1848,7 @@ ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, struct table_algo iface_idx = { .name = "iface:array", + .type = IPFW_TABLE_INTERFACE, .init = ta_init_ifidx, .destroy = ta_destroy_ifidx, .prepare_add = ta_prepare_add_ifidx,