From 8963c5055d41e670a36c097a0f6b475e6c8aacda Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sun, 26 Apr 2015 10:53:35 +0000 Subject: [PATCH] Generalize object reference handling in ipfw rules. No ABI changes. --- sbin/ipfw/ipfw2.c | 125 ++++++++++++++++++++++++++++++++++++++++++--- sbin/ipfw/ipfw2.h | 2 - sbin/ipfw/tables.c | 67 ------------------------ 3 files changed, 118 insertions(+), 76 deletions(-) diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 9a0bd9e5d7df..687d707195e6 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -375,6 +375,13 @@ static int ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo, ipfw_cfg_lheader *cfg, size_t sz, int ac, char **av); static void ipfw_list_tifaces(void); +struct tidx; +static uint16_t pack_object(struct tidx *tstate, char *name, int otype); +static uint16_t pack_table(struct tidx *tstate, char *name); + +static char *table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx); +static void object_sort_ctlv(ipfw_obj_ctlv *ctlv); + /* * Simple string buffer API. * Used to simplify buffer passing between function and for @@ -2558,6 +2565,7 @@ ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo, if (cfg->flags & IPFW_CFG_GET_STATIC) { /* We've requested static rules */ if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { + object_sort_ctlv(ctlv); fo->tstate = ctlv; readsz += ctlv->head.length; ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + @@ -2724,19 +2732,18 @@ struct tidx { }; static uint16_t -pack_table(struct tidx *tstate, char *name) +pack_object(struct tidx *tstate, char *name, int otype) { int i; ipfw_obj_ntlv *ntlv; - if (table_check_name(name) != 0) - return (0); - for (i = 0; i < tstate->count; i++) { if (strcmp(tstate->idx[i].name, name) != 0) continue; if (tstate->idx[i].set != tstate->set) continue; + if (tstate->idx[i].head.type != otype) + continue; return (tstate->idx[i].idx); } @@ -2752,7 +2759,7 @@ pack_table(struct tidx *tstate, char *name) ntlv = &tstate->idx[i]; memset(ntlv, 0, sizeof(ipfw_obj_ntlv)); strlcpy(ntlv->name, name, sizeof(ntlv->name)); - ntlv->head.type = IPFW_TLV_TBL_NAME; + ntlv->head.type = otype; ntlv->head.length = sizeof(ipfw_obj_ntlv); ntlv->set = tstate->set; ntlv->idx = ++tstate->counter; @@ -2761,6 +2768,16 @@ pack_table(struct tidx *tstate, char *name) return (ntlv->idx); } +static uint16_t +pack_table(struct tidx *tstate, char *name) +{ + + if (table_check_name(name) != 0) + return (0); + + return (pack_object(tstate, name, IPFW_TLV_TBL_NAME)); +} + static void fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate) { @@ -3611,7 +3628,6 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) break; } else goto chkarg; - case TOK_QUEUE: action->opcode = O_QUEUE; goto chkarg; @@ -4656,6 +4672,101 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) *rbufsize = (char *)dst - (char *)rule; } +static int +compare_ntlv(const void *_a, const void *_b) +{ + ipfw_obj_ntlv *a, *b; + + a = (ipfw_obj_ntlv *)_a; + b = (ipfw_obj_ntlv *)_b; + + if (a->set < b->set) + return (-1); + else if (a->set > b->set) + return (1); + + if (a->idx < b->idx) + return (-1); + else if (a->idx > b->idx) + return (1); + + if (a->head.type < b->head.type) + return (-1); + else if (a->head.type > b->head.type) + return (1); + + return (0); +} + +/* + * Provide kernel with sorted list of referenced objects + */ +static void +object_sort_ctlv(ipfw_obj_ctlv *ctlv) +{ + + qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); +} + +struct object_kt { + uint16_t uidx; + uint16_t type; +}; +static int +compare_object_kntlv(const void *k, const void *v) +{ + ipfw_obj_ntlv *ntlv; + struct object_kt key; + + key = *((struct object_kt *)k); + ntlv = (ipfw_obj_ntlv *)v; + + if (key.uidx < ntlv->idx) + return (-1); + else if (key.uidx > ntlv->idx) + return (1); + + if (key.type < ntlv->head.type) + return (-1); + else if (key.type > ntlv->head.type) + return (1); + + return (0); +} + +/* + * Finds object name in @ctlv by @idx and @type. + * Uses the following facts: + * 1) All TLVs are the same size + * 2) Kernel implementation provides already sorted list. + * + * Returns table name or NULL. + */ +static char * +object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx, uint16_t type) +{ + ipfw_obj_ntlv *ntlv; + struct object_kt key; + + key.uidx = idx; + key.type = type; + + ntlv = bsearch(&key, (ctlv + 1), ctlv->count, ctlv->objsize, + compare_object_kntlv); + + if (ntlv != 0) + return (ntlv->name); + + return (NULL); +} + +static char * +table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) +{ + + return (object_search_ctlv(ctlv, idx, IPFW_TLV_TBL_NAME)); +} + /* * Adds one or more rules to ipfw chain. * Data layout: @@ -4724,7 +4835,7 @@ ipfw_add(char *av[]) ctlv->count = ts.count; ctlv->objsize = sizeof(ipfw_obj_ntlv); memcpy(ctlv + 1, ts.idx, tlen); - table_sort_ctlv(ctlv); + object_sort_ctlv(ctlv); tstate = ctlv; /* Rule next */ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 80970ef0deee..5a083216d53b 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -344,8 +344,6 @@ int fill_ext6hdr(struct _ipfw_insn *cmd, char *av); /* tables.c */ struct _ipfw_obj_ctlv; -char *table_search_ctlv(struct _ipfw_obj_ctlv *ctlv, uint16_t idx); -void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv); int table_check_name(char *tablename); void ipfw_list_ta(int ac, char *av[]); void ipfw_list_values(int ac, char *av[]); diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 4ea5b7b84fdb..08f47318e678 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -1936,73 +1936,6 @@ ipfw_list_values(int ac, char *av[]) free(olh); } -int -compare_ntlv(const void *_a, const void *_b) -{ - ipfw_obj_ntlv *a, *b; - - a = (ipfw_obj_ntlv *)_a; - b = (ipfw_obj_ntlv *)_b; - - if (a->set < b->set) - return (-1); - else if (a->set > b->set) - return (1); - - if (a->idx < b->idx) - return (-1); - else if (a->idx > b->idx) - return (1); - - return (0); -} - -int -compare_kntlv(const void *k, const void *v) -{ - ipfw_obj_ntlv *ntlv; - uint16_t key; - - key = *((uint16_t *)k); - ntlv = (ipfw_obj_ntlv *)v; - - if (key < ntlv->idx) - return (-1); - else if (key > ntlv->idx) - return (1); - - return (0); -} - -/* - * Finds table name in @ctlv by @idx. - * Uses the following facts: - * 1) All TLVs are the same size - * 2) Kernel implementation provides already sorted list. - * - * Returns table name or NULL. - */ -char * -table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) -{ - ipfw_obj_ntlv *ntlv; - - ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, - compare_kntlv); - - if (ntlv != 0) - return (ntlv->name); - - return (NULL); -} - -void -table_sort_ctlv(ipfw_obj_ctlv *ctlv) -{ - - qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); -} - int table_check_name(char *tablename) {