From owner-svn-src-projects@FreeBSD.ORG Sun Jun 15 13:40:29 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 39DAEA92; Sun, 15 Jun 2014 13:40:29 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 1D8112BD1; Sun, 15 Jun 2014 13:40:29 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s5FDeTmW048013; Sun, 15 Jun 2014 13:40:29 GMT (envelope-from melifaro@svn.freebsd.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s5FDeS9Q048004; Sun, 15 Jun 2014 13:40:28 GMT (envelope-from melifaro@svn.freebsd.org) Message-Id: <201406151340.s5FDeS9Q048004@svn.freebsd.org> From: "Alexander V. Chernikov" Date: Sun, 15 Jun 2014 13:40:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r267509 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Jun 2014 13:40:29 -0000 Author: melifaro Date: Sun Jun 15 13:40:27 2014 New Revision: 267509 URL: http://svnweb.freebsd.org/changeset/base/267509 Log: Simplify opcode handling. * Use one u16 from op3 header to implement opcode versioning. * IP_FW_TABLE_XLIST has now 2 handlers, for ver.0 (old) and ver.1 (current). * Every getsockopt request is now handled in ip_fw_table.c * Rename new opcodes: IP_FW_OBJ_DEL -> IP_FW_TABLE_XDESTROY IP_FW_OBJ_LISTSIZE -> IP_FW_TABLES_XGETSIZE IP_FW_OBJ_LIST -> IP_FW_TABLES_XLIST IP_FW_OBJ_INFO -> IP_FW_TABLE_XINFO IP_FW_OBJ_INFO -> IP_FW_TABLE_XFLUSH * Add some docs about using given opcodes. * Group some legacy opcode/handlers. Modified: projects/ipfw/sbin/ipfw/tables.c projects/ipfw/sys/netinet/ip_fw.h projects/ipfw/sys/netpfil/ipfw/ip_fw_private.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 Modified: projects/ipfw/sbin/ipfw/tables.c ============================================================================== --- projects/ipfw/sbin/ipfw/tables.c Sun Jun 15 12:21:06 2014 (r267508) +++ projects/ipfw/sbin/ipfw/tables.c Sun Jun 15 13:40:27 2014 (r267509) @@ -317,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh oh->set = i->set; oh->idx = 1; - oh->objtype = IPFW_OBJTYPE_TABLE; table_fill_ntlv(&oh->ntlv, i->tablename, 1); } @@ -332,9 +331,8 @@ table_destroy(char *name, uint32_t set) memset(&oh, 0, sizeof(oh)); oh.idx = 1; - oh.objtype = IPFW_OBJTYPE_TABLE; table_fill_ntlv(&oh.ntlv, name, 1); - if (do_set3(IP_FW_OBJ_DEL, &oh.opheader, sizeof(oh)) != 0) + if (do_set3(IP_FW_TABLE_XDESTROY, &oh.opheader, sizeof(oh)) != 0) return (-1); return (0); @@ -351,9 +349,8 @@ table_flush(char *name, uint32_t set) memset(&oh, 0, sizeof(oh)); oh.idx = 1; - oh.objtype = IPFW_OBJTYPE_TABLE; table_fill_ntlv(&oh.ntlv, name, 1); - if (do_set3(IP_FW_OBJ_FLUSH, &oh.opheader, sizeof(oh)) != 0) + if (do_set3(IP_FW_TABLE_XFLUSH, &oh.opheader, sizeof(oh)) != 0) return (-1); return (0); @@ -380,7 +377,7 @@ table_get_info(char *name, uint32_t set, table_fill_objheader(oh, i); - if (do_get3(IP_FW_OBJ_INFO, &oh->opheader, &sz) < 0) + if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) < 0) return (-1); if (sz < sizeof(tbuf)) @@ -486,17 +483,15 @@ tables_foreach(table_cb_t *f, void *arg, memset(&req, 0, sizeof(req)); sz = sizeof(req); - req.objtype = IPFW_OBJTYPE_TABLE; - if ((error = do_get3(IP_FW_OBJ_LISTSIZE, &req.opheader, &sz)) != 0) + if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) return (errno); sz = req.size; if ((olh = calloc(1, sz)) == NULL) return (ENOMEM); - olh->objtype = IPFW_OBJTYPE_TABLE; olh->size = sz; - if ((error = do_get3(IP_FW_OBJ_LIST, &olh->opheader, &sz)) != 0) { + if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { free(olh); return (errno); } @@ -517,7 +512,8 @@ tables_foreach(table_cb_t *f, void *arg, /* * Retrieves all entries for given table @i in - * eXtended format, returning pointer vi @ooh. + * eXtended format. Assumes buffer of size + * @i->size has already been allocated by caller. * * Returns 0 on success. */ @@ -530,7 +526,9 @@ table_get_list(ipfw_xtable_info *i, ipfw table_fill_objheader(oh, i); sz = i->size; - if ((error = do_get3(IP_FW_OBJ_DUMP, &oh->opheader, &sz)) != 0) + oh->opheader.version = 1; /* Current version */ + + if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0) return (errno); return (0); Modified: projects/ipfw/sys/netinet/ip_fw.h ============================================================================== --- projects/ipfw/sys/netinet/ip_fw.h Sun Jun 15 12:21:06 2014 (r267508) +++ projects/ipfw/sys/netinet/ip_fw.h Sun Jun 15 13:40:27 2014 (r267509) @@ -70,21 +70,47 @@ /* IP_FW3 header/opcodes */ typedef struct _ip_fw3_opheader { uint16_t opcode; /* Operation opcode */ - uint16_t reserved[3]; /* Align to 64-bit boundary */ + uint16_t version; /* Opcode version */ + uint16_t reserved[2]; /* Align to 64-bit boundary */ } ip_fw3_opheader; /* IPFW extented tables support */ #define IP_FW_TABLE_XADD 86 /* add entry */ #define IP_FW_TABLE_XDEL 87 /* delete entry */ -#define IP_FW_TABLE_XGETSIZE 88 /* get table size */ +#define IP_FW_TABLE_XGETSIZE 88 /* get table size (deprecated) */ #define IP_FW_TABLE_XLIST 89 /* list table contents */ -#define IP_FW_OBJ_DEL 90 /* del table/pipe/etc */ -#define IP_FW_OBJ_LISTSIZE 91 /* get size for table/etc list */ -#define IP_FW_OBJ_LIST 92 /* list all objects of given type */ -#define IP_FW_OBJ_INFO 93 /* request info for one object */ -#define IP_FW_OBJ_FLUSH 94 /* flush data for given object */ -#define IP_FW_OBJ_DUMP 95 /* dump all data for given object */ +#define IP_FW_TABLE_XDESTROY 90 /* destroy table */ +#define IP_FW_TABLES_XGETSIZE 91 /* get size for table/etc list */ +#define IP_FW_TABLES_XLIST 92 /* list all objects of given type */ +#define IP_FW_TABLE_XINFO 93 /* request info for one object */ +#define IP_FW_TABLE_XFLUSH 94 /* flush data for given object */ + +/* + * Usage guidelines: + * + * IP_FW_TABLE_XLIST(ver 1): Dumps all table data + * Request(getsockopt): [ ipfw_obj_lheader ], size = ipfw_xtable_info.size + * Reply: [ ipfw_obj_lheader ipfw_xtable_info ipfw_table_xentry x N ] + * + * IP_FW_TABLE_XDESTROY: Destroys given table + * Request(setsockopt): [ ipfw_obj_header ] + * + * IP_FW_TABLES_XGETSIZE: Get buffer size needed to list info for all tables. + * Request(getsockopt): [ empty ], size = sizeof(ipfw_obj_lheader) + * Reply: [ ipfw_obj_lheader ] + * + * IP_FW_TABLES_XLIST: Lists all tables currently available in kernel. + * Request(getsockopt): [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size + * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] + * + * IP_FW_TABLE_XINFO: Store table info to buffer. + * Request(getsockopt): [ ipfw_obj_header ipfw_xtable_info(empty)] + * Reply: [ ipfw_obj_header ipfw_xtable_info ] + * + * IP_FW_TABLE_XFLUSH: Removes all data from given table leaving type etc.. + * Request(setsockopt): [ ipfw_obj_header ] + */ /* * The kernel representation of ipfw rules is made of a list of @@ -679,10 +705,6 @@ typedef struct _ipfw_xtable_info { } ipfw_xtable_info; #define IPFW_OBJTYPE_TABLE 1 -/* - * IP_FW_OBJ_DEL, IP_FW_OBJ_INFO (followed by ipfw_xtable_info), - * IP_FW_OBJ_DUMP (followed by ipfw_xtable_info and ipfw_table_xentry'xN ) - */ typedef struct _ipfw_obj_header { ip_fw3_opheader opheader; /* IP_FW3 opcode */ uint32_t set; /* Set we're operating */ @@ -692,12 +714,9 @@ typedef struct _ipfw_obj_header { ipfw_obj_ntlv ntlv; /* object name tlv */ } ipfw_obj_header; -/* IP_FW_OBJ_LISTSIZE, IP_FW_OBJ_LIST (followd by ipfw_xtable_info) */ typedef struct _ipfw_obj_lheader { ip_fw3_opheader opheader; /* IP_FW3 opcode */ - uint8_t objtype; /* object type */ - uint8_t spare0; - uint16_t spare1; + uint32_t spare; uint32_t count; /* Total objects count */ uint32_t size; /* Total objects size */ uint32_t objsize; /* Size of one object */ Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sun Jun 15 12:21:06 2014 (r267508) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sun Jun 15 13:40:27 2014 (r267509) @@ -327,15 +327,6 @@ struct rule_check_info { struct obj_idx obuf[8]; /* table references storage */ }; -struct tentry_info { - void *paddr; - int plen; /* Total entry length */ - uint8_t masklen; /* mask length */ - uint8_t spare; - uint16_t flags; /* record flags */ - uint32_t value; /* value */ -}; - /* In ip_fw_sockopt.c */ int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id); int ipfw_ctl(struct sockopt *sopt); Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sun Jun 15 12:21:06 2014 (r267508) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sun Jun 15 13:40:27 2014 (r267509) @@ -1171,10 +1171,9 @@ ipfw_ctl(struct sockopt *sopt) sopt->sopt_name == IP_FW_RESETLOG); break; - /*--- TABLE manipulations are protected by the IPFW_LOCK ---*/ - case IP_FW_OBJ_DEL: /* IP_FW3 */ - case IP_FW_OBJ_INFO: /* IP_FW3 */ - case IP_FW_OBJ_FLUSH: /* IP_FW3 */ + /*--- TABLE opcodes ---*/ + case IP_FW_TABLE_XDESTROY: /* IP_FW3 */ + case IP_FW_TABLE_XFLUSH: /* IP_FW3 */ { struct _ipfw_obj_header *oh; struct tid_info ti; @@ -1186,64 +1185,31 @@ ipfw_ctl(struct sockopt *sopt) oh = (struct _ipfw_obj_header *)op3; - switch (oh->objtype) { - case IPFW_OBJTYPE_TABLE: - memset(&ti, 0, sizeof(ti)); - ti.set = oh->set; - ti.uidx = oh->idx; - ti.tlvs = &oh->ntlv; - ti.tlen = oh->ntlv.head.length; - if (opt == IP_FW_OBJ_DEL) - error = ipfw_destroy_table(chain, &ti); - else if (opt == IP_FW_OBJ_FLUSH) - error = ipfw_flush_table(chain, &ti); - else { - /* IP_FW_OBJ_INFO */ - if (sopt->sopt_valsize < sizeof(*oh) + - sizeof(ipfw_xtable_info)) { - error = EINVAL; - break; - } - - error = ipfw_describe_table(chain, &ti, - (ipfw_xtable_info *)(oh + 1)); - if (error == 0) - error = sooptcopyout(sopt, oh, - sopt->sopt_valsize); - } - break; - default: + objheader_to_ti(oh, &ti); + + if (opt == IP_FW_TABLE_XDESTROY) + error = ipfw_destroy_table(chain, &ti); + else if (opt == IP_FW_TABLE_XFLUSH) + error = ipfw_flush_table(chain, &ti); + else error = ENOTSUP; - break; - } break; } - case IP_FW_TABLE_ADD: - case IP_FW_TABLE_DEL: - { - ipfw_table_entry ent; - struct tentry_info tei; - struct tid_info ti; - error = sooptcopyin(sopt, &ent, - sizeof(ent), sizeof(ent)); - if (error) - break; + case IP_FW_TABLE_XINFO: /* IP_FW3 */ + error = ipfw_describe_table(chain, sopt, op3, valsize); + break; - memset(&tei, 0, sizeof(tei)); - tei.paddr = &ent.addr; - tei.plen = sizeof(ent.addr); - tei.masklen = ent.masklen; - tei.value = ent.value; - memset(&ti, 0, sizeof(ti)); - ti.set = RESVD_SET; - ti.uidx = ent.tbl; - ti.type = IPFW_TABLE_CIDR; + case IP_FW_TABLES_XGETSIZE: /* IP_FW3 */ + error = ipfw_listsize_tables(chain, sopt, op3, valsize); + break; - error = (opt == IP_FW_TABLE_ADD) ? - ipfw_add_table_entry(chain, &ti, &tei) : - ipfw_del_table_entry(chain, &ti, &tei); - } + case IP_FW_TABLES_XLIST: /* IP_FW3 */ + error = ipfw_list_tables(chain, sopt, op3, valsize); + break; + + case IP_FW_TABLE_XLIST: /* IP_FW3 */ + error = ipfw_dump_table(chain, sopt, op3, valsize); break; case IP_FW_TABLE_XADD: /* IP_FW3 */ @@ -1283,6 +1249,36 @@ ipfw_ctl(struct sockopt *sopt) } break; + /*--- LEGACY API ---*/ + case IP_FW_TABLE_ADD: + case IP_FW_TABLE_DEL: + { + ipfw_table_entry ent; + struct tentry_info tei; + struct tid_info ti; + + error = sooptcopyin(sopt, &ent, + sizeof(ent), sizeof(ent)); + if (error) + break; + + memset(&tei, 0, sizeof(tei)); + tei.paddr = &ent.addr; + tei.plen = sizeof(ent.addr); + tei.masklen = ent.masklen; + tei.value = ent.value; + memset(&ti, 0, sizeof(ti)); + ti.set = RESVD_SET; + ti.uidx = ent.tbl; + ti.type = IPFW_TABLE_CIDR; + + error = (opt == IP_FW_TABLE_ADD) ? + ipfw_add_table_entry(chain, &ti, &tei) : + ipfw_del_table_entry(chain, &ti, &tei); + } + break; + + case IP_FW_TABLE_FLUSH: { u_int16_t tbl; @@ -1375,110 +1371,6 @@ ipfw_ctl(struct sockopt *sopt) error = sooptcopyout(sopt, op3, sopt->sopt_valsize); } break; - - case IP_FW_TABLE_XLIST: /* IP_FW3 */ - { - ipfw_xtable *tbl; - struct tid_info ti; - - if ((size = valsize) < sizeof(ipfw_xtable)) { - error = EINVAL; - break; - } - - tbl = malloc(size, M_TEMP, M_ZERO | M_WAITOK); - memcpy(tbl, op3, sizeof(ipfw_xtable)); - - /* Get maximum number of entries we can store */ - tbl->size = (size - sizeof(ipfw_xtable)) / - sizeof(ipfw_table_xentry); - memset(&ti, 0, sizeof(ti)); - ti.set = 0; /* XXX: No way to specify set */ - ti.uidx = tbl->tbl; - IPFW_UH_RLOCK(chain); - error = ipfw_dump_xtable(chain, &ti, tbl); - IPFW_UH_RUNLOCK(chain); - if (error) { - free(tbl, M_TEMP); - break; - } - - /* Revert size field back to bytes */ - tbl->size = tbl->size * sizeof(ipfw_table_xentry) + - sizeof(ipfw_table); - /* - * Since we call sooptcopyin() with small buffer, sopt_valsize is - * decreased to reflect supplied buffer size. Set it back to original value - */ - sopt->sopt_valsize = valsize; - error = sooptcopyout(sopt, tbl, size); - free(tbl, M_TEMP); - } - break; - case IP_FW_OBJ_LISTSIZE: /* IP_FW3 */ - { - struct _ipfw_obj_lheader *olh; - - if (sopt->sopt_valsize < sizeof(*olh)) { - error = EINVAL; - break; - } - - olh = (struct _ipfw_obj_lheader *)op3; - - switch (olh->objtype) { - case IPFW_OBJTYPE_TABLE: - error = ipfw_listsize_tables(chain, sopt, op3, - valsize); - break; - default: - error = ENOTSUP; - break; - } - break; - } - case IP_FW_OBJ_LIST: /* IP_FW3 */ - { - struct _ipfw_obj_lheader *olh; - - if (sopt->sopt_valsize < sizeof(*olh)) { - error = EINVAL; - break; - } - - olh = (struct _ipfw_obj_lheader *)op3; - switch (olh->objtype) { - case IPFW_OBJTYPE_TABLE: - error = ipfw_list_tables(chain, sopt, op3, - valsize); - break; - default: - error = ENOTSUP; - break; - } - break; - } - case IP_FW_OBJ_DUMP: /* IP_FW3 */ - { - struct _ipfw_obj_header *oh; - - if (sopt->sopt_valsize < sizeof(*oh)) { - error = EINVAL; - break; - } - - oh = (struct _ipfw_obj_header *)op3; - switch (oh->objtype) { - case IPFW_OBJTYPE_TABLE: - error = ipfw_dump_table(chain, sopt, op3, - valsize); - break; - default: - error = ENOTSUP; - break; - } - break; - } /*--- NAT operations are protected by the IPFW_LOCK ---*/ case IP_FW_NAT_CFG: if (IPFW_NAT_LOADED) Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sun Jun 15 12:21:06 2014 (r267508) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sun Jun 15 13:40:27 2014 (r267509) @@ -105,6 +105,14 @@ static int export_tables(struct ip_fw_ch static void export_table_info(struct table_config *tc, ipfw_xtable_info *i); static int dump_table_xentry(void *e, void *arg); +static int check_buffer(size_t items, size_t item_size, size_t header, + size_t bufsize); + +static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt, + ip_fw3_opheader *op3, size_t valsize); +static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt, + ip_fw3_opheader *op3, size_t valsize); + static struct table_algo *find_table_algo(struct tables_config *tableconf, struct tid_info *ti); @@ -538,7 +546,16 @@ ipfw_lookup_table_extended(struct ip_fw_ */ /* - * High-level handlers for setsockopt + * High-level 'get' cmds sysctl handlers + */ + +/* + * Get buffer size needed to list info for all tables. + * Data layout: + * Request: [ empty ], size = sizeof(ipfw_obj_lheader) + * Reply: [ ipfw_obj_lheader ] + * + * Returns 0 on success */ int ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt, @@ -546,6 +563,9 @@ ipfw_listsize_tables(struct ip_fw_chain { struct _ipfw_obj_lheader *olh; + if (sopt->sopt_valsize < sizeof(*olh)) + return (EINVAL); + olh = (struct _ipfw_obj_lheader *)op3; olh->size = sizeof(*olh); /* Make export_table store needed size */ @@ -558,15 +578,25 @@ ipfw_listsize_tables(struct ip_fw_chain return (sooptcopyout(sopt, olh, sopt->sopt_valsize)); } - +/* + * Lists all tables currently available in kernel. + * Data layout: + * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size + * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] + * + * Returns 0 on success + */ int ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt, ip_fw3_opheader *op3, size_t valsize) { struct _ipfw_obj_lheader *olh; - uint32_t sz, sz_min, sz_max; + uint32_t sz; int error; + if (sopt->sopt_valsize < sizeof(*olh)) + return (EINVAL); + olh = (struct _ipfw_obj_lheader *)op3; if (valsize != olh->size) @@ -580,11 +610,9 @@ ipfw_list_tables(struct ip_fw_chain *ch, IPFW_UH_RLOCK(ch); sz = ipfw_objhash_count(CHAIN_TO_NI(ch)); IPFW_UH_RUNLOCK(ch); - - sz_min = sz * sizeof(ipfw_xtable_info) + sizeof(*olh); - sz_max = sz_min + (sz + 1) * sizeof(ipfw_xtable_info); - if (valsize < sz_min || valsize > sz_max) + if (check_buffer(sz, sizeof(ipfw_xtable_info), + sizeof(*olh), valsize) != 0) return (EINVAL); olh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK); @@ -612,6 +640,46 @@ ipfw_list_tables(struct ip_fw_chain *ch, return (0); } +/* + * Store table info to buffer provided by @op3. + * Data layout: + * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] + * Reply: [ ipfw_obj_header ipfw_xtable_info ] + * + * Returns 0 on success. + */ +int +ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt, + ip_fw3_opheader *op3, size_t valsize) +{ + struct _ipfw_obj_header *oh; + struct table_config *tc; + struct tid_info ti; + size_t sz; + int error; + + sz = sizeof(*oh) + sizeof(ipfw_xtable_info); + if (sopt->sopt_valsize < sz) + return (EINVAL); + + oh = (struct _ipfw_obj_header *)op3; + + objheader_to_ti(oh, &ti); + + IPFW_UH_RLOCK(ch); + if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { + IPFW_UH_RUNLOCK(ch); + return (ESRCH); + } + + export_table_info(tc, (ipfw_xtable_info *)(oh + 1)); + IPFW_UH_RUNLOCK(ch); + + error = sooptcopyout(sopt, oh, sz); + + return (error); +} + struct dump_args { struct table_info *ti; struct table_config *tc; @@ -626,22 +694,49 @@ int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt, ip_fw3_opheader *op3, size_t valsize) { + int error; + + switch (op3->version) { + case 0: + error = ipfw_dump_table_v0(ch, sopt, op3, valsize); + break; + case 1: + error = ipfw_dump_table_v1(ch, sopt, op3, valsize); + break; + default: + error = ENOTSUP; + } + + return (error); +} + +/* + * Dumps all table data + * Data layout (version 1): + * Request: [ ipfw_obj_lheader ], size = ipfw_xtable_info.size + * Reply: [ ipfw_obj_lheader ipfw_xtable_info ipfw_table_xentry x N ] + * + * Returns 0 on success + */ +static int +ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt, + ip_fw3_opheader *op3, size_t valsize) +{ struct _ipfw_obj_header *oh; ipfw_xtable_info *i; struct tid_info ti; struct table_config *tc; struct table_algo *ta; struct dump_args da; - uint32_t sz, sz_min, sz_max; + uint32_t sz; int error; + if (sopt->sopt_valsize < sizeof(*oh)) + return (EINVAL); + oh = (struct _ipfw_obj_header *)op3; - memset(&ti, 0, sizeof(ti)); - ti.set = oh->set; - ti.uidx = oh->idx; - ti.tlvs = &oh->ntlv; - ti.tlen = oh->ntlv.head.length; + objheader_to_ti(oh, &ti); IPFW_UH_RLOCK(ch); if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { @@ -651,20 +746,10 @@ ipfw_dump_table(struct ip_fw_chain *ch, sz = tc->count; IPFW_UH_RUNLOCK(ch); - /* - * Check if array size is "reasonable": - * Permit valsize between current size and - * 2x current size + 1 - */ - - sz_min = sz * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable_info) + - sizeof(*oh); - - sz_max = sz_min + (sz + 1) * sizeof(ipfw_table_xentry); - - if (valsize < sz_min || valsize > sz_max) + if (check_buffer(sz, sizeof(ipfw_table_xentry), + sizeof(ipfw_xtable_info) + sizeof(*oh), valsize) != 0) return (EINVAL); - + oh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK); i = (ipfw_xtable_info *)(oh + 1); /* Copy header to new storage */ @@ -689,6 +774,7 @@ ipfw_dump_table(struct ip_fw_chain *ch, /* * Do the actual dump in eXtended format */ + memset(&da, 0, sizeof(da)); da.ti = KIDX_TO_TI(ch, tc->no.kidx); da.tc = tc; da.xent = (ipfw_table_xentry *)(i + 1); @@ -712,6 +798,122 @@ ipfw_dump_table(struct ip_fw_chain *ch, return (0); } +/* + * Dumps all table data + * Data layout (version 0): + * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() + * Reply: [ ipfw_xtable ipfw_table_xentry x N ] + * + * Returns 0 on success + */ +static int +ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt, + ip_fw3_opheader *op3, size_t valsize) +{ + ipfw_xtable *xtbl; + struct tid_info ti; + struct table_config *tc; + struct table_algo *ta; + struct dump_args da; + int error; + size_t sz; + + if (valsize < sizeof(ipfw_xtable)) + return (EINVAL); + + xtbl = (ipfw_xtable *)op3; + + memset(&ti, 0, sizeof(ti)); + ti.set = 0; /* XXX: No way to specify set */ + ti.uidx = xtbl->tbl; + + IPFW_UH_RLOCK(ch); + if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { + IPFW_UH_RUNLOCK(ch); + return (0); + } + sz = tc->count; + IPFW_UH_RUNLOCK(ch); + + if (check_buffer(sz, sizeof(ipfw_table_xentry), + sizeof(ipfw_xtable) - sizeof(ipfw_table_xentry), valsize) != 0) + return (EINVAL); + + xtbl = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK); + memcpy(xtbl, op3, sizeof(ipfw_xtable)); + + IPFW_UH_RLOCK(ch); + if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { + IPFW_UH_RUNLOCK(ch); + free(xtbl, M_TEMP); + return (0); + } + + /* Check size another time */ + sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); + if (sz > valsize) { + IPFW_UH_RUNLOCK(ch); + free(xtbl, M_TEMP); + return (EINVAL); + } + + /* Do the actual dump in eXtended format */ + memset(&da, 0, sizeof(da)); + da.ti = KIDX_TO_TI(ch, tc->no.kidx); + da.tc = tc; + da.xent = &xtbl->xent[0]; + da.size = tc->count; + xtbl->type = tc->no.type; + xtbl->tbl = ti.uidx; + ta = tc->ta; + + ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); + xtbl->cnt = da.cnt; + xtbl->size = sz; + + IPFW_UH_RUNLOCK(ch); + + /* + * Since we call sooptcopyin() with small buffer, sopt_valsize is + * decreased to reflect supplied buffer size. Set it back to original value + */ + sopt->sopt_valsize = valsize; + error = sooptcopyout(sopt, xtbl, sz); + free(xtbl, M_TEMP); + + return (error); +} + +/* + * Checks if supplied buffer size is "reasonable". + * Permit valsize between current needed size and + * 2x needed size + 1 + */ +static int +check_buffer(size_t items, size_t item_size, size_t header, size_t bufsize) +{ + size_t sz_min, sz_max; + + sz_min = items * item_size + header; + sz_max = (2 * items + 1) * item_size + header; + + if (bufsize < sz_min || bufsize > sz_max) + return (EINVAL); + + return (0); +} + +void +objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) +{ + + memset(ti, 0, sizeof(struct tid_info)); + ti->set = oh->set; + ti->uidx = oh->idx; + ti->tlvs = &oh->ntlv; + ti->tlen = oh->ntlv.head.length; +} + static void export_table_info(struct table_config *tc, ipfw_xtable_info *i) { @@ -728,34 +930,6 @@ export_table_info(struct table_config *t strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); } -int -ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh) -{ - uint32_t count; - - count = ipfw_objhash_count(CHAIN_TO_NI(ch)); - - olh->count = count; - olh->size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); - olh->objsize = sizeof(ipfw_xtable_info); - - return (0); -} - -int -ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti, - ipfw_xtable_info *i) -{ - struct table_config *tc; - - if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) - return (ESRCH); - - export_table_info(tc, i); - - return (0); -} - static void export_table_internal(struct namedobj_instance *ni, struct named_object *no, void *arg) @@ -818,8 +992,10 @@ ipfw_count_xtable(struct ip_fw_chain *ch { struct table_config *tc; - if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) + if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { + *cnt = 0; return (0); /* 'table all list' requires success */ + } *cnt = tc->count * sizeof(ipfw_table_xentry); if (tc->count > 0) *cnt += sizeof(ipfw_xtable); @@ -870,10 +1046,10 @@ ipfw_dump_table_legacy(struct ip_fw_chai if (ta->dump_entry == NULL) return (0); /* Legacy dump support is not necessary */ + memset(&da, 0, sizeof(da)); da.ti = KIDX_TO_TI(ch, tc->no.kidx); da.tc = tc; da.ent = &tbl->ent[0]; - da.cnt = 0; da.size = tbl->size; tbl->cnt = 0; @@ -921,11 +1097,11 @@ ipfw_dump_xtable(struct ip_fw_chain *ch, if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) return (0); /* XXX: We should return ESRCH */ + memset(&da, 0, sizeof(da)); da.ti = KIDX_TO_TI(ch, tc->no.kidx); da.tc = tc; da.xent = &xtbl->xent[0]; da.size = xtbl->size; - da.cnt = 0; xtbl->type = tc->no.type; xtbl->tbl = ti->uidx; ta = tc->ta; Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Sun Jun 15 12:21:06 2014 (r267508) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Sun Jun 15 13:40:27 2014 (r267509) @@ -41,6 +41,15 @@ struct table_info { u_long data; /* Hints for given func */ }; +struct tentry_info { + void *paddr; + int plen; /* Total entry length */ + uint8_t masklen; /* mask length */ + uint8_t spare; + uint16_t flags; /* record flags */ + uint32_t value; /* value */ +}; + typedef int (ta_init)(void **ta_state, struct table_info *ti); typedef void (ta_destroy)(void *ta_state, struct table_info *ti); typedef int (ta_prepare_add)(struct tentry_info *tei, void *ta_buf); @@ -77,6 +86,10 @@ struct table_algo { void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta); extern struct table_algo radix_cidr, radix_iface; +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_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt, ip_fw3_opheader *op3, size_t valsize); @@ -84,6 +97,8 @@ int ipfw_list_tables(struct ip_fw_chain ip_fw3_opheader *op3, size_t valsize); int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt, ip_fw3_opheader *op3, size_t valsize); +int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt, + ip_fw3_opheader *op3, size_t valsize); int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); int ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti); @@ -91,6 +106,16 @@ int ipfw_add_table_entry(struct ip_fw_ch struct tentry_info *tei); int ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, struct tentry_info *tei); +int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, + struct rule_check_info *ci); +int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule); +void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule); +void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head); + +/* utility functions */ +void objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti); + +/* Legacy interfaces */ int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt); int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, @@ -99,17 +124,6 @@ int ipfw_dump_table_legacy(struct ip_fw_ ipfw_table *tbl); int ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_xtable *tbl); -int ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti, - ipfw_xtable_info *i); -int ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh); -int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, - struct rule_check_info *ci); -int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule); -void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule); -void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head); - -void ipfw_table_algo_init(struct ip_fw_chain *chain); -void ipfw_table_algo_destroy(struct ip_fw_chain *chain); #endif /* _KERNEL */