diff options
-rw-r--r-- | sys/netpfil/ipfw/ip_fw2.c | 15 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_iface.c | 12 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_private.h | 33 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_sockopt.c | 377 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_table.c | 236 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_table.h | 29 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_table_value.c | 81 |
7 files changed, 458 insertions, 325 deletions
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index b11c10d..843bc41 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -2667,6 +2667,7 @@ ipfw_init(void) if (default_fw_tables > IPFW_TABLES_MAX) default_fw_tables = IPFW_TABLES_MAX; + ipfw_init_sopt_handler(); ipfw_log_bpf(1); /* init */ ipfw_iface_init(); return (error); @@ -2681,6 +2682,7 @@ ipfw_destroy(void) ipfw_iface_destroy(); ipfw_log_bpf(0); /* uninit */ + ipfw_destroy_sopt_handler(); printf("IP firewall unloaded\n"); } @@ -2691,12 +2693,14 @@ ipfw_destroy(void) static int vnet_ipfw_init(const void *unused) { - int error; + int error, first; struct ip_fw *rule = NULL; struct ip_fw_chain *chain; chain = &V_layer3_chain; + first = IS_DEFAULT_VNET(curvnet) ? 1 : 0; + /* First set up some values that are compile time options */ V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ V_fw_deny_unknown_exthdrs = 1; @@ -2718,7 +2722,7 @@ vnet_ipfw_init(const void *unused) /* Set initial number of tables */ V_fw_tables_max = default_fw_tables; - error = ipfw_init_tables(chain); + error = ipfw_init_tables(chain, first); if (error) { printf("ipfw2: setting up tables failed\n"); free(chain->map, M_IPFW); @@ -2771,7 +2775,7 @@ vnet_ipfw_uninit(const void *unused) { struct ip_fw *reap; struct ip_fw_chain *chain = &V_layer3_chain; - int i; + int i, last; V_ipfw_vnet_ready = 0; /* tell new callers to go away */ /* @@ -2781,6 +2785,9 @@ vnet_ipfw_uninit(const void *unused) */ (void)ipfw_attach_hooks(0 /* detach */); V_ip_fw_ctl_ptr = NULL; + + last = IS_DEFAULT_VNET(curvnet) ? 1 : 0; + IPFW_UH_WLOCK(chain); IPFW_UH_WUNLOCK(chain); IPFW_UH_WLOCK(chain); @@ -2797,7 +2804,7 @@ vnet_ipfw_uninit(const void *unused) ipfw_destroy_skipto_cache(chain); IPFW_WUNLOCK(chain); IPFW_UH_WUNLOCK(chain); - ipfw_destroy_tables(chain); + ipfw_destroy_tables(chain, last); if (reap != NULL) ipfw_reap_rules(reap); vnet_ipfw_iface_destroy(chain); diff --git a/sys/netpfil/ipfw/ip_fw_iface.c b/sys/netpfil/ipfw/ip_fw_iface.c index 8f38ae7..9fb5e10 100644 --- a/sys/netpfil/ipfw/ip_fw_iface.c +++ b/sys/netpfil/ipfw/ip_fw_iface.c @@ -65,6 +65,12 @@ static void handle_ifdetach(struct ip_fw_chain *ch, struct ipfw_iface *iif, uint16_t ifindex); static void handle_ifattach(struct ip_fw_chain *ch, struct ipfw_iface *iif, uint16_t ifindex); +static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, + struct sockopt_data *sd); + +static struct ipfw_sopt_handler scodes[] = { + { IP_FW_XIFLIST, 0, HDIR_GET, list_ifaces }, +}; /* * FreeBSD Kernel interface. @@ -200,6 +206,7 @@ ipfw_iface_init() { mtx_init(&vnet_mtx, "IPFW ifhandler mtx", NULL, MTX_DEF); + IPFW_ADD_SOPT_HANDLER(1, scodes); return (0); } @@ -211,6 +218,7 @@ void ipfw_iface_destroy() { + IPFW_DEL_SOPT_HANDLER(1, scodes); mtx_destroy(&vnet_mtx); } @@ -483,8 +491,8 @@ export_iface_internal(struct namedobj_instance *ii, struct named_object *no, * * Returns 0 on success */ -int -ipfw_list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct namedobj_instance *ii; diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h index 6879588..9a65b3f 100644 --- a/sys/netpfil/ipfw/ip_fw_private.h +++ b/sys/netpfil/ipfw/ip_fw_private.h @@ -520,8 +520,6 @@ int ipfw_iface_ref(struct ip_fw_chain *ch, char *name, void ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic); void ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic); void ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic); -int ipfw_list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd); /* In ip_fw_sockopt.c */ void ipfw_init_skipto_cache(struct ip_fw_chain *chain); @@ -537,8 +535,35 @@ void ipfw_destroy_counters(void); struct ip_fw *ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize); int ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt); +typedef int (sopt_handler_f)(struct ip_fw_chain *ch, + ip_fw3_opheader *op3, struct sockopt_data *sd); +struct ipfw_sopt_handler { + uint16_t opcode; + uint8_t version; + uint8_t dir; + sopt_handler_f *handler; + uint64_t refcnt; +}; +#define HDIR_SET 0x01 /* Handler is used to set some data */ +#define HDIR_GET 0x02 /* Handler is used to retrieve data */ +#define HDIR_BOTH HDIR_GET|HDIR_SET + +void ipfw_init_sopt_handler(void); +void ipfw_destroy_sopt_handler(void); +void ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count); +int ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count); caddr_t ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed); caddr_t ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed); +#define IPFW_ADD_SOPT_HANDLER(f, c) do { \ + if ((f) != 0) \ + ipfw_add_sopt_handler(c, \ + sizeof(c) / sizeof(c[0])); \ + } while(0) +#define IPFW_DEL_SOPT_HANDLER(l, c) do { \ + if ((l) != 0) \ + ipfw_del_sopt_handler(c, \ + sizeof(c) / sizeof(c[0])); \ + } while(0) typedef void (objhash_cb_t)(struct namedobj_instance *ni, struct named_object *, void *arg); @@ -580,10 +605,10 @@ int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint32_t *val); int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, void *paddr, uint32_t *val); -int ipfw_init_tables(struct ip_fw_chain *ch); +int ipfw_init_tables(struct ip_fw_chain *ch, int first); int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables); int ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int nsets); -void ipfw_destroy_tables(struct ip_fw_chain *ch); +void ipfw_destroy_tables(struct ip_fw_chain *ch, int last); /* In ip_fw_nat.c -- XXX to be moved to ip_var.h */ diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 33ce32b..051dc00 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -98,9 +98,47 @@ static uint32_t objhash_hash_name(struct namedobj_instance *ni, void *key, static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val); static int objhash_cmp_name(struct named_object *no, void *name, uint32_t set); +MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); + +static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd); +static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd); +static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd); +static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd); +static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd); +static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd); + +/* ctl3 handler data */ +struct mtx ctl3_lock; +#define CTL3_LOCK_INIT() mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF) +#define CTL3_LOCK_DESTROY() mtx_destroy(&ctl3_lock) +#define CTL3_LOCK() mtx_lock(&ctl3_lock) +#define CTL3_UNLOCK() mtx_unlock(&ctl3_lock) + +static struct ipfw_sopt_handler *ctl3_handlers; +static size_t ctl3_hsize; +static uint64_t ctl3_refct, ctl3_gencnt; +#define CTL3_SMALLBUF 4096 /* small page-size write buffer */ +#define CTL3_LARGEBUF 16 * 1024 * 1024 /* handle large rulesets */ + static int ipfw_flush_sopt_data(struct sockopt_data *sd); -MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); +static struct ipfw_sopt_handler scodes[] = { + { IP_FW_XGET, 0, HDIR_GET, dump_config }, + { IP_FW_XADD, 0, HDIR_BOTH, add_rules }, + { IP_FW_XDEL, 0, HDIR_BOTH, del_rules }, + { IP_FW_XZERO, 0, HDIR_SET, clear_rules }, + { IP_FW_XRESETLOG, 0, HDIR_SET, clear_rules }, + { IP_FW_XMOVE, 0, HDIR_SET, move_rules }, + { IP_FW_SET_SWAP, 0, HDIR_SET, manage_sets }, + { IP_FW_SET_MOVE, 0, HDIR_SET, manage_sets }, + { IP_FW_SET_ENABLE, 0, HDIR_SET, manage_sets }, +}; /* * static variables followed by global ones @@ -2027,11 +2065,6 @@ cleanup: return (error); } -#define IP_FW3_OPLENGTH(x) ((x)->sopt_valsize - sizeof(ip_fw3_opheader)) -#define IP_FW3_WRITEBUF 4096 /* small page-size write buffer */ -#define IP_FW3_READBUF 16 * 1024 * 1024 /* handle large rulesets */ - - static int check_object_name(ipfw_obj_ntlv *ntlv) { @@ -2085,9 +2118,6 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, struct rule_check_info rci, *ci, *cbuf; int i, rsize; - if (sd->valsize > IP_FW3_READBUF) - return (EINVAL); - op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize); ctlv = (ipfw_obj_ctlv *)(op3 + 1); @@ -2252,6 +2282,189 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, } /* + * Compares two sopt handlers (code, version and handler ptr). + * Used both as qsort() and bsearch(). + * Does not compare handler for latter case. + * + * Returns 0 if match is found. + */ +static int +compare_sh(const void *_a, const void *_b) +{ + struct ipfw_sopt_handler *a, *b; + + a = (struct ipfw_sopt_handler *)_a; + b = (struct ipfw_sopt_handler *)_b; + + if (a->opcode < b->opcode) + return (-1); + else if (a->opcode > b->opcode) + return (1); + + if (a->version < b->version) + return (-1); + else if (a->version > b->version) + return (1); + + /* bsearch helper */ + if (a->handler == NULL) + return (0); + + if ((uintptr_t)a->handler < (uintptr_t)b->handler) + return (-1); + else if ((uintptr_t)b->handler > (uintptr_t)b->handler) + return (1); + + return (0); +} + +/* + * Finds sopt handler based on @code and @version. + * + * Returns pointer to handler or NULL. + */ +static struct ipfw_sopt_handler * +find_sh(uint16_t code, uint8_t version, void *handler) +{ + struct ipfw_sopt_handler *sh, h; + + memset(&h, 0, sizeof(h)); + h.opcode = code; + h.version = version; + h.handler = handler; + + sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers, + ctl3_hsize, sizeof(h), compare_sh); + + return (sh); +} + +static int +find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh) +{ + struct ipfw_sopt_handler *sh; + + CTL3_LOCK(); + if ((sh = find_sh(opcode, version, NULL)) == NULL) { + CTL3_UNLOCK(); + printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n", + opcode, version); + return (EINVAL); + } + sh->refcnt++; + ctl3_refct++; + /* Copy handler data to requested buffer */ + *psh = *sh; + CTL3_UNLOCK(); + + return (0); +} + +static void +find_unref_sh(struct ipfw_sopt_handler *psh) +{ + struct ipfw_sopt_handler *sh; + + CTL3_LOCK(); + sh = find_sh(psh->opcode, psh->version, NULL); + KASSERT(sh != NULL, ("ctl3 handler disappeared")); + sh->refcnt--; + ctl3_refct--; + CTL3_UNLOCK(); +} + +void +ipfw_init_sopt_handler() +{ + + CTL3_LOCK_INIT(); + IPFW_ADD_SOPT_HANDLER(1, scodes); +} + +void +ipfw_destroy_sopt_handler() +{ + + IPFW_DEL_SOPT_HANDLER(1, scodes); + CTL3_LOCK_DESTROY(); +} + +/* + * Adds one or more sockopt handlers to the global array. + * Function may sleep. + */ +void +ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) +{ + size_t sz; + struct ipfw_sopt_handler *tmp; + + CTL3_LOCK(); + + for (;;) { + sz = ctl3_hsize + count; + CTL3_UNLOCK(); + tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO); + CTL3_LOCK(); + if (ctl3_hsize + count <= sz) + break; + + /* Retry */ + free(tmp, M_IPFW); + } + + /* Merge old & new arrays */ + sz = ctl3_hsize + count; + memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh)); + memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh)); + qsort(tmp, sz, sizeof(*sh), compare_sh); + /* Switch new and free old */ + if (ctl3_handlers != NULL) + free(ctl3_handlers, M_IPFW); + ctl3_handlers = tmp; + ctl3_hsize = sz; + ctl3_gencnt++; + + CTL3_UNLOCK(); +} + +/* + * Removes one or more sockopt handlers from the global array. + */ +int +ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) +{ + size_t sz; + struct ipfw_sopt_handler *tmp, *h; + int i; + + CTL3_LOCK(); + + for (i = 0; i < count; i++) { + tmp = &sh[i]; + h = find_sh(tmp->opcode, tmp->version, tmp->handler); + if (h == NULL) + continue; + + sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h); + memmove(h, h + 1, sz); + ctl3_hsize--; + } + + if (ctl3_hsize == 0) { + if (ctl3_handlers != NULL) + free(ctl3_handlers, M_IPFW); + ctl3_handlers = NULL; + } + + ctl3_gencnt++; + + CTL3_UNLOCK(); + + return (0); +} + +/* * Writes data accumulated in @sd to sockopt buffer. * Zeroes internal @sd buffer. */ @@ -2341,12 +2554,12 @@ ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed) int ipfw_ctl3(struct sockopt *sopt) { - int error, ctype; - size_t bsize_max, size, valsize; + int error; + size_t size, valsize; struct ip_fw_chain *chain; - uint32_t opt; char xbuf[256]; struct sockopt_data sdata; + struct ipfw_sopt_handler h; ip_fw3_opheader *op3 = NULL; error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); @@ -2367,52 +2580,55 @@ ipfw_ctl3(struct sockopt *sopt) error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3)); if (error != 0) return (error); - opt = op3->opcode; sopt->sopt_valsize = valsize; /* - * Determine opcode type/buffer size: - * use on-stack xbuf for short request, - * allocate sliding-window buf for data export or - * contigious buffer for special ops. + * Find and reference command. */ - ctype = (sopt->sopt_dir == SOPT_GET) ? SOPT_GET : SOPT_SET; - switch (opt) { - case IP_FW_XADD: - case IP_FW_XDEL: - case IP_FW_TABLE_XADD: - case IP_FW_TABLE_XDEL: - ctype = SOPT_SET; - bsize_max = IP_FW3_READBUF; - break; - default: - bsize_max = IP_FW3_WRITEBUF; - } + error = find_ref_sh(op3->opcode, op3->version, &h); + if (error != 0) + return (error); /* * Disallow modifications in really-really secure mode, but still allow * the logging counters to be reset. */ - if (ctype == SOPT_SET && opt != IP_FW_XRESETLOG) { + if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) { error = securelevel_ge(sopt->sopt_td->td_ucred, 3); - if (error != 0) + if (error != 0) { + find_unref_sh(&h); return (error); + } } /* * Fill in sockopt_data structure that may be useful for * IP_FW3 get requests. */ - if (valsize <= sizeof(xbuf)) { + /* use on-stack buffer */ sdata.kbuf = xbuf; sdata.ksize = sizeof(xbuf); sdata.kavail = valsize; } else { - if (valsize < bsize_max) + + /* + * Determine opcode type/buffer size: + * allocate sliding-window buf for data export or + * contigious buffer for special ops. + */ + if ((h.dir & HDIR_SET) != 0) { + /* Set request. Allocate contigous buffer. */ + if (valsize > CTL3_LARGEBUF) { + find_unref_sh(&h); + return (EFBIG); + } + size = valsize; - else - size = bsize_max; + } else { + /* Get request. Allocate sliding window buffer */ + size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF; + } sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); sdata.ksize = size; @@ -2433,95 +2649,10 @@ ipfw_ctl3(struct sockopt *sopt) sizeof(ip_fw3_opheader))) != 0) return (error); op3 = (ip_fw3_opheader *)sdata.kbuf; - opt = op3->opcode; - - switch (opt) { - case IP_FW_XGET: - error = dump_config(chain, op3, &sdata); - break; - - case IP_FW_XADD: - error = add_rules(chain, op3, &sdata); - break; - - case IP_FW_XDEL: - error = del_rules(chain, op3, &sdata); - break; - - case IP_FW_XZERO: - case IP_FW_XRESETLOG: - error = clear_rules(chain, op3, &sdata); - break; - - case IP_FW_XMOVE: - error = move_rules(chain, op3, &sdata); - break; - - case IP_FW_SET_SWAP: - case IP_FW_SET_MOVE: - case IP_FW_SET_ENABLE: - error = manage_sets(chain, op3, &sdata); - break; - - case IP_FW_XIFLIST: - error = ipfw_list_ifaces(chain, op3, &sdata); - break; - - /*--- TABLE opcodes ---*/ - case IP_FW_TABLE_XCREATE: - error = ipfw_create_table(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XDESTROY: - case IP_FW_TABLE_XFLUSH: - error = ipfw_flush_table(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XMODIFY: - error = ipfw_modify_table(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XINFO: - error = ipfw_describe_table(chain, op3, &sdata); - break; - - case IP_FW_TABLES_XLIST: - error = ipfw_list_tables(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XLIST: - error = ipfw_dump_table(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XADD: - case IP_FW_TABLE_XDEL: - error = ipfw_manage_table_ent(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XFIND: - error = ipfw_find_table_entry(chain, op3, &sdata); - break; - - case IP_FW_TABLE_XSWAP: - error = ipfw_swap_table(chain, op3, &sdata); - break; - - case IP_FW_TABLES_ALIST: - error = ipfw_list_table_algo(chain, op3, &sdata); - break; - - case IP_FW_TABLE_VLIST: - error = ipfw_list_table_values(chain, op3, &sdata); - break; - case IP_FW_TABLE_XGETSIZE: - error = ipfw_get_table_size(chain, op3, &sdata); - break; - - default: - printf("ipfw: ipfw_ctl3 invalid option %d\n", opt); - error = EINVAL; - } + /* Finally, run handler */ + error = h.handler(chain, op3, &sdata); + find_unref_sh(&h); /* Flush state and free buffers */ if (error == 0) diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index b670552..f2129d9 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -107,12 +107,6 @@ static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 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); -static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); -static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd); static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a, struct tid_info *b); @@ -887,30 +881,6 @@ check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts, } /* - * Selects appropriate table operation handler - * depending on opcode version. - */ -int -ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd) -{ - int error; - - switch (op3->version) { - case 0: - error = ipfw_manage_table_ent_v0(ch, op3, sd); - break; - case 1: - error = ipfw_manage_table_ent_v1(ch, op3, sd); - break; - default: - error = ENOTSUP; - } - - return (error); -} - -/* * Adds or deletes record in table. * Data layout (v0): * Request: [ ip_fw3_opheader ipfw_table_xentry ] @@ -918,7 +888,7 @@ ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * Returns 0 on success */ static int -ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { ipfw_table_xentry *xent; @@ -975,7 +945,7 @@ ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * Returns 0 on success */ static int -ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { ipfw_obj_tentry *tent, *ptent; @@ -1095,8 +1065,8 @@ ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * * Returns 0 on success */ -int -ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { ipfw_obj_tentry *tent; @@ -1163,8 +1133,8 @@ ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * * Returns 0 on success */ -int -ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +flush_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { int error; @@ -1323,8 +1293,8 @@ restart: * * Returns 0 on success */ -int -ipfw_swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { int error; @@ -1508,64 +1478,6 @@ destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) return (0); } -static void -destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, - void *arg) -{ - - unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); - if (ipfw_objhash_free_idx(ni, no->kidx) != 0) - printf("Error unlinking kidx %d from table %s\n", - no->kidx, no->name); - free_table_config(ni, (struct table_config *)no); -} - -/* - * Shuts tables module down. - */ -void -ipfw_destroy_tables(struct ip_fw_chain *ch) -{ - - /* Remove all tables from working set */ - IPFW_UH_WLOCK(ch); - IPFW_WLOCK(ch); - ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); - IPFW_WUNLOCK(ch); - IPFW_UH_WUNLOCK(ch); - - /* Free pointers itself */ - free(ch->tablestate, M_IPFW); - - ipfw_table_value_destroy(ch); - ipfw_table_algo_destroy(ch); - - ipfw_objhash_destroy(CHAIN_TO_NI(ch)); - free(CHAIN_TO_TCFG(ch), M_IPFW); -} - -/* - * Starts tables module. - */ -int -ipfw_init_tables(struct ip_fw_chain *ch) -{ - struct tables_config *tcfg; - - /* Allocate pointers */ - ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), - M_IPFW, M_WAITOK | M_ZERO); - - tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); - tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); - ch->tblcfg = tcfg; - - ipfw_table_value_init(ch); - ipfw_table_algo_init(ch); - - return (0); -} - /* * Grow tables index. * @@ -1753,8 +1665,8 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, * * Returns 0 on success */ -int -ipfw_list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct _ipfw_obj_lheader *olh; @@ -1781,8 +1693,8 @@ ipfw_list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * * Returns 0 on success. */ -int -ipfw_describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct _ipfw_obj_header *oh; @@ -1816,8 +1728,8 @@ ipfw_describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * * Returns 0 on success */ -int -ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct _ipfw_obj_header *oh; @@ -1873,8 +1785,8 @@ ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * * Returns 0 on success */ -int -ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct _ipfw_obj_header *oh; @@ -2243,26 +2155,6 @@ export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, return (0); } -int -ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd) -{ - int error; - - switch (op3->version) { - case 0: - error = ipfw_dump_table_v0(ch, sd); - break; - case 1: - error = ipfw_dump_table_v1(ch, sd); - break; - default: - error = ENOTSUP; - } - - return (error); -} - /* * Dumps all table data * Data layout (v1)(current): @@ -2272,7 +2164,8 @@ ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * Returns 0 on success */ static int -ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) +dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, + struct sockopt_data *sd) { struct _ipfw_obj_header *oh; ipfw_xtable_info *i; @@ -2335,7 +2228,8 @@ ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) * Returns 0 on success */ static int -ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) +dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, + struct sockopt_data *sd) { ipfw_xtable *xtbl; struct tid_info ti; @@ -2394,8 +2288,8 @@ ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) /* * Legacy function to retrieve number of items in table. */ -int -ipfw_get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { uint32_t *tbl; @@ -2800,8 +2694,8 @@ ipfw_del_table_algo(struct ip_fw_chain *ch, int idx) * * Returns 0 on success */ -int -ipfw_list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct _ipfw_obj_lheader *olh; @@ -3666,3 +3560,85 @@ free: return (error); } +static struct ipfw_sopt_handler scodes[] = { + { IP_FW_TABLE_XCREATE, 0, HDIR_SET, create_table }, + { IP_FW_TABLE_XDESTROY, 0, HDIR_SET, flush_table_v0 }, + { IP_FW_TABLE_XFLUSH, 0, HDIR_SET, flush_table_v0 }, + { IP_FW_TABLE_XMODIFY, 0, HDIR_BOTH, modify_table }, + { IP_FW_TABLE_XINFO, 0, HDIR_GET, describe_table }, + { IP_FW_TABLES_XLIST, 0, HDIR_GET, list_tables }, + { IP_FW_TABLE_XLIST, 0, HDIR_GET, dump_table_v0 }, + { IP_FW_TABLE_XLIST, 1, HDIR_GET, dump_table_v1 }, + { IP_FW_TABLE_XADD, 0, HDIR_BOTH, manage_table_ent_v0 }, + { IP_FW_TABLE_XADD, 1, HDIR_BOTH, manage_table_ent_v1 }, + { IP_FW_TABLE_XDEL, 0, HDIR_BOTH, manage_table_ent_v0 }, + { IP_FW_TABLE_XDEL, 1, HDIR_BOTH, manage_table_ent_v1 }, + { IP_FW_TABLE_XFIND, 0, HDIR_GET, find_table_entry }, + { IP_FW_TABLE_XSWAP, 0, HDIR_SET, swap_table }, + { IP_FW_TABLES_ALIST, 0, HDIR_GET, list_table_algo }, + { IP_FW_TABLE_XGETSIZE, 0, HDIR_GET, get_table_size }, +}; + +static void +destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, + void *arg) +{ + + unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); + if (ipfw_objhash_free_idx(ni, no->kidx) != 0) + printf("Error unlinking kidx %d from table %s\n", + no->kidx, no->name); + free_table_config(ni, (struct table_config *)no); +} + +/* + * Shuts tables module down. + */ +void +ipfw_destroy_tables(struct ip_fw_chain *ch, int last) +{ + + IPFW_DEL_SOPT_HANDLER(last, scodes); + + /* Remove all tables from working set */ + IPFW_UH_WLOCK(ch); + IPFW_WLOCK(ch); + ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); + IPFW_WUNLOCK(ch); + IPFW_UH_WUNLOCK(ch); + + /* Free pointers itself */ + free(ch->tablestate, M_IPFW); + + ipfw_table_value_destroy(ch, last); + ipfw_table_algo_destroy(ch); + + ipfw_objhash_destroy(CHAIN_TO_NI(ch)); + free(CHAIN_TO_TCFG(ch), M_IPFW); +} + +/* + * Starts tables module. + */ +int +ipfw_init_tables(struct ip_fw_chain *ch, int first) +{ + struct tables_config *tcfg; + + /* Allocate pointers */ + ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), + M_IPFW, M_WAITOK | M_ZERO); + + tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); + tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); + ch->tblcfg = tcfg; + + ipfw_table_value_init(ch, first); + ipfw_table_algo_init(ch); + + IPFW_ADD_SOPT_HANDLER(first, scodes); + return (0); +} + + + diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h index c8c1405..cefaaf2 100644 --- a/sys/netpfil/ipfw/ip_fw_table.h +++ b/sys/netpfil/ipfw/ip_fw_table.h @@ -161,29 +161,6 @@ void ipfw_del_table_algo(struct ip_fw_chain *ch, int idx); void ipfw_table_algo_init(struct ip_fw_chain *chain); void ipfw_table_algo_destroy(struct ip_fw_chain *chain); - -/* direct ipfw_ctl handlers */ -int ipfw_list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd); -int ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd); -int ipfw_describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - 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, - struct sockopt_data *sd); -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, ip_fw3_opheader *op3, - struct sockopt_data *sd); -int ipfw_swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - 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, uint8_t flags, uint32_t count); @@ -196,12 +173,10 @@ int ipfw_get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); /* ipfw_table_value.c functions */ -int ipfw_list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd); struct table_config; struct tableop_state; -void ipfw_table_value_init(struct ip_fw_chain *ch); -void ipfw_table_value_destroy(struct ip_fw_chain *ch); +void ipfw_table_value_init(struct ip_fw_chain *ch, int first); +void ipfw_table_value_destroy(struct ip_fw_chain *ch, int last); int ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts); void ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc, struct tentry_info *tei, uint32_t count, int rollback); diff --git a/sys/netpfil/ipfw/ip_fw_table_value.c b/sys/netpfil/ipfw/ip_fw_table_value.c index a8d4a31..cff8d76 100644 --- a/sys/netpfil/ipfw/ip_fw_table_value.c +++ b/sys/netpfil/ipfw/ip_fw_table_value.c @@ -60,6 +60,13 @@ static uint32_t hash_table_value(struct namedobj_instance *ni, void *key, uint32_t kopt); static int cmp_table_value(struct named_object *no, void *key, uint32_t kopt); +static int list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3, + struct sockopt_data *sd); + +static struct ipfw_sopt_handler scodes[] = { + { IP_FW_TABLE_VLIST, 0, HDIR_GET, list_table_values }, +}; + #define CHAIN_TO_VI(chain) (CHAIN_TO_TCFG(chain)->valhash) struct table_val_link @@ -77,39 +84,6 @@ struct vdump_args { }; -void -ipfw_table_value_init(struct ip_fw_chain *ch) -{ - struct tables_config *tcfg; - - ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value), - M_IPFW, M_WAITOK | M_ZERO); - - tcfg = ch->tblcfg; - - tcfg->val_size = VALDATA_START_SIZE; - tcfg->valhash = ipfw_objhash_create(tcfg->val_size); - ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value, - cmp_table_value); -} - -static void -destroy_value(struct namedobj_instance *ni, struct named_object *no, - void *arg) -{ - - free(no, M_IPFW); -} - -void -ipfw_table_value_destroy(struct ip_fw_chain *ch) -{ - - free(ch->valuestate, M_IPFW); - ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch); - ipfw_objhash_destroy(CHAIN_TO_VI(ch)); -} - static uint32_t hash_table_value(struct namedobj_instance *ni, void *key, uint32_t kopt) { @@ -734,8 +708,8 @@ dump_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg) * * Returns 0 on success */ -int -ipfw_list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +static int +list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { struct _ipfw_obj_lheader *olh; @@ -779,3 +753,40 @@ ipfw_list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3, return (0); } +void +ipfw_table_value_init(struct ip_fw_chain *ch, int first) +{ + struct tables_config *tcfg; + + ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value), + M_IPFW, M_WAITOK | M_ZERO); + + tcfg = ch->tblcfg; + + tcfg->val_size = VALDATA_START_SIZE; + tcfg->valhash = ipfw_objhash_create(tcfg->val_size); + ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value, + cmp_table_value); + + IPFW_ADD_SOPT_HANDLER(first, scodes); +} + +static void +destroy_value(struct namedobj_instance *ni, struct named_object *no, + void *arg) +{ + + free(no, M_IPFW); +} + +void +ipfw_table_value_destroy(struct ip_fw_chain *ch, int last) +{ + + IPFW_DEL_SOPT_HANDLER(last, scodes); + + free(ch->valuestate, M_IPFW); + ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch); + ipfw_objhash_destroy(CHAIN_TO_VI(ch)); +} + |