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:
parent
fe9646e6ff
commit
b06860b3e2
@ -317,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
|
||||
|
||||
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, ipfw_xtable_info *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);
|
||||
|
||||
if (sz < sizeof(tbuf))
|
||||
@ -486,17 +483,15 @@ tables_foreach(table_cb_t *f, void *arg, int sort)
|
||||
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, int sort)
|
||||
|
||||
/*
|
||||
* 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_obj_header *oh)
|
||||
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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
objheader_to_ti(oh, &ti);
|
||||
|
||||
error = ipfw_describe_table(chain, &ti,
|
||||
(ipfw_xtable_info *)(oh + 1));
|
||||
if (error == 0)
|
||||
error = sooptcopyout(sopt, oh,
|
||||
sopt->sopt_valsize);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
|
@ -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 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_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
|
||||
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;
|
||||
|
||||
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 *ch, struct sockopt *sopt,
|
||||
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, struct sockopt *sopt,
|
||||
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, struct sockopt *sopt,
|
||||
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;
|
||||
@ -625,6 +693,34 @@ struct dump_args {
|
||||
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;
|
||||
@ -632,16 +728,15 @@ ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
||||
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, struct sockopt *sopt,
|
||||
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, struct sockopt *sopt,
|
||||
/*
|
||||
* 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, struct sockopt *sopt,
|
||||
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 *tc, ipfw_xtable_info *i)
|
||||
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 tid_info *ti, uint32_t *cnt)
|
||||
{
|
||||
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_chain *ch, struct tid_info *ti,
|
||||
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, struct tid_info *ti, ipfw_xtable *xtbl)
|
||||
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;
|
||||
|
@ -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 *ch, struct sockopt *sopt,
|
||||
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_chain *ch, struct tid_info *ti,
|
||||
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_chain *ch, struct tid_info *ti,
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user