summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw/tables.c
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2014-07-06 18:16:04 +0000
committermelifaro <melifaro@FreeBSD.org>2014-07-06 18:16:04 +0000
commit0eba52a18ed50103d8112e30498da8550afbcda1 (patch)
tree7bff0187a127e1084163ef2e8b04eca27a28fa75 /sbin/ipfw/tables.c
parentdfa3781d7821c7b942f07ac961bbd4e9354dbcaf (diff)
downloadFreeBSD-src-0eba52a18ed50103d8112e30498da8550afbcda1.zip
FreeBSD-src-0eba52a18ed50103d8112e30498da8550afbcda1.tar.gz
* 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().
Diffstat (limited to 'sbin/ipfw/tables.c')
-rw-r--r--sbin/ipfw/tables.c250
1 files changed, 153 insertions, 97 deletions
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index ad7ea99..670b8ce 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -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);
+ 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);
/*
- * Non-CIDR of FQDN hostname. Ask kernel
- * about given table.
+ * Table does not exist.
+ * Compability layer: try to interpret data as CIDR
+ * before failing.
*/
- error = table_get_info(oh, &xi);
- if (error == ESRCH)
- errx(EX_USAGE, "Table %s does not exist, cannot intuit "
+ 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);
- else if (error != 0)
- errx(EX_OSERR, "Error requesting table %s info",
- oh->ntlv.name);
-
- /* Table found. */
- type = xi.type;
- vtype = xi.vtype;
+ }
}
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,56 +837,52 @@ 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));
- }
+ table_show_entry(i, tent);
+ tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
+ count--;
+ }
+}
- 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);
- }
+static void
+table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
+{
+ char tbuf[128];
+ uint32_t tval;
- xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len);
- count--;
+ 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);
}
}
OpenPOWER on IntegriCloud