* 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:
parent
dfa3781d78
commit
0eba52a18e
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user