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.
This commit is contained in:
melifaro 2014-06-15 13:40:27 +00:00
parent fe9646e6ff
commit b06860b3e2
6 changed files with 354 additions and 264 deletions

View File

@ -317,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
oh->set = i->set; oh->set = i->set;
oh->idx = 1; oh->idx = 1;
oh->objtype = IPFW_OBJTYPE_TABLE;
table_fill_ntlv(&oh->ntlv, i->tablename, 1); table_fill_ntlv(&oh->ntlv, i->tablename, 1);
} }
@ -332,9 +331,8 @@ table_destroy(char *name, uint32_t set)
memset(&oh, 0, sizeof(oh)); memset(&oh, 0, sizeof(oh));
oh.idx = 1; oh.idx = 1;
oh.objtype = IPFW_OBJTYPE_TABLE;
table_fill_ntlv(&oh.ntlv, name, 1); 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 (-1);
return (0); return (0);
@ -351,9 +349,8 @@ table_flush(char *name, uint32_t set)
memset(&oh, 0, sizeof(oh)); memset(&oh, 0, sizeof(oh));
oh.idx = 1; oh.idx = 1;
oh.objtype = IPFW_OBJTYPE_TABLE;
table_fill_ntlv(&oh.ntlv, name, 1); 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 (-1);
return (0); return (0);
@ -380,7 +377,7 @@ table_get_info(char *name, uint32_t set, ipfw_xtable_info *i)
table_fill_objheader(oh, i); 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); return (-1);
if (sz < sizeof(tbuf)) if (sz < sizeof(tbuf))
@ -486,17 +483,15 @@ tables_foreach(table_cb_t *f, void *arg, int sort)
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
sz = sizeof(req); sz = sizeof(req);
req.objtype = IPFW_OBJTYPE_TABLE; if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0)
if ((error = do_get3(IP_FW_OBJ_LISTSIZE, &req.opheader, &sz)) != 0)
return (errno); return (errno);
sz = req.size; sz = req.size;
if ((olh = calloc(1, sz)) == NULL) if ((olh = calloc(1, sz)) == NULL)
return (ENOMEM); return (ENOMEM);
olh->objtype = IPFW_OBJTYPE_TABLE;
olh->size = sz; 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); free(olh);
return (errno); return (errno);
} }
@ -517,7 +512,8 @@ tables_foreach(table_cb_t *f, void *arg, int sort)
/* /*
* Retrieves all entries for given table @i in * 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. * Returns 0 on success.
*/ */
@ -530,7 +526,9 @@ table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
table_fill_objheader(oh, i); table_fill_objheader(oh, i);
sz = i->size; 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 (errno);
return (0); return (0);

View File

