Date: Sun, 6 Jul 2014 18:16:05 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r268329 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw Message-ID: <201407061816.s66IG5xg037994@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: melifaro Date: Sun Jul 6 18:16:04 2014 New Revision: 268329 URL: http://svnweb.freebsd.org/changeset/base/268329 Log: * Add "lookup" table functionality to permit userland entry lookups. * Bump table dump format preserving old ABI. Kernel size: * Add IP_FW_TABLE_XFIND to handle "lookup" request from userland. * Add ta_find_tentry() algorithm callbacks/handlers to support lookups. * Fully switch to ipfw_obj_tentry for various table dumps: algorithms are now required to support the latest (ipfw_obj_tentry) entry dump format, the rest is handled by generic dump code. IP_FW_TABLE_XLIST opcode version bumped (0 -> 1). * Eliminate legacy ta_dump_entry algo handler: dump_table_entry() converts data from current to legacy format. Userland side: * Add "lookup" table parameter. * Change the way table type is guessed: call table_get_info() first, and check value for IPv4/IPv6 type IFF table does not exist. * Fix table_get_list(): do more tries if supplied buffer is not enough. * Sparate table_show_entry() from table_show_list(). Modified: projects/ipfw/sbin/ipfw/tables.c projects/ipfw/sys/netinet/ip_fw.h projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Modified: projects/ipfw/sbin/ipfw/tables.c ============================================================================== --- projects/ipfw/sbin/ipfw/tables.c Sun Jul 6 17:57:59 2014 (r268328) +++ projects/ipfw/sbin/ipfw/tables.c Sun Jul 6 18:16:04 2014 (r268329) @@ -55,6 +55,7 @@ static int table_flush(ipfw_obj_header * static int table_destroy(ipfw_obj_header *oh); static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); static void table_create(ipfw_obj_header *oh, int ac, char *av[]); +static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); static int table_show_info(ipfw_xtable_info *i, void *arg); static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, @@ -64,9 +65,10 @@ static int table_flush_one(ipfw_xtable_i static int table_show_one(ipfw_xtable_info *i, void *arg); static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh); static void table_show_list(ipfw_obj_header *oh, int need_header); +static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, - char *key, uint8_t *ptype, uint8_t *pvtype); + char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, uint8_t type, uint8_t vtype); @@ -99,6 +101,7 @@ static struct _s_x tablecmds[] = { { "flush", TOK_FLUSH }, { "info", TOK_INFO }, { "list", TOK_LIST }, + { "lookup", TOK_LOOKUP }, { NULL, 0 } }; @@ -147,7 +150,6 @@ ipfw_table_handler(int ac, char *av[]) if (table_check_name(tablename) == 0) { table_fill_ntlv(&oh.ntlv, *av, set, 1); - //oh->set = set; oh.idx = 1; } else { if (strcmp(tablename, "all") == 0) @@ -220,6 +222,10 @@ ipfw_table_handler(int ac, char *av[]) err(EX_OSERR, "failed to request tables list"); } break; + case TOK_LOOKUP: + ac--; av++; + table_lookup(&oh, ac, av); + break; } } @@ -238,9 +244,8 @@ static void table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) { - oh->set = i->set; oh->idx = 1; - table_fill_ntlv(&oh->ntlv, i->tablename, oh->set, 1); + table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); } static struct _s_x tablenewcmds[] = { @@ -284,7 +289,6 @@ table_create(ipfw_obj_header *oh, int ac NEED1("table type required"); val = match_token(tabletypes, *av); if (val != -1) { - printf("av %s type %d\n", *av, xi.type); xi.type = val; ac--; av++; break; @@ -429,12 +433,17 @@ static int table_show_one(ipfw_xtable_info *i, void *arg) { ipfw_obj_header *oh; + int error; if ((oh = calloc(1, i->size)) == NULL) return (ENOMEM); - if (table_get_list(i, oh) == 0) - table_show_list(oh, 1); + if ((error = table_get_list(i, oh)) != 0) { + err(EX_OSERR, "Error requesting table %s list", i->tablename); + return (error); + } + + table_show_list(oh, 1); free(oh); return (0); @@ -467,7 +476,7 @@ table_do_modify_record(int cmd, ipfw_obj memcpy(oh + 1, tent, sizeof(*tent)); tent = (ipfw_obj_tentry *)(oh + 1); if (update != 0) - tent->flags |= IPFW_TF_UPDATE; + tent->head.flags |= IPFW_TF_UPDATE; tent->head.length = sizeof(ipfw_obj_tentry); error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); @@ -479,6 +488,7 @@ static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) { ipfw_obj_tentry tent; + ipfw_xtable_info xi; uint8_t type, vtype; int cmd; char *texterr; @@ -490,7 +500,7 @@ table_modify_record(ipfw_obj_header *oh, tent.head.length = sizeof(tent); tent.idx = 1; - tentry_fill_key(oh, &tent, *av, &type, &vtype); + tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); oh->ntlv.type = type; ac--; av++; @@ -508,6 +518,67 @@ table_modify_record(ipfw_obj_header *oh, err(EX_OSERR, "%s", texterr); } +static int +table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, + ipfw_obj_tentry *xtent) +{ + char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; + ipfw_obj_tentry *tent; + uint8_t type, vtype; + int error; + size_t sz; + + memcpy(xbuf, oh, sizeof(*oh)); + oh = (ipfw_obj_header *)xbuf; + tent = (ipfw_obj_tentry *)(oh + 1); + + memset(tent, 0, sizeof(*tent)); + tent->head.length = sizeof(*tent); + tent->idx = 1; + + tentry_fill_key(oh, tent, key, &type, &vtype, xi); + oh->ntlv.type = type; + + sz = sizeof(xbuf); + if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) + return (error); + + if (sz < sizeof(xbuf)) + return (EINVAL); + + *xtent = *tent; + + return (0); +} + +static void +table_lookup(ipfw_obj_header *oh, int ac, char *av[]) +{ + ipfw_obj_tentry xtent; + ipfw_xtable_info xi; + int error; + + if (ac == 0) + errx(EX_USAGE, "address required"); + + error = table_do_lookup(oh, *av, &xi, &xtent); + + switch (error) { + case 0: + break; + case ESRCH: + errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); + case ENOENT: + errx(EX_UNAVAILABLE, "Entry %s not found", *av); + case ENOTSUP: + errx(EX_UNAVAILABLE, "Table %s algo does not support " + "\"lookup\" method", oh->ntlv.name); + default: + err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); + } + + table_show_entry(&xi, &xtent); +} static void tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type) @@ -584,39 +655,43 @@ tentry_fill_key_type(char *arg, ipfw_obj static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, - uint8_t *ptype, uint8_t *pvtype) + uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) { - ipfw_xtable_info xi; uint8_t type, vtype; int error; type = 0; vtype = 0; - /* - * Compability layer. Try to interpret data as CIDR first. - */ - if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || - inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { - /* OK Prepare and send */ - type = IPFW_TABLE_CIDR; - } else { + error = table_get_info(oh, xi); + if (error == 0) { + /* Table found. */ + type = xi->type; + vtype = xi->vtype; + } else { + if (error != ESRCH) + errx(EX_OSERR, "Error requesting table %s info", + oh->ntlv.name); /* - * Non-CIDR of FQDN hostname. Ask kernel - * about given table. + * Table does not exist. + * Compability layer: try to interpret data as CIDR + * before failing. */ - error = table_get_info(oh, &xi); - if (error == ESRCH) - errx(EX_USAGE, "Table %s does not exist, cannot intuit " + if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || + inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { + /* OK Prepare and send */ + type = IPFW_TABLE_CIDR; + /* + * XXX: Value type is forced to be u32. + * This should be changed for MFC. + */ + vtype = IPFW_VTYPE_U32; + } else { + /* Inknown key */ + errx(EX_USAGE, "Table %s does not exist, cannot guess " "key type", oh->ntlv.name); - else if (error != 0) - errx(EX_OSERR, "Error requesting table %s info", - oh->ntlv.name); - - /* Table found. */ - type = xi.type; - vtype = xi.vtype; + } } tentry_fill_key_type(key, tent, type); @@ -629,29 +704,9 @@ static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, uint8_t type, uint8_t vtype) { - ipfw_xtable_info xi; - int error; int code; char *p; - if (vtype == 0) { - /* Format type is unknown, ask kernel */ - error = table_get_info(oh, &xi); - if (error == ESRCH) { - - /* - * XXX: This one may break some scripts. - * Change this behavior for MFC. - */ - errx(EX_USAGE, "Table %s does not exist. Unable to " - "guess value format.", oh->ntlv.name); - } else if (error != 0) - errx(EX_OSERR, "Error requesting table %s info", - oh->ntlv.name); - - vtype = xi.vtype; - } - switch (vtype) { case IPFW_VTYPE_U32: tent->value = strtoul(arg, &p, 0); @@ -758,17 +813,22 @@ static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) { size_t sz; - int error; + int error, c; - table_fill_objheader(oh, i); - sz = i->size; + sz = 0; + for (c = 0; c < 3; c++) { + table_fill_objheader(oh, i); + if (sz < i->size) + sz = i->size; - oh->opheader.version = 1; /* Current version */ + oh->opheader.version = 1; /* Current version */ + error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); - if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0) - return (errno); + if (error != ENOMEM) + return (errno); + } - return (0); + return (ENOMEM); } /* @@ -777,56 +837,52 @@ table_get_list(ipfw_xtable_info *i, ipfw static void table_show_list(ipfw_obj_header *oh, int need_header) { - ipfw_table_xentry *xent; - uint32_t count, tval; - char tbuf[128]; - struct in6_addr *addr6; + ipfw_obj_tentry *tent; + uint32_t count; ipfw_xtable_info *i; i = (ipfw_xtable_info *)(oh + 1); - xent = (ipfw_table_xentry *)(i + 1); + tent = (ipfw_obj_tentry *)(i + 1); if (need_header) printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); count = i->count; while (count > 0) { - switch (i->type) { - case IPFW_TABLE_CIDR: - /* IPv4 or IPv6 prefixes */ - tval = xent->value; - addr6 = &xent->k.addr6; + table_show_entry(i, tent); + tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); + count--; + } +} +static void +table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) +{ + char tbuf[128]; + uint32_t tval; - if ((xent->flags & IPFW_TCF_INET) != 0) { - /* IPv4 address */ - inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, - sizeof(tbuf)); - } else { - /* IPv6 address */ - inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf)); - } + tval = tent->value; - if (co.do_value_as_ip) { - tval = htonl(tval); - printf("%s/%u %s\n", tbuf, xent->masklen, - inet_ntoa(*(struct in_addr *)&tval)); - } else - printf("%s/%u %u\n", tbuf, xent->masklen, tval); - break; - case IPFW_TABLE_INTERFACE: - /* Interface names */ - tval = xent->value; - if (co.do_value_as_ip) { - tval = htonl(tval); - printf("%s %s\n", xent->k.iface, - inet_ntoa(*(struct in_addr *)&tval)); - } else - printf("%s %u\n", xent->k.iface, tval); - } + switch (i->type) { + case IPFW_TABLE_CIDR: + /* IPv4 or IPv6 prefixes */ + inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); - xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len); - count--; + if (co.do_value_as_ip) { + tval = htonl(tval); + printf("%s/%u %s\n", tbuf, tent->masklen, + inet_ntoa(*(struct in_addr *)&tval)); + } else + printf("%s/%u %u\n", tbuf, tent->masklen, tval); + break; + case IPFW_TABLE_INTERFACE: + /* Interface names */ + if (co.do_value_as_ip) { + tval = htonl(tval); + printf("%s %s\n", tent->k.iface, + inet_ntoa(*(struct in_addr *)&tval)); + } else + printf("%s %u\n", tent->k.iface, tval); } } Modified: projects/ipfw/sys/netinet/ip_fw.h ============================================================================== --- projects/ipfw/sys/netinet/ip_fw.h Sun Jul 6 17:57:59 2014 (r268328) +++ projects/ipfw/sys/netinet/ip_fw.h Sun Jul 6 18:16:04 2014 (r268329) @@ -89,6 +89,7 @@ typedef struct _ip_fw3_opheader { //#define IP_FW_TABLE_XMODIFY 96 /* modify existing table */ #define IP_FW_XGET 97 /* Retrieve configuration */ #define IP_FW_XADD 98 /* add entry */ +#define IP_FW_TABLE_XFIND 99 /* finds an entry */ /* * Usage guidelines: @@ -713,10 +714,8 @@ typedef struct _ipfw_obj_tentry { uint8_t subtype; /* subtype (IPv4,IPv6) */ uint8_t masklen; /* mask length */ uint16_t idx; /* Table name index */ - uint16_t flags; /* Entry flags */ - uint16_t spare0; - uint32_t spare1; uint32_t value; /* value */ + uint64_t spare; union { /* Longest field needs to be aligned by 8-byte boundary */ struct in_addr addr; /* IPv4 address */ @@ -751,7 +750,7 @@ typedef struct _ipfw_xtable_info { #define IPFW_OBJTYPE_TABLE 1 typedef struct _ipfw_obj_header { ip_fw3_opheader opheader; /* IP_FW3 opcode */ - uint32_t set; /* Set we're operating */ + uint32_t spare; uint16_t idx; /* object name index */ uint8_t objtype; /* object type */ uint8_t objsubtype; /* object subtype */ Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sun Jul 6 17:57:59 2014 (r268328) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sun Jul 6 18:16:04 2014 (r268329) @@ -1726,6 +1726,9 @@ ipfw_ctl(struct sockopt *sopt) case IP_FW_TABLE_XDEL: /* IP_FW3 */ error = ipfw_modify_table(chain, op3, &sdata); break; + case IP_FW_TABLE_XFIND: /* IP_FW3 */ + error = ipfw_find_table_entry(chain, op3, &sdata); + break; /*--- LEGACY API ---*/ case IP_FW_TABLE_ADD: Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sun Jul 6 17:57:59 2014 (r268328) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sun Jul 6 18:16:04 2014 (r268329) @@ -105,6 +105,7 @@ static int export_tables(struct ip_fw_ch struct sockopt_data *sd); static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, ipfw_xtable_info *i); +static int dump_table_tentry(void *e, void *arg); static int dump_table_xentry(void *e, void *arg); static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); @@ -406,19 +407,18 @@ ipfw_modify_table_v1(struct ip_fw_chain tent->head.length + read > sd->valsize) return (EINVAL); + /* Convert data into kernel request objects */ memset(&tei, 0, sizeof(tei)); tei.paddr = &tent->k; tei.subtype = tent->subtype; tei.masklen = tent->masklen; - if (tent->flags & IPFW_TF_UPDATE) + if (tent->head.flags & IPFW_TF_UPDATE) tei.flags |= TEI_FLAGS_UPDATE; tei.value = tent->value; - memset(&ti, 0, sizeof(ti)); - ti.uidx = tent->idx; + objheader_to_ti(oh, &ti); ti.type = oh->ntlv.type; - ti.tlvs = &oh->ntlv; - ti.tlen = oh->ntlv.head.length; + ti.uidx = tent->idx; error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ? add_table_entry(ch, &ti, &tei) : @@ -427,6 +427,101 @@ ipfw_modify_table_v1(struct ip_fw_chain return (error); } +/* + * Looks up an entry in given table. + * Data layout (v0)(current): + * Request: [ ipfw_obj_header ipfw_obj_tentry ] + * Reply: [ ipfw_obj_header ipfw_obj_tentry ] + * + * Returns 0 on success + */ +int +ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + ipfw_obj_tentry *tent; + ipfw_obj_header *oh; + struct tid_info ti; + struct table_config *tc; + struct table_algo *ta; + struct table_info *kti; + struct namedobj_instance *ni; + int error, plen; + void *paddr; + size_t sz; + + /* Check minimum header size */ + sz = sizeof(*oh) + sizeof(*tent); + if (sd->valsize != sz) + return (EINVAL); + + oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); + tent = (ipfw_obj_tentry *)(oh + 1); + + /* Basic length checks for TLVs */ + if (oh->ntlv.head.length != sizeof(oh->ntlv)) + return (EINVAL); + + objheader_to_ti(oh, &ti); + ti.type = oh->ntlv.type; + ti.uidx = tent->idx; + + IPFW_UH_RLOCK(ch); + ni = CHAIN_TO_NI(ch); + + /* + * Find existing table and check its type . + */ + ta = NULL; + if ((tc = find_table(ni, &ti)) == NULL) { + IPFW_UH_RUNLOCK(ch); + return (ESRCH); + } + + /* check table type */ + if (tc->no.type != ti.type) { + IPFW_UH_RUNLOCK(ch); + return (EINVAL); + } + + /* Check lookup key for validness */ + plen = 0; + paddr = &tent->k; + switch (ti.type) + { + case IPFW_TABLE_CIDR: + if (tent->subtype == AF_INET) + plen = sizeof(struct in_addr); + else if (tent->subtype == AF_INET6) + plen = sizeof(struct in6_addr); + else { + IPFW_UH_RUNLOCK(ch); + return (EINVAL); + } + break; + case IPFW_TABLE_INTERFACE: + /* Check key first */ + plen = sizeof(tent->k.iface); + if (strnlen(tent->k.iface, plen) == plen) { + IPFW_UH_RUNLOCK(ch); + return (EINVAL); + } + + break; + default: + IPFW_UH_RUNLOCK(ch); + return (ENOTSUP); + } + kti = KIDX_TO_TI(ch, tc->no.kidx); + ta = tc->ta; + + error = ta->find_tentry(tc->astate, kti, paddr, plen, tent); + + IPFW_UH_RUNLOCK(ch); + + return (error); +} + int ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) @@ -807,8 +902,10 @@ struct dump_args { struct sockopt_data *sd; uint32_t cnt; uint16_t uidx; + int error; ipfw_table_entry *ent; uint32_t size; + ipfw_obj_tentry tent; }; int @@ -835,7 +932,7 @@ ipfw_dump_table(struct ip_fw_chain *ch, * Dumps all table data * Data layout (v1)(current): * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size - * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_table_xentry x N ] + * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ] * * Returns 0 on success */ @@ -866,7 +963,7 @@ ipfw_dump_table_v1(struct ip_fw_chain *c export_table_info(ch, tc, i); sz = tc->count; - if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) { + if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) { /* * Submitted buffer size is not enough. @@ -888,10 +985,10 @@ ipfw_dump_table_v1(struct ip_fw_chain *c ta = tc->ta; - ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); + ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); IPFW_UH_RUNLOCK(ch); - return (0); + return (da.error); } /* @@ -1045,7 +1142,7 @@ objheader_to_ti(struct _ipfw_obj_header { memset(ti, 0, sizeof(struct tid_info)); - ti->set = oh->set; + ti->set = oh->ntlv.set; ti->uidx = oh->idx; ti->tlvs = &oh->ntlv; ti->tlen = oh->ntlv.head.length; @@ -1088,7 +1185,7 @@ export_table_info(struct ip_fw_chain *ch i->kidx = tc->no.kidx; i->refcnt = tc->no.refcnt; i->count = tc->count; - i->size = tc->count * sizeof(ipfw_table_xentry); + i->size = tc->count * sizeof(ipfw_obj_tentry); i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); if (tc->ta->print_config != NULL) { @@ -1155,6 +1252,9 @@ export_tables(struct ip_fw_chain *ch, ip return (0); } +/* + * Legacy IP_FW_TABLE_GETSIZE handler + */ int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) { @@ -1167,6 +1267,9 @@ ipfw_count_table(struct ip_fw_chain *ch, } +/* + * Legacy IP_FW_TABLE_XGETSIZE handler + */ int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) { @@ -1189,6 +1292,7 @@ dump_table_entry(void *e, void *arg) struct table_config *tc; struct table_algo *ta; ipfw_table_entry *ent; + int error; da = (struct dump_args *)arg; @@ -1202,7 +1306,15 @@ dump_table_entry(void *e, void *arg) ent->tbl = da->uidx; da->cnt++; - return (ta->dump_entry(tc->astate, da->ti, e, ent)); + error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent); + if (error != 0) + return (error); + + ent->addr = da->tent.k.addr.s_addr; + ent->masklen = da->tent.masklen; + ent->value = da->tent.value; + + return (0); } /* @@ -1223,8 +1335,9 @@ ipfw_dump_table_legacy(struct ip_fw_chai ta = tc->ta; - if (ta->dump_entry == NULL) - return (0); /* Legacy dump support is not necessary */ + /* This dump format supports IPv4 only */ + if (tc->no.type != IPFW_TABLE_CIDR) + return (0); memset(&da, 0, sizeof(da)); da.ti = KIDX_TO_TI(ch, tc->no.kidx); @@ -1240,7 +1353,35 @@ ipfw_dump_table_legacy(struct ip_fw_chai } /* - * Dumps table entry in eXtended format (current). + * Dumps table entry in eXtended format (v1)(current). + */ +static int +dump_table_tentry(void *e, void *arg) +{ + struct dump_args *da; + struct table_config *tc; + struct table_algo *ta; + ipfw_obj_tentry *tent; + + da = (struct dump_args *)arg; + + tc = da->tc; + ta = tc->ta; + + tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent)); + /* Out of memory, returning */ + if (tent == NULL) { + da->error = ENOMEM; + return (1); + } + tent->head.length = sizeof(ipfw_obj_tentry); + tent->idx = da->uidx; + + return (ta->dump_tentry(tc->astate, da->ti, e, tent)); +} + +/* + * Dumps table entry in eXtended format (v0). */ static int dump_table_xentry(void *e, void *arg) @@ -1249,6 +1390,8 @@ dump_table_xentry(void *e, void *arg) struct table_config *tc; struct table_algo *ta; ipfw_table_xentry *xent; + ipfw_obj_tentry *tent; + int error; da = (struct dump_args *)arg; @@ -1262,7 +1405,23 @@ dump_table_xentry(void *e, void *arg) xent->len = sizeof(ipfw_table_xentry); xent->tbl = da->uidx; - return (ta->dump_xentry(tc->astate, da->ti, e, xent)); + memset(&da->tent, 0, sizeof(da->tent)); + tent = &da->tent; + error = ta->dump_tentry(tc->astate, da->ti, e, tent); + if (error != 0) + return (error); + + /* Convert current format to previous one */ + xent->masklen = tent->masklen; + xent->value = tent->value; + /* Apply some hacks */ + if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) { + xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; + xent->flags = IPFW_TCF_INET; + } else + memcpy(&xent->k, &tent->k, sizeof(xent->k)); + + return (0); } /* Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Sun Jul 6 17:57:59 2014 (r268328) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Sun Jul 6 18:16:04 2014 (r268329) @@ -77,10 +77,10 @@ typedef void (ta_print_config)(void *ta_ typedef int ta_foreach_f(void *node, void *arg); typedef void ta_foreach(void *ta_state, struct table_info *ti, ta_foreach_f *f, void *arg); -typedef int ta_dump_entry(void *ta_state, struct table_info *ti, void *e, - ipfw_table_entry *ent); -typedef int ta_dump_xentry(void *ta_state, struct table_info *ti, void *e, - ipfw_table_xentry *xent); +typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e, + ipfw_obj_tentry *tent); +typedef int ta_find_tentry(void *ta_state, struct table_info *ti, void *key, + uint32_t keylen, ipfw_obj_tentry *tent); struct table_algo { char name[16]; @@ -94,9 +94,9 @@ struct table_algo { ta_del *del; ta_flush_entry *flush_entry; ta_foreach *foreach; - ta_dump_entry *dump_entry; - ta_dump_xentry *dump_xentry; + ta_dump_tentry *dump_tentry; ta_print_config *print_config; + ta_find_tentry *find_tentry; }; void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta); extern struct table_algo radix_cidr, radix_iface; @@ -112,6 +112,8 @@ int ipfw_dump_table(struct ip_fw_chain * struct sockopt_data *sd); int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd); +int ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, + struct sockopt_data *sd); int ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); int ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Sun Jul 6 17:57:59 2014 (r268328) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Sun Jul 6 18:16:04 2014 (r268329) @@ -208,30 +208,8 @@ ta_destroy_radix(void *ta_state, struct } static int -ta_dump_radix_entry(void *ta_state, struct table_info *ti, void *e, - ipfw_table_entry *ent) -{ - struct table_entry *n; - - n = (struct table_entry *)e; - - /* Guess IPv4/IPv6 radix by sockaddr family */ - if (n->addr.sin_family != AF_INET) - return (0); - - if (in_nullhost(n->mask.sin_addr)) - ent->masklen = 0; - else - ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); - ent->addr = n->addr.sin_addr.s_addr; - ent->value = n->value; - - return (0); -} - -static int -ta_dump_radix_xentry(void *ta_state, struct table_info *ti, void *e, - ipfw_table_xentry *xent) +ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, + ipfw_obj_tentry *tent) { struct table_entry *n; struct table_xentry *xn; @@ -245,28 +223,59 @@ ta_dump_radix_xentry(void *ta_state, str /* Guess IPv4/IPv6 radix by sockaddr family */ if (n->addr.sin_family == AF_INET) { if (in_nullhost(n->mask.sin_addr)) - xent->masklen = 0; + tent->masklen = 0; else - xent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr)); + tent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr)); /* Save IPv4 address as deprecated IPv6 compatible */ - xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr; - xent->flags = IPFW_TCF_INET; - xent->value = n->value; + tent->k.addr.s_addr = n->addr.sin_addr.s_addr; + tent->subtype = AF_INET; + tent->value = n->value; #ifdef INET6 } else { xn = (struct table_xentry *)e; /* Count IPv6 mask */ v = (uint32_t *)&xn->m.mask6.sin6_addr; for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++) - xent->masklen += bitcount32(*v); - memcpy(&xent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr)); - xent->value = xn->value; + tent->masklen += bitcount32(*v); + memcpy(&tent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr)); + tent->subtype = AF_INET6; + tent->value = xn->value; #endif } return (0); } +static int +ta_find_radix_tentry(void *ta_state, struct table_info *ti, void *key, + uint32_t keylen, ipfw_obj_tentry *tent) +{ + struct radix_node_head *rnh; + void *e; + + e = NULL; + if (keylen == sizeof(in_addr_t)) { + struct sockaddr_in sa; + KEY_LEN(sa) = KEY_LEN_INET; + sa.sin_addr.s_addr = *((in_addr_t *)key); + rnh = (struct radix_node_head *)ti->state; + e = rnh->rnh_matchaddr(&sa, rnh); + } else { + struct sockaddr_in6 sa6; + KEY_LEN(sa6) = KEY_LEN_INET6; + memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); + rnh = (struct radix_node_head *)ti->xstate; + e = rnh->rnh_matchaddr(&sa6, rnh); + } + + if (e != NULL) { + ta_dump_radix_tentry(ta_state, ti, e, tent); + return (0); + } + + return (ENOENT); +} + static void ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, void *arg) @@ -495,7 +504,7 @@ ta_del_cidr(void *ta_state, struct table tb->ent_ptr = rn; if (rn == NULL) - return (ESRCH); + return (ENOENT); return (0); } @@ -522,8 +531,8 @@ struct table_algo radix_cidr = { .del = ta_del_cidr, .flush_entry = ta_flush_cidr_entry, .foreach = ta_foreach_radix, - .dump_entry = ta_dump_radix_entry, - .dump_xentry = ta_dump_radix_xentry, + .dump_tentry = ta_dump_radix_tentry, + .find_tentry = ta_find_radix_tentry, }; @@ -724,7 +733,7 @@ ta_del_iface(void *ta_state, struct tabl tb->ent_ptr = rn; if (rn == NULL) - return (ESRCH); + return (ENOENT); return (0); } @@ -741,19 +750,42 @@ ta_flush_iface_entry(struct tentry_info } static int -ta_dump_iface_xentry(void *ta_state, struct table_info *ti, void *e, - ipfw_table_xentry *xent) +ta_dump_iface_tentry(void *ta_state, struct table_info *ti, void *e, + ipfw_obj_tentry *tent) { struct table_xentry *xn; xn = (struct table_xentry *)e; - xent->masklen = 8 * IF_NAMESIZE; - memcpy(&xent->k, &xn->a.iface.ifname, IF_NAMESIZE); - xent->value = xn->value; + tent->masklen = 8 * IF_NAMESIZE; + memcpy(&tent->k, &xn->a.iface.ifname, IF_NAMESIZE); + tent->value = xn->value; return (0); } +static int +ta_find_iface_tentry(void *ta_state, struct table_info *ti, void *key, + uint32_t keylen, ipfw_obj_tentry *tent) +{ + struct radix_node_head *rnh; + struct xaddr_iface iface; + void *e; + e = NULL; + + KEY_LEN(iface) = KEY_LEN_IFACE + + strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1; + + rnh = (struct radix_node_head *)ti->xstate; + e = rnh->rnh_matchaddr(&iface, rnh); + + if (e != NULL) { + ta_dump_iface_tentry(ta_state, ti, e, tent); + return (0); + } + + return (ENOENT); +} + static void ta_foreach_iface(void *ta_state, struct table_info *ti, ta_foreach_f *f, void *arg) @@ -775,7 +807,8 @@ struct table_algo radix_iface = { .del = ta_del_iface, .flush_entry = ta_flush_iface_entry, .foreach = ta_foreach_iface, - .dump_xentry = ta_dump_iface_xentry, + .dump_tentry = ta_dump_iface_tentry, + .find_tentry = ta_find_iface_tentry, }; void
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407061816.s66IG5xg037994>