* Add "lookup" table functionality to permit userland entry lookups.

* Bump table dump format preserving old ABI.

Kernel size:
* Add IP_FW_TABLE_XFIND to handle "lookup" request from userland.
* Add ta_find_tentry() algorithm callbacks/handlers to support lookups.
* Fully switch to ipfw_obj_tentry for various table dumps:
  algorithms are now required to support the latest (ipfw_obj_tentry) entry
    dump format, the rest is handled by generic dump code.
  IP_FW_TABLE_XLIST opcode version bumped (0 -> 1).
* Eliminate legacy ta_dump_entry algo handler:
  dump_table_entry() converts data from current to legacy format.

Userland side:
* Add "lookup" table parameter.
* Change the way table type is guessed: call table_get_info() first,
  and check value for IPv4/IPv6 type IFF table does not exist.
* Fix table_get_list(): do more tries if supplied buffer is not enough.
* Sparate table_show_entry() from table_show_list().
This commit is contained in:
melifaro 2014-07-06 18:16:04 +00:00
parent dfa3781d78
commit 0eba52a18e
6 changed files with 419 additions and 167 deletions

View File

@ -55,6 +55,7 @@ static int table_flush(ipfw_obj_header *oh);
static int table_destroy(ipfw_obj_header *oh);
static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
static int table_show_info(ipfw_xtable_info *i, void *arg);
static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
@ -64,9 +65,10 @@ static int table_flush_one(ipfw_xtable_info *i, void *arg);
static int table_show_one(ipfw_xtable_info *i, void *arg);
static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh);
static void table_show_list(ipfw_obj_header *oh, int need_header);
static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
char *key, uint8_t *ptype, uint8_t *pvtype);
char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
char *arg, uint8_t type, uint8_t vtype);
@ -99,6 +101,7 @@ static struct _s_x tablecmds[] = {
{ "flush", TOK_FLUSH },
{ "info", TOK_INFO },
{ "list", TOK_LIST },
{ "lookup", TOK_LOOKUP },
{ NULL, 0 }
};
@ -147,7 +150,6 @@ ipfw_table_handler(int ac, char *av[])
if (table_check_name(tablename) == 0) {
table_fill_ntlv(&oh.ntlv, *av, set, 1);
//oh->set = set;
oh.idx = 1;
} else {
if (strcmp(tablename, "all") == 0)
@ -220,6 +222,10 @@ ipfw_table_handler(int ac, char *av[])
err(EX_OSERR, "failed to request tables list");
}
break;
case TOK_LOOKUP:
ac--; av++;
table_lookup(&oh, ac, av);
break;
}
}
@ -238,9 +244,8 @@ static void
table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
{
oh->set = i->set;
oh->idx = 1;
table_fill_ntlv(&oh->ntlv, i->tablename, oh->set, 1);
table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
}
static struct _s_x tablenewcmds[] = {
@ -284,7 +289,6 @@ table_create(ipfw_obj_header *oh, int ac, char *av[])
NEED1("table type required");
val = match_token(tabletypes, *av);
if (val != -1) {
printf("av %s type %d\n", *av, xi.type);
xi.type = val;
ac--; av++;
break;
@ -429,12 +433,17 @@ static int
table_show_one(ipfw_xtable_info *i, void *arg)
{
ipfw_obj_header *oh;
int error;
if ((oh = calloc(1, i->size)) == NULL)
return (ENOMEM);
if (table_get_list(i, oh) == 0)
table_show_list(oh, 1);
if ((error = table_get_list(i, oh)) != 0) {
err(EX_OSERR, "Error requesting table %s list", i->tablename);
return (error);
}
table_show_list(oh, 1);
free(oh);
return (0);
@ -467,7 +476,7 @@ table_do_modify_record(int cmd, ipfw_obj_header *oh,
memcpy(oh + 1, tent, sizeof(*tent));
tent = (ipfw_obj_tentry *)(oh + 1);
if (update != 0)
tent->flags |= IPFW_TF_UPDATE;
tent->head.flags |= IPFW_TF_UPDATE;
tent->head.length = sizeof(ipfw_obj_tentry);
error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
@ -479,6 +488,7 @@ static void
table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
{
ipfw_obj_tentry tent;
ipfw_xtable_info xi;
uint8_t type, vtype;
int cmd;
char *texterr;
@ -490,7 +500,7 @@ table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update
tent.head.length = sizeof(tent);
tent.idx = 1;
tentry_fill_key(oh, &tent, *av, &type, &vtype);
tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
oh->ntlv.type = type;
ac--; av++;
@ -508,6 +518,67 @@ table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update
err(EX_OSERR, "%s", texterr);
}
static int
table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
ipfw_obj_tentry *xtent)
{
char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
ipfw_obj_tentry *tent;
uint8_t type, vtype;
int error;
size_t sz;
memcpy(xbuf, oh, sizeof(*oh));
oh = (ipfw_obj_header *)xbuf;
tent = (ipfw_obj_tentry *)(oh + 1);
memset(tent, 0, sizeof(*tent));
tent->head.length = sizeof(*tent);
tent->idx = 1;
tentry_fill_key(oh, tent, key, &type, &vtype, xi);
oh->ntlv.type = type;
sz = sizeof(xbuf);
if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0)
return (error);
if (sz < sizeof(xbuf))
return (EINVAL);
*xtent = *tent;
return (0);
}
static void
table_lookup(ipfw_obj_header *oh, int ac, char *av[])
{
ipfw_obj_tentry xtent;
ipfw_xtable_info xi;
int error;
if (ac == 0)
errx(EX_USAGE, "address required");
error = table_do_lookup(oh, *av, &xi, &xtent);
switch (error) {
case 0:
break;
case ESRCH:
errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
case ENOENT:
errx(EX_UNAVAILABLE, "Entry %s not found", *av);
case ENOTSUP:
errx(EX_UNAVAILABLE, "Table %s algo does not support "
"\"lookup\" method", oh->ntlv.name);
default:
err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
}
table_show_entry(&xi, &xtent);
}
static void
tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
@ -584,39 +655,43 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
static void
tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
uint8_t *ptype, uint8_t *pvtype)
uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
{
ipfw_xtable_info xi;
uint8_t type, vtype;
int error;
type = 0;
vtype = 0;
/*
* Compability layer. Try to interpret data as CIDR first.
*/
if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
/* OK Prepare and send */
type = IPFW_TABLE_CIDR;
} else {
error = table_get_info(oh, xi);
/*
* Non-CIDR of FQDN hostname. Ask kernel
* about given table.
*/
error = table_get_info(oh, &xi);
if (error == ESRCH)
errx(EX_USAGE, "Table %s does not exist, cannot intuit "
"key type", oh->ntlv.name);
else if (error != 0)
if (error == 0) {
/* Table found. */
type = xi->type;
vtype = xi->vtype;
} else {
if (error != ESRCH)
errx(EX_OSERR, "Error requesting table %s info",
oh->ntlv.name);
/* Table found. */
type = xi.type;
vtype = xi.vtype;
/*
* Table does not exist.
* Compability layer: try to interpret data as CIDR
* before failing.
*/
if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
/* OK Prepare and send */
type = IPFW_TABLE_CIDR;
/*
* XXX: Value type is forced to be u32.
* This should be changed for MFC.
*/
vtype = IPFW_VTYPE_U32;
} else {
/* Inknown key */
errx(EX_USAGE, "Table %s does not exist, cannot guess "
"key type", oh->ntlv.name);
}
}
tentry_fill_key_type(key, tent, type);
@ -629,29 +704,9 @@ static void
tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
uint8_t type, uint8_t vtype)
{
ipfw_xtable_info xi;
int error;
int code;
char *p;
if (vtype == 0) {
/* Format type is unknown, ask kernel */
error = table_get_info(oh, &xi);
if (error == ESRCH) {
/*
* XXX: This one may break some scripts.
* Change this behavior for MFC.
*/
errx(EX_USAGE, "Table %s does not exist. Unable to "
"guess value format.", oh->ntlv.name);
} else if (error != 0)
errx(EX_OSERR, "Error requesting table %s info",
oh->ntlv.name);
vtype = xi.vtype;
}
switch (vtype) {
case IPFW_VTYPE_U32:
tent->value = strtoul(arg, &p, 0);
@ -758,17 +813,22 @@ static int
table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
{
size_t sz;
int error;
int error, c;
table_fill_objheader(oh, i);
sz = i->size;
sz = 0;
for (c = 0; c < 3; c++) {
table_fill_objheader(oh, i);
if (sz < i->size)
sz = i->size;
oh->opheader.version = 1; /* Current version */
oh->opheader.version = 1; /* Current version */
error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz);
if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0)
return (errno);
if (error != ENOMEM)
return (errno);
}
return (0);
return (ENOMEM);
}
/*
@ -777,59 +837,55 @@ table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh)
static void
table_show_list(ipfw_obj_header *oh, int need_header)
{
ipfw_table_xentry *xent;
uint32_t count, tval;
char tbuf[128];
struct in6_addr *addr6;
ipfw_obj_tentry *tent;
uint32_t count;
ipfw_xtable_info *i;
i = (ipfw_xtable_info *)(oh + 1);
xent = (ipfw_table_xentry *)(i + 1);
tent = (ipfw_obj_tentry *)(i + 1);
if (need_header)
printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
count = i->count;
while (count > 0) {
switch (i->type) {
case IPFW_TABLE_CIDR:
/* IPv4 or IPv6 prefixes */
tval = xent->value;
addr6 = &xent->k.addr6;
if ((xent->flags & IPFW_TCF_INET) != 0) {
/* IPv4 address */
inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf,
sizeof(tbuf));
} else {
/* IPv6 address */
inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
}
if (co.do_value_as_ip) {
tval = htonl(tval);
printf("%s/%u %s\n", tbuf, xent->masklen,
inet_ntoa(*(struct in_addr *)&tval));
} else
printf("%s/%u %u\n", tbuf, xent->masklen, tval);
break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
tval = xent->value;
if (co.do_value_as_ip) {
tval = htonl(tval);
printf("%s %s\n", xent->k.iface,
inet_ntoa(*(struct in_addr *)&tval));
} else
printf("%s %u\n", xent->k.iface, tval);
}
xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len);
table_show_entry(i, tent);
tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
count--;
}
}
static void
table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
{
char tbuf[128];
uint32_t tval;
tval = tent->value;
switch (i->type) {
case IPFW_TABLE_CIDR:
/* IPv4 or IPv6 prefixes */
inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
if (co.do_value_as_ip) {
tval = htonl(tval);
printf("%s/%u %s\n", tbuf, tent->masklen,
inet_ntoa(*(struct in_addr *)&tval));
} else
printf("%s/%u %u\n", tbuf, tent->masklen, tval);
break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
if (co.do_value_as_ip) {
tval = htonl(tval);
printf("%s %s\n", tent->k.iface,
inet_ntoa(*(struct in_addr *)&tval));
} else
printf("%s %u\n", tent->k.iface, tval);
}
}
int
compare_ntlv(const void *_a, const void *_b)
{

View File

@ -89,6 +89,7 @@ typedef struct _ip_fw3_opheader {
//#define IP_FW_TABLE_XMODIFY 96 /* modify existing table */
#define IP_FW_XGET 97 /* Retrieve configuration */
#define IP_FW_XADD 98 /* add entry */
#define IP_FW_TABLE_XFIND 99 /* finds an entry */
/*
* Usage guidelines:
@ -713,10 +714,8 @@ typedef struct _ipfw_obj_tentry {
uint8_t subtype; /* subtype (IPv4,IPv6) */
uint8_t masklen; /* mask length */
uint16_t idx; /* Table name index */
uint16_t flags; /* Entry flags */
uint16_t spare0;
uint32_t spare1;
uint32_t value; /* value */
uint64_t spare;
union {
/* Longest field needs to be aligned by 8-byte boundary */
struct in_addr addr; /* IPv4 address */
@ -751,7 +750,7 @@ typedef struct _ipfw_xtable_info {
#define IPFW_OBJTYPE_TABLE 1
typedef struct _ipfw_obj_header {
ip_fw3_opheader opheader; /* IP_FW3 opcode */
uint32_t set; /* Set we're operating */
uint32_t spare;
uint16_t idx; /* object name index */
uint8_t objtype; /* object type */
uint8_t objsubtype; /* object subtype */

View File

@ -1726,6 +1726,9 @@ ipfw_ctl(struct sockopt *sopt)
case IP_FW_TABLE_XDEL: /* IP_FW3 */
error = ipfw_modify_table(chain, op3, &sdata);
break;
case IP_FW_TABLE_XFIND: /* IP_FW3 */
error = ipfw_find_table_entry(chain, op3, &sdata);
break;
/*--- LEGACY API ---*/
case IP_FW_TABLE_ADD:

View File

@ -105,6 +105,7 @@ static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
struct sockopt_data *sd);
static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
ipfw_xtable_info *i);
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);
@ -406,19 +407,18 @@ ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
tent->head.length + read > sd->valsize)
return (EINVAL);
/* Convert data into kernel request objects */
memset(&tei, 0, sizeof(tei));
tei.paddr = &tent->k;
tei.subtype = tent->subtype;
tei.masklen = tent->masklen;
if (tent->flags & IPFW_TF_UPDATE)
if (tent->head.flags & IPFW_TF_UPDATE)
tei.flags |= TEI_FLAGS_UPDATE;
tei.value = tent->value;
memset(&ti, 0, sizeof(ti));
ti.uidx = tent->idx;
objheader_to_ti(oh, &ti);
ti.type = oh->ntlv.type;
ti.tlvs = &oh->ntlv;
ti.tlen = oh->ntlv.head.length;
ti.uidx = tent->idx;
error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
add_table_entry(ch, &ti, &tei) :
@ -427,6 +427,101 @@ ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
return (error);
}
/*
* Looks up an entry in given table.
* Data layout (v0)(current):
* Request: [ ipfw_obj_header ipfw_obj_tentry ]
* Reply: [ ipfw_obj_header ipfw_obj_tentry ]
*
* Returns 0 on success
*/
int
ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd)
{
ipfw_obj_tentry *tent;
ipfw_obj_header *oh;
struct tid_info ti;
struct table_config *tc;
struct table_algo *ta;
struct table_info *kti;
struct namedobj_instance *ni;
int error, plen;
void *paddr;
size_t sz;
/* Check minimum header size */
sz = sizeof(*oh) + sizeof(*tent);
if (sd->valsize != sz)
return (EINVAL);
oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
tent = (ipfw_obj_tentry *)(oh + 1);
/* Basic length checks for TLVs */
if (oh->ntlv.head.length != sizeof(oh->ntlv))
return (EINVAL);
objheader_to_ti(oh, &ti);
ti.type = oh->ntlv.type;
ti.uidx = tent->idx;
IPFW_UH_RLOCK(ch);
ni = CHAIN_TO_NI(ch);
/*
* Find existing table and check its type .
*/
ta = NULL;
if ((tc = find_table(ni, &ti)) == NULL) {
IPFW_UH_RUNLOCK(ch);
return (ESRCH);
}
/* check table type */
if (tc->no.type != ti.type) {
IPFW_UH_RUNLOCK(ch);
return (EINVAL);
}
/* Check lookup key for validness */
plen = 0;
paddr = &tent->k;
switch (ti.type)
{
case IPFW_TABLE_CIDR:
if (tent->subtype == AF_INET)
plen = sizeof(struct in_addr);
else if (tent->subtype == AF_INET6)
plen = sizeof(struct in6_addr);
else {
IPFW_UH_RUNLOCK(ch);
return (EINVAL);
}
break;
case IPFW_TABLE_INTERFACE:
/* Check key first */
plen = sizeof(tent->k.iface);
if (strnlen(tent->k.iface, plen) == plen) {
IPFW_UH_RUNLOCK(ch);
return (EINVAL);
}
break;
default:
IPFW_UH_RUNLOCK(ch);
return (ENOTSUP);
}
kti = KIDX_TO_TI(ch, tc->no.kidx);
ta = tc->ta;
error = ta->find_tentry(tc->astate, kti, paddr, plen, tent);
IPFW_UH_RUNLOCK(ch);
return (error);
}
int
ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd)
@ -807,8 +902,10 @@ struct dump_args {
struct sockopt_data *sd;
uint32_t cnt;
uint16_t uidx;
int error;
ipfw_table_entry *ent;
uint32_t size;
ipfw_obj_tentry tent;
};
int
@ -835,7 +932,7 @@ ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
* Dumps all table data
* Data layout (v1)(current):
* Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
* Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_table_xentry x N ]
* Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
*
* Returns 0 on success
*/
@ -866,7 +963,7 @@ ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
export_table_info(ch, tc, i);
sz = tc->count;
if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) {
if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) {
/*
* Submitted buffer size is not enough.
@ -888,10 +985,10 @@ ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
ta = tc->ta;
ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
IPFW_UH_RUNLOCK(ch);
return (0);
return (da.error);
}
/*
@ -1045,7 +1142,7 @@ objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
{
memset(ti, 0, sizeof(struct tid_info));
ti->set = oh->set;
ti->set = oh->ntlv.set;
ti->uidx = oh->idx;
ti->tlvs = &oh->ntlv;
ti->tlen = oh->ntlv.head.length;
@ -1088,7 +1185,7 @@ export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
i->kidx = tc->no.kidx;
i->refcnt = tc->no.refcnt;
i->count = tc->count;
i->size = tc->count * sizeof(ipfw_table_xentry);
i->size = tc->count * sizeof(ipfw_obj_tentry);
i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
if (tc->ta->print_config != NULL) {
@ -1155,6 +1252,9 @@ export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
return (0);
}
/*
* Legacy IP_FW_TABLE_GETSIZE handler
*/
int
ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
{
@ -1167,6 +1267,9 @@ ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
}
/*
* Legacy IP_FW_TABLE_XGETSIZE handler
*/
int
ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
{
@ -1189,6 +1292,7 @@ dump_table_entry(void *e, void *arg)
struct table_config *tc;
struct table_algo *ta;
ipfw_table_entry *ent;
int error;
da = (struct dump_args *)arg;
@ -1202,7 +1306,15 @@ dump_table_entry(void *e, void *arg)
ent->tbl = da->uidx;
da->cnt++;
return (ta->dump_entry(tc->astate, da->ti, e, ent));
error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
if (error != 0)
return (error);
ent->addr = da->tent.k.addr.s_addr;
ent->masklen = da->tent.masklen;
ent->value = da->tent.value;
return (0);
}
/*
@ -1223,8 +1335,9 @@ ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
ta = tc->ta;
if (ta->dump_entry == NULL)
return (0); /* Legacy dump support is not necessary */
/* This dump format supports IPv4 only */
if (tc->no.type != IPFW_TABLE_CIDR)
return (0);
memset(&da, 0, sizeof(da));
da.ti = KIDX_TO_TI(ch, tc->no.kidx);
@ -1240,7 +1353,35 @@ ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
}
/*
* Dumps table entry in eXtended format (current).
* Dumps table entry in eXtended format (v1)(current).
*/
static int
dump_table_tentry(void *e, void *arg)
{
struct dump_args *da;
struct table_config *tc;
struct table_algo *ta;
ipfw_obj_tentry *tent;
da = (struct dump_args *)arg;
tc = da->tc;
ta = tc->ta;
tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent));
/* Out of memory, returning */
if (tent == NULL) {
da->error = ENOMEM;
return (1);
}
tent->head.length = sizeof(ipfw_obj_tentry);
tent->idx = da->uidx;
return (ta->dump_tentry(tc->astate, da->ti, e, tent));
}
/*
* Dumps table entry in eXtended format (v0).
*/
static int
dump_table_xentry(void *e, void *arg)
@ -1249,6 +1390,8 @@ dump_table_xentry(void *e, void *arg)
struct table_config *tc;
struct table_algo *ta;
ipfw_table_xentry *xent;
ipfw_obj_tentry *tent;
int error;
da = (struct dump_args *)arg;
@ -1262,7 +1405,23 @@ dump_table_xentry(void *e, void *arg)
xent->len = sizeof(ipfw_table_xentry);
xent->tbl = da->uidx;
return (ta->dump_xentry(tc->astate, da->ti, e, xent));
memset(&da->tent, 0, sizeof(da->tent));
tent = &da->tent;
error = ta->dump_tentry(tc->astate, da->ti, e, tent);
if (error != 0)
return (error);
/* Convert current format to previous one */
xent->masklen = tent->masklen;
xent->value = tent->value;
/* Apply some hacks */
if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) {
xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
xent->flags = IPFW_TCF_INET;
} else
memcpy(&xent->k, &tent->k, sizeof(xent->k));
return (0);
}
/*

View File

@ -77,10 +77,10 @@ typedef void (ta_print_config)(void *ta_state, struct table_info *ti, char *buf,
typedef int ta_foreach_f(void *node, void *arg);
typedef void ta_foreach(void *ta_state, struct table_info *ti, ta_foreach_f *f,
void *arg);
typedef int ta_dump_entry(void *ta_state, struct table_info *ti, void *e,
ipfw_table_entry *ent);
typedef int ta_dump_xentry(void *ta_state, struct table_info *ti, void *e,
ipfw_table_xentry *xent);
typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
ipfw_obj_tentry *tent);
typedef int ta_find_tentry(void *ta_state, struct table_info *ti, void *key,
uint32_t keylen, ipfw_obj_tentry *tent);
struct table_algo {
char name[16];
@ -94,9 +94,9 @@ struct table_algo {
ta_del *del;
ta_flush_entry *flush_entry;
ta_foreach *foreach;
ta_dump_entry *dump_entry;
ta_dump_xentry *dump_xentry;
ta_dump_tentry *dump_tentry;
ta_print_config *print_config;
ta_find_tentry *find_tentry;
};
void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
extern struct table_algo radix_cidr, radix_iface;
@ -112,6 +112,8 @@ 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, 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,

View File

@ -208,30 +208,8 @@ ta_destroy_radix(void *ta_state, struct table_info *ti)
}
static int
ta_dump_radix_entry(void *ta_state, struct table_info *ti, void *e,
ipfw_table_entry *ent)
{
struct table_entry *n;
n = (struct table_entry *)e;
/* Guess IPv4/IPv6 radix by sockaddr family */
if (n->addr.sin_family != AF_INET)
return (0);
if (in_nullhost(n->mask.sin_addr))
ent->masklen = 0;
else
ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
ent->addr = n->addr.sin_addr.s_addr;
ent->value = n->value;
return (0);
}
static int
ta_dump_radix_xentry(void *ta_state, struct table_info *ti, void *e,
ipfw_table_xentry *xent)
ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
ipfw_obj_tentry *tent)
{
struct table_entry *n;
struct table_xentry *xn;
@ -245,28 +223,59 @@ ta_dump_radix_xentry(void *ta_state, struct table_info *ti, void *e,
/* Guess IPv4/IPv6 radix by sockaddr family */
if (n->addr.sin_family == AF_INET) {
if (in_nullhost(n->mask.sin_addr))
xent->masklen = 0;
tent->masklen = 0;
else
xent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr));
tent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr));
/* Save IPv4 address as deprecated IPv6 compatible */
xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
xent->flags = IPFW_TCF_INET;
xent->value = n->value;
tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
tent->subtype = AF_INET;
tent->value = n->value;
#ifdef INET6
} else {
xn = (struct table_xentry *)e;
/* Count IPv6 mask */
v = (uint32_t *)&xn->m.mask6.sin6_addr;
for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++)
xent->masklen += bitcount32(*v);
memcpy(&xent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr));
xent->value = xn->value;
tent->masklen += bitcount32(*v);
memcpy(&tent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr));
tent->subtype = AF_INET6;
tent->value = xn->value;
#endif
}
return (0);
}
static int
ta_find_radix_tentry(void *ta_state, struct table_info *ti, void *key,
uint32_t keylen, ipfw_obj_tentry *tent)
{
struct radix_node_head *rnh;
void *e;
e = NULL;
if (keylen == sizeof(in_addr_t)) {
struct sockaddr_in sa;
KEY_LEN(sa) = KEY_LEN_INET;
sa.sin_addr.s_addr = *((in_addr_t *)key);
rnh = (struct radix_node_head *)ti->state;
e = rnh->rnh_matchaddr(&sa, rnh);
} else {
struct sockaddr_in6 sa6;
KEY_LEN(sa6) = KEY_LEN_INET6;
memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
rnh = (struct radix_node_head *)ti->xstate;
e = rnh->rnh_matchaddr(&sa6, rnh);
}
if (e != NULL) {
ta_dump_radix_tentry(ta_state, ti, e, tent);
return (0);
}
return (ENOENT);
}
static void
ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
void *arg)
@ -495,7 +504,7 @@ ta_del_cidr(void *ta_state, struct table_info *ti,
tb->ent_ptr = rn;
if (rn == NULL)
return (ESRCH);
return (ENOENT);
return (0);
}
@ -522,8 +531,8 @@ struct table_algo radix_cidr = {
.del = ta_del_cidr,
.flush_entry = ta_flush_cidr_entry,
.foreach = ta_foreach_radix,
.dump_entry = ta_dump_radix_entry,
.dump_xentry = ta_dump_radix_xentry,
.dump_tentry = ta_dump_radix_tentry,
.find_tentry = ta_find_radix_tentry,
};
@ -724,7 +733,7 @@ ta_del_iface(void *ta_state, struct table_info *ti,
tb->ent_ptr = rn;
if (rn == NULL)
return (ESRCH);
return (ENOENT);
return (0);
}
@ -741,19 +750,42 @@ ta_flush_iface_entry(struct tentry_info *tei, void *ta_buf)
}
static int
ta_dump_iface_xentry(void *ta_state, struct table_info *ti, void *e,
ipfw_table_xentry *xent)
ta_dump_iface_tentry(void *ta_state, struct table_info *ti, void *e,
ipfw_obj_tentry *tent)
{
struct table_xentry *xn;
xn = (struct table_xentry *)e;
xent->masklen = 8 * IF_NAMESIZE;
memcpy(&xent->k, &xn->a.iface.ifname, IF_NAMESIZE);
xent->value = xn->value;
tent->masklen = 8 * IF_NAMESIZE;
memcpy(&tent->k, &xn->a.iface.ifname, IF_NAMESIZE);
tent->value = xn->value;
return (0);
}
static int
ta_find_iface_tentry(void *ta_state, struct table_info *ti, void *key,
uint32_t keylen, ipfw_obj_tentry *tent)
{
struct radix_node_head *rnh;
struct xaddr_iface iface;
void *e;
e = NULL;
KEY_LEN(iface) = KEY_LEN_IFACE +
strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1;
rnh = (struct radix_node_head *)ti->xstate;
e = rnh->rnh_matchaddr(&iface, rnh);
if (e != NULL) {
ta_dump_iface_tentry(ta_state, ti, e, tent);
return (0);
}
return (ENOENT);
}
static void
ta_foreach_iface(void *ta_state, struct table_info *ti, ta_foreach_f *f,
void *arg)
@ -775,7 +807,8 @@ struct table_algo radix_iface = {
.del = ta_del_iface,
.flush_entry = ta_flush_iface_entry,
.foreach = ta_foreach_iface,
.dump_xentry = ta_dump_iface_xentry,
.dump_tentry = ta_dump_iface_tentry,
.find_tentry = ta_find_iface_tentry,
};
void