@ -70,21 +70,47 @@
/* IP_FW3 header/opcodes */ /* IP_FW3 header/opcodes */
typedef struct _ip_fw3_opheader { typedef struct _ip_fw3_opheader {
uint16_t opcode; /* Operation opcode */ 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; } ip_fw3_opheader;
/* IPFW extented tables support */ /* IPFW extented tables support */
#define IP_FW_TABLE_XADD 86 /* add entry */ #define IP_FW_TABLE_XADD 86 /* add entry */
#define IP_FW_TABLE_XDEL 87 /* delete 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_TABLE_XLIST 89 /* list table contents */
#define IP_FW_OBJ_DEL 90 /* del table/pipe/etc */ #define IP_FW_TABLE_XDESTROY 90 /* destroy table */
#define IP_FW_OBJ_LISTSIZE 91 /* get size for table/etc list */ #define IP_FW_TABLES_XGETSIZE 91 /* get size for table/etc list */
#define IP_FW_OBJ_LIST 92 /* list all objects of given type */ #define IP_FW_TABLES_XLIST 92 /* list all objects of given type */
#define IP_FW_OBJ_INFO 93 /* request info for one object */ #define IP_FW_TABLE_XINFO 93 /* request info for one object */
#define IP_FW_OBJ_FLUSH 94 /* flush data for given object */ #define IP_FW_TABLE_XFLUSH 94 /* flush data for given object */
#define IP_FW_OBJ_DUMP 95 /* dump all 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 * The kernel representation of ipfw rules is made of a list of
@ -679,10 +705,6 @@ typedef struct _ipfw_xtable_info {
} ipfw_xtable_info; } ipfw_xtable_info;
#define IPFW_OBJTYPE_TABLE 1 #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 { typedef struct _ipfw_obj_header {
ip_fw3_opheader opheader; /* IP_FW3 opcode */ ip_fw3_opheader opheader; /* IP_FW3 opcode */
uint32_t set; /* Set we're operating */ 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_ntlv ntlv; /* object name tlv */
} ipfw_obj_header; } ipfw_obj_header;
/* IP_FW_OBJ_LISTSIZE, IP_FW_OBJ_LIST (followd by ipfw_xtable_info) */
typedef struct _ipfw_obj_lheader { typedef struct _ipfw_obj_lheader {
ip_fw3_opheader opheader; /* IP_FW3 opcode */ ip_fw3_opheader opheader; /* IP_FW3 opcode */
uint8_t objtype; /* object type */ uint32_t spare;
uint8_t spare0;
uint16_t spare1;
uint32_t count; /* Total objects count */ uint32_t count; /* Total objects count */
uint32_t size; /* Total objects size */ uint32_t size; /* Total objects size */
uint32_t objsize; /* Size of one object */ uint32_t objsize; /* Size of one object */

View File

@ -327,15 +327,6 @@ struct rule_check_info {
struct obj_idx obuf[8]; /* table references storage */ 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 */ /* In ip_fw_sockopt.c */
int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id); int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);
int ipfw_ctl(struct sockopt *sopt); int ipfw_ctl(struct sockopt *sopt);

View File

@ -1171,10 +1171,9 @@ ipfw_ctl(struct sockopt *sopt)
sopt->sopt_name == IP_FW_RESETLOG); sopt->sopt_name == IP_FW_RESETLOG);
break; break;
/*--- TABLE manipulations are protected by the IPFW_LOCK ---*/ /*--- TABLE opcodes ---*/
case IP_FW_OBJ_DEL: /* IP_FW3 */ case IP_FW_TABLE_XDESTROY: /* IP_FW3 */
case IP_FW_OBJ_INFO: /* IP_FW3 */ case IP_FW_TABLE_XFLUSH: /* IP_FW3 */
case IP_FW_OBJ_FLUSH: /* IP_FW3 */
{ {
struct _ipfw_obj_header *oh; struct _ipfw_obj_header *oh;
struct tid_info ti; struct tid_info ti;
@ -1186,64 +1185,31 @@ ipfw_ctl(struct sockopt *sopt)
oh = (struct _ipfw_obj_header *)op3; oh = (struct _ipfw_obj_header *)op3;
switch (oh->objtype) { objheader_to_ti(oh, &ti);
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, if (opt == IP_FW_TABLE_XDESTROY)
(ipfw_xtable_info *)(oh + 1)); error = ipfw_destroy_table(chain, &ti);
if (error == 0) else if (opt == IP_FW_TABLE_XFLUSH)
error = sooptcopyout(sopt, oh, error = ipfw_flush_table(chain, &ti);
sopt->sopt_valsize); else
}
break;
default:
error = ENOTSUP; error = ENOTSUP;
break;
}
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, case IP_FW_TABLE_XINFO: /* IP_FW3 */
sizeof(ent), sizeof(ent)); error = ipfw_describe_table(chain, sopt, op3, valsize);
if (error) break;
break;
memset(&tei, 0, sizeof(tei)); case IP_FW_TABLES_XGETSIZE: /* IP_FW3 */
tei.paddr = &ent.addr; error = ipfw_listsize_tables(chain, sopt, op3, valsize);
tei.plen = sizeof(ent.addr); break;
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) ? case IP_FW_TABLES_XLIST: /* IP_FW3 */
ipfw_add_table_entry(chain, &ti, &tei) : error = ipfw_list_tables(chain, sopt, op3, valsize);
ipfw_del_table_entry(chain, &ti, &tei); break;
}
case IP_FW_TABLE_XLIST: /* IP_FW3 */
error = ipfw_dump_table(chain, sopt, op3, valsize);
break; break;
case IP_FW_TABLE_XADD: /* IP_FW3 */ case IP_FW_TABLE_XADD: /* IP_FW3 */
@ -1283,6 +1249,36 @@ ipfw_ctl(struct sockopt *sopt)
} }
break; 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: case IP_FW_TABLE_FLUSH:
{ {
u_int16_t tbl; u_int16_t tbl;
@ -1375,110 +1371,6 @@ ipfw_ctl(struct sockopt *sopt)
error = sooptcopyout(sopt, op3, sopt->sopt_valsize); error = sooptcopyout(sopt, op3, sopt->sopt_valsize);
} }
break; 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 ---*/ /*--- NAT operations are protected by the IPFW_LOCK ---*/
case IP_FW_NAT_CFG: case IP_FW_NAT_CFG:
if (IPFW_NAT_LOADED) if (IPFW_NAT_LOADED)

View File

@ -105,6 +105,14 @@ static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh);
static void export_table_info(struct table_config *tc, ipfw_xtable_info *i); static void export_table_info(struct table_config *tc, ipfw_xtable_info *i);
static int dump_table_xentry(void *e, void *arg); 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, static struct table_algo *find_table_algo(struct tables_config *tableconf,
struct tid_info *ti); struct tid_info *ti);
@ -538,7 +546,16 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
*/ */
/* /*
* 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 int
ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt, ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
@ -546,6 +563,9 @@ ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
{ {
struct _ipfw_obj_lheader *olh; struct _ipfw_obj_lheader *olh;
if (sopt->sopt_valsize < sizeof(*olh))
return (EINVAL);
olh = (struct _ipfw_obj_lheader *)op3; olh = (struct _ipfw_obj_lheader *)op3;
olh->size = sizeof(*olh); /* Make export_table store needed size */ olh->size = sizeof(*olh); /* Make export_table store needed size */
@ -558,15 +578,25 @@ ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
return (sooptcopyout(sopt, olh, sopt->sopt_valsize)); 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 int
ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt, ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize) ip_fw3_opheader *op3, size_t valsize)
{ {
struct _ipfw_obj_lheader *olh; struct _ipfw_obj_lheader *olh;
uint32_t sz, sz_min, sz_max; uint32_t sz;
int error; int error;
if (sopt->sopt_valsize < sizeof(*olh))
return (EINVAL);
olh = (struct _ipfw_obj_lheader *)op3; olh = (struct _ipfw_obj_lheader *)op3;
if (valsize != olh->size) if (valsize != olh->size)
@ -580,11 +610,9 @@ ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
IPFW_UH_RLOCK(ch); IPFW_UH_RLOCK(ch);
sz = ipfw_objhash_count(CHAIN_TO_NI(ch)); sz = ipfw_objhash_count(CHAIN_TO_NI(ch));
IPFW_UH_RUNLOCK(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); return (EINVAL);
olh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK); olh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
@ -612,6 +640,46 @@ ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
return (0); 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 dump_args {
struct table_info *ti; struct table_info *ti;
struct table_config *tc; struct table_config *tc;
@ -625,6 +693,34 @@ struct dump_args {
int int
ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt, ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize) 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; struct _ipfw_obj_header *oh;
ipfw_xtable_info *i; ipfw_xtable_info *i;
@ -632,16 +728,15 @@ ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
struct table_config *tc; struct table_config *tc;
struct table_algo *ta; struct table_algo *ta;
struct dump_args da; struct dump_args da;
uint32_t sz, sz_min, sz_max; uint32_t sz;
int error; int error;
if (sopt->sopt_valsize < sizeof(*oh))
return (EINVAL);
oh = (struct _ipfw_obj_header *)op3; oh = (struct _ipfw_obj_header *)op3;
memset(&ti, 0, sizeof(ti)); objheader_to_ti(oh, &ti);
ti.set = oh->set;
ti.uidx = oh->idx;
ti.tlvs = &oh->ntlv;
ti.tlen = oh->ntlv.head.length;
IPFW_UH_RLOCK(ch); IPFW_UH_RLOCK(ch);
if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
@ -651,20 +746,10 @@ ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
sz = tc->count; sz = tc->count;
IPFW_UH_RUNLOCK(ch); IPFW_UH_RUNLOCK(ch);
/* if (check_buffer(sz, sizeof(ipfw_table_xentry),
* Check if array size is "reasonable": sizeof(ipfw_xtable_info) + sizeof(*oh), valsize) != 0)
* 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)
return (EINVAL); return (EINVAL);
oh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK); oh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
i = (ipfw_xtable_info *)(oh + 1); i = (ipfw_xtable_info *)(oh + 1);
/* Copy header to new storage */ /* Copy header to new storage */
@ -689,6 +774,7 @@ ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
/* /*
* Do the actual dump in eXtended format * Do the actual dump in eXtended format
*/ */
memset(&da, 0, sizeof(da));
da.ti = KIDX_TO_TI(ch, tc->no.kidx); da.ti = KIDX_TO_TI(ch, tc->no.kidx);
da.tc = tc; da.tc = tc;
da.xent = (ipfw_table_xentry *)(i + 1); da.xent = (ipfw_table_xentry *)(i + 1);
@ -712,6 +798,122 @@ ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
return (0); 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 static void
export_table_info(struct table_config *tc, ipfw_xtable_info *i) export_table_info(struct table_config *tc, ipfw_xtable_info *i)
{ {
@ -728,34 +930,6 @@ export_table_info(struct table_config *tc, ipfw_xtable_info *i)
strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 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 static void
export_table_internal(struct namedobj_instance *ni, struct named_object *no, export_table_internal(struct namedobj_instance *ni, struct named_object *no,
void *arg) void *arg)
@ -818,8 +992,10 @@ ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
{ {
struct table_config *tc; 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 */ return (0); /* 'table all list' requires success */
}
*cnt = tc->count * sizeof(ipfw_table_xentry); *cnt = tc->count * sizeof(ipfw_table_xentry);
if (tc->count > 0) if (tc->count > 0)
*cnt += sizeof(ipfw_xtable); *cnt += sizeof(ipfw_xtable);
@ -870,10 +1046,10 @@ ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
if (ta->dump_entry == NULL) if (ta->dump_entry == NULL)
return (0); /* Legacy dump support is not necessary */ return (0); /* Legacy dump support is not necessary */
memset(&da, 0, sizeof(da));
da.ti = KIDX_TO_TI(ch, tc->no.kidx); da.ti = KIDX_TO_TI(ch, tc->no.kidx);
da.tc = tc; da.tc = tc;
da.ent = &tbl->ent[0]; da.ent = &tbl->ent[0];
da.cnt = 0;
da.size = tbl->size; da.size = tbl->size;
tbl->cnt = 0; tbl->cnt = 0;
@ -921,11 +1097,11 @@ ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_xtable *xtbl)
if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
return (0); /* XXX: We should return ESRCH */ return (0); /* XXX: We should return ESRCH */
memset(&da, 0, sizeof(da));
da.ti = KIDX_TO_TI(ch, tc->no.kidx); da.ti = KIDX_TO_TI(ch, tc->no.kidx);
da.tc = tc; da.tc = tc;
da.xent = &xtbl->xent[0]; da.xent = &xtbl->xent[0];
da.size = xtbl->size; da.size = xtbl->size;
da.cnt = 0;
xtbl->type = tc->no.type; xtbl->type = tc->no.type;
xtbl->tbl = ti->uidx; xtbl->tbl = ti->uidx;
ta = tc->ta; ta = tc->ta;

View File

@ -41,6 +41,15 @@ struct table_info {
u_long data; /* Hints for given func */ 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 int (ta_init)(void **ta_state, struct table_info *ti);
typedef void (ta_destroy)(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); 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); void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
extern struct table_algo radix_cidr, radix_iface; 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 */ /* direct ipfw_ctl handlers */
int ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt, int ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize); ip_fw3_opheader *op3, size_t valsize);
@ -84,6 +97,8 @@ int ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize); ip_fw3_opheader *op3, size_t valsize);
int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt, int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize); 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_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
int ipfw_flush_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_chain *ch, struct tid_info *ti,
struct tentry_info *tei); struct tentry_info *tei);
int ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, int ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
struct tentry_info *tei); 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, int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti,
uint32_t *cnt); uint32_t *cnt);
int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, 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_chain *ch, struct tid_info *ti,
ipfw_table *tbl); ipfw_table *tbl);
int ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, int ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti,
ipfw_xtable *tbl); 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 */ #endif /* _KERNEL */