summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw/tables.c
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2014-07-03 22:25:59 +0000
committermelifaro <melifaro@FreeBSD.org>2014-07-03 22:25:59 +0000
commit99023231d3e6ab3f80cecab0626d12352069bedf (patch)
tree698d237c2de20d6a6adb97f520a6f5a63853b737 /sbin/ipfw/tables.c
parent75913dd997a81341ee4e07a64ff5f6d7ccec1d2b (diff)
downloadFreeBSD-src-99023231d3e6ab3f80cecab0626d12352069bedf.zip
FreeBSD-src-99023231d3e6ab3f80cecab0626d12352069bedf.tar.gz
Fully switch to named tables:
Kernel changes: * Introduce ipfw_obj_tentry table entry structure to force u64 alignment. * Support "update-on-existing-key" "add" bahavior (TEI_FLAGS_UPDATED). * Use "subtype" field to distingush between IPv4 and IPv6 table records instead of previous hack. * Add value type (vtype) field for kernel tables. Current types are number,ip and dscp * Fix sets mask retrieval for old binaries * Fix crash while using interface tables Userland changes: * Switch ipfw_table_handler() to use named-only tables. * Add "table NAME create [type {cidr|iface|u32} [valtype {number|ip|dscp}] ..." * Switch ipfw_table_handler to match_token()-based parser. * Switch ipfw_sets_handler to use new ipfw_get_config() for mask retrieval. * Allow ipfw set X table ... syntax to permit using per-set table namespaces.
Diffstat (limited to 'sbin/ipfw/tables.c')
-rw-r--r--sbin/ipfw/tables.c700
1 files changed, 469 insertions, 231 deletions
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index e34b140..ad7ea99 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -49,18 +49,27 @@
#include "ipfw2.h"
static void table_list(ipfw_xtable_info *i, int need_header);
-static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
-static int table_flush(char *name, uint32_t set);
-static int table_destroy(char *name, uint32_t set);
-static int table_get_info(char *name, uint32_t set, ipfw_xtable_info *i);
+static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
+ int add, int update);
+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 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, uint16_t uidx);
+static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
+ uint16_t uidx);
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 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
+ char *key, uint8_t *ptype, uint8_t *pvtype);
+static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
+ char *arg, uint8_t type, uint8_t vtype);
+
typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
static int tables_foreach(table_cb_t *f, void *arg, int sort);
@@ -68,6 +77,31 @@ static int tables_foreach(table_cb_t *f, void *arg, int sort);
#define s6_addr32 __u6_addr.__u6_addr32
#endif
+static struct _s_x tabletypes[] = {
+ { "cidr", IPFW_TABLE_CIDR },
+ { "iface", IPFW_TABLE_INTERFACE },
+ { "u32", IPFW_TABLE_U32 },
+ { NULL, 0 }
+};
+
+static struct _s_x tablevaltypes[] = {
+ { "dscp", IPFW_VTYPE_DSCP },
+ { "ip", IPFW_VTYPE_IP },
+ { "number", IPFW_VTYPE_U32 },
+ { NULL, 0 }
+};
+
+static struct _s_x tablecmds[] = {
+ { "add", TOK_ADD },
+ { "create", TOK_CREATE },
+ { "delete", TOK_DEL },
+ { "destroy", TOK_DESTROY },
+ { "flush", TOK_FLUSH },
+ { "info", TOK_INFO },
+ { "list", TOK_LIST },
+ { NULL, 0 }
+};
+
static int
lookup_host (char *host, struct in_addr *ipaddr)
{
@@ -83,305 +117,280 @@ lookup_host (char *host, struct in_addr *ipaddr)
/*
* This one handles all table-related commands
- * ipfw table N add addr[/masklen] [value]
- * ipfw table N delete addr[/masklen]
- * ipfw table {N | all} flush
- * ipfw table {N | all} list
- * ipfw table {N | all} info
+ * ipfw table NAME create ...
+ * ipfw table NAME destroy
+ * ipfw table NAME add addr[/masklen] [value]
+ * ipfw table NAME delete addr[/masklen]
+ * ipfw table {NAME | all} flush
+ * ipfw table {NAME | all} list
+ * ipfw table {NAME | all} info
*/
void
ipfw_table_handler(int ac, char *av[])
{
- ipfw_table_xentry *xent;
- int do_add;
- int is_all;
- uint32_t set;
- int error;
- char xbuf[sizeof(ip_fw3_opheader) + sizeof(ipfw_table_xentry)];
- ip_fw3_opheader *op3;
+ int do_add, is_all;
+ int error, tcmd;
+ ipfw_xtable_info i;
+ ipfw_obj_header oh;
char *tablename;
+ uint32_t set;
- memset(xbuf, 0, sizeof(xbuf));
- op3 = (ip_fw3_opheader *)xbuf;
- xent = (ipfw_table_xentry *)(op3 + 1);
+ memset(&oh, 0, sizeof(oh));
+ is_all = 0;
+ if (co.use_set != 0)
+ set = co.use_set - 1;
+ else
+ set = 0;
ac--; av++;
tablename = *av;
- set = 0;
- if (ac && isdigit(**av)) {
- xent->tbl = atoi(*av);
- is_all = 0;
- ac--; av++;
- } else if (ac && _substrcmp(*av, "all") == 0) {
- xent->tbl = 0;
- is_all = 1;
- ac--; av++;
- } else
- errx(EX_USAGE, "table number or 'all' keyword required");
+
+ 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)
+ is_all = 1;
+ else
+ errx(EX_USAGE, "table name %s is invalid", tablename);
+ }
+ ac--; av++;
+
+ if ((tcmd = match_token(tablecmds, *av)) == -1)
+ errx(EX_USAGE, "invalid table command %s", *av);
+
NEED1("table needs command");
- if (is_all && _substrcmp(*av, "list") != 0
- && _substrcmp(*av, "info") != 0
- && _substrcmp(*av, "flush") != 0)
- errx(EX_USAGE, "table number required");
+ switch (tcmd) {
+ case TOK_LIST:
+ case TOK_INFO:
+ case TOK_FLUSH:
+ break;
+ default:
+ if (is_all != 0)
+ errx(EX_USAGE, "table name required");
+ }
- if (_substrcmp(*av, "add") == 0 ||
- _substrcmp(*av, "delete") == 0) {
+ switch (tcmd) {
+ case TOK_ADD:
+ case TOK_DEL:
do_add = **av == 'a';
ac--; av++;
- if (!ac)
- errx(EX_USAGE, "address required");
-
- table_fill_xentry(*av, xent);
-
+ table_modify_record(&oh, ac, av, do_add, co.do_quiet);
+ break;
+ case TOK_CREATE:
ac--; av++;
- if (do_add && ac) {
- unsigned int tval;
- /* isdigit is a bit of a hack here.. */
- if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
- xent->value = strtoul(*av, NULL, 0);
- } else {
- if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
- /* The value must be stored in host order *
- * so that the values < 65k can be distinguished */
- xent->value = ntohl(tval);
- } else {
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
- }
- }
- } else
- xent->value = 0;
- if (do_set3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL,
- op3, sizeof(xbuf)) < 0) {
- /* If running silent, don't bomb out on these errors. */
- if (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH))))
- err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)",
- do_add ? "XADD" : "XDEL");
- /* In silent mode, react to a failed add by deleting */
- if (do_add) {
- do_set3(IP_FW_TABLE_XDEL, op3, sizeof(xbuf));
- if (do_set3(IP_FW_TABLE_XADD, op3, sizeof(xbuf)) < 0)
- err(EX_OSERR,
- "setsockopt(IP_FW_TABLE_XADD)");
- }
- }
- } else if (_substrcmp(*av, "flush") == 0) {
+ table_create(&oh, ac, av);
+ break;
+ case TOK_DESTROY:
+ if (table_destroy(&oh) != 0)
+ err(EX_OSERR, "failed to destroy table %s", tablename);
+ break;
+ case TOK_FLUSH:
if (is_all == 0) {
- if ((error = table_flush(tablename, set)) != 0)
+ if ((error = table_flush(&oh)) != 0)
err(EX_OSERR, "failed to flush table %s info",
tablename);
} else {
- error = tables_foreach(table_flush_one, NULL, 1);
+ error = tables_foreach(table_flush_one, &oh, 1);
if (error != 0)
err(EX_OSERR, "failed to flush tables list");
}
- } else if (_substrcmp(*av, "list") == 0) {
+ break;
+ case TOK_INFO:
if (is_all == 0) {
- ipfw_xtable_info i;
- if ((error = table_get_info(tablename, set, &i)) != 0)
+ if ((error = table_get_info(&oh, &i)) != 0)
err(EX_OSERR, "failed to request table info");
- table_show_one(&i, NULL);
+ table_show_info(&i, NULL);
} else {
- error = tables_foreach(table_show_one, NULL, 1);
+ error = tables_foreach(table_show_info, NULL, 1);
if (error != 0)
err(EX_OSERR, "failed to request tables list");
}
- } else if (_substrcmp(*av, "destroy") == 0) {
- if (table_destroy(tablename, set) != 0)
- err(EX_OSERR, "failed to destroy table %s", tablename);
- } else if (_substrcmp(*av, "info") == 0) {
+ break;
+ case TOK_LIST:
if (is_all == 0) {
ipfw_xtable_info i;
- if ((error = table_get_info(tablename, set, &i)) != 0)
+ if ((error = table_get_info(&oh, &i)) != 0)
err(EX_OSERR, "failed to request table info");
- table_show_info(&i, NULL);
+ table_show_one(&i, NULL);
} else {
- error = tables_foreach(table_show_info, NULL, 1);
+ error = tables_foreach(table_show_one, NULL, 1);
if (error != 0)
err(EX_OSERR, "failed to request tables list");
}
- } else
- errx(EX_USAGE, "invalid table command %s", *av);
+ break;
+ }
}
static void
-table_fill_xentry(char *arg, ipfw_table_xentry *xent)
+table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
{
- int addrlen, mask, masklen, type;
- struct in6_addr *paddr;
- uint32_t *pkey;
- char *p;
- uint32_t key;
- mask = 0;
- type = 0;
- addrlen = 0;
- masklen = 0;
+ ntlv->head.type = IPFW_TLV_TBL_NAME;
+ ntlv->head.length = sizeof(ipfw_obj_ntlv);
+ ntlv->idx = uidx;
+ ntlv->set = set;
+ strlcpy(ntlv->name, name, sizeof(ntlv->name));
+}
- /*
- * Let's try to guess type by agrument.
- * Possible types:
- * 1) IPv4[/mask]
- * 2) IPv6[/mask]
- * 3) interface name
- * 4) port, uid/gid or other u32 key (base 10 format)
- * 5) hostname
- */
- paddr = &xent->k.addr6;
- if (ishexnumber(*arg) != 0 || *arg == ':') {
- /* Remove / if exists */
- if ((p = strchr(arg, '/')) != NULL) {
- *p = '\0';
- mask = atoi(p + 1);
- }
+static void
+table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
+{
- if (inet_pton(AF_INET, arg, paddr) == 1) {
- if (p != NULL && mask > 32)
- errx(EX_DATAERR, "bad IPv4 mask width: %s",
- p + 1);
+ oh->set = i->set;
+ oh->idx = 1;
+ table_fill_ntlv(&oh->ntlv, i->tablename, oh->set, 1);
+}
- type = IPFW_TABLE_CIDR;
- masklen = p ? mask : 32;
- addrlen = sizeof(struct in_addr);
- } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
- if (IN6_IS_ADDR_V4COMPAT(paddr))
- errx(EX_DATAERR,
- "Use IPv4 instead of v4-compatible");
- if (p != NULL && mask > 128)
- errx(EX_DATAERR, "bad IPv6 mask width: %s",
- p + 1);
+static struct _s_x tablenewcmds[] = {
+ { "type", TOK_TYPE},
+ { "valtype", TOK_VALTYPE },
+ { "algo", TOK_ALGO },
+ { NULL, 0 }
+};
- type = IPFW_TABLE_CIDR;
- masklen = p ? mask : 128;
- addrlen = sizeof(struct in6_addr);
- } else {
- /* Port or any other key */
- /* Skip non-base 10 entries like 'fa1' */
- key = strtol(arg, &p, 10);
- if (*p == '\0') {
- pkey = (uint32_t *)paddr;
- *pkey = htonl(key);
- type = IPFW_TABLE_CIDR;
- masklen = 32;
- addrlen = sizeof(uint32_t);
- } else if ((p != arg) && (*p == '.')) {
- /*
- * Warn on IPv4 address strings
- * which are "valid" for inet_aton() but not
- * in inet_pton().
- *
- * Typical examples: '10.5' or '10.0.0.05'
- */
- errx(EX_DATAERR,
- "Invalid IPv4 address: %s", arg);
- }
- }
- }
+/*
+ * Creates new table
+ *
+ * ipfw table NAME create [ type { cidr | iface | u32 } ]
+ * [ valtype { number | ip | dscp } ]
+ * [ algo algoname ]
+ *
+ * Request: [ ipfw_obj_header ipfw_xtable_info ]
+ */
+static void
+table_create(ipfw_obj_header *oh, int ac, char *av[])
+{
+ ipfw_xtable_info xi;
+ int error, tcmd, val;
+ size_t sz;
+ char tbuf[128];
- if (type == 0 && strchr(arg, '.') == NULL) {
- /* Assume interface name. Copy significant data only */
- mask = MIN(strlen(arg), IF_NAMESIZE - 1);
- memcpy(xent->k.iface, arg, mask);
- /* Set mask to exact match */
- masklen = 8 * IF_NAMESIZE;
- type = IPFW_TABLE_INTERFACE;
- addrlen = IF_NAMESIZE;
- }
+ sz = sizeof(tbuf);
+ memset(&xi, 0, sizeof(xi));
- if (type == 0) {
- if (lookup_host(arg, (struct in_addr *)paddr) != 0)
- errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
+ /* Set some defaults to preserve compability */
+ xi.type = IPFW_TABLE_CIDR;
+ xi.vtype = IPFW_VTYPE_U32;
- masklen = 32;
- type = IPFW_TABLE_CIDR;
- addrlen = sizeof(struct in_addr);
+ while (ac > 0) {
+ if ((tcmd = match_token(tablenewcmds, *av)) == -1)
+ errx(EX_USAGE, "unknown option: %s", *av);
+ ac--; av++;
+
+ switch (tcmd) {
+ case TOK_TYPE:
+ 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;
+ }
+ concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", ");
+ errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s",
+ *av, tbuf);
+ break;
+ case TOK_VALTYPE:
+ NEED1("table value type required");
+ val = match_token(tablevaltypes, *av);
+ if (val != -1) {
+ xi.vtype = val;
+ ac--; av++;
+ break;
+ }
+ concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
+ errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
+ *av, tbuf);
+ break;
+ case TOK_ALGO:
+ NEED1("table algorithm name required");
+ if (strlen(*av) > sizeof(xi.algoname))
+ errx(EX_USAGE, "algorithm name too long");
+ strlcpy(xi.algoname, *av, sizeof(xi.algoname));
+ ac--; av++;
+ break;
+ }
}
- xent->type = type;
- xent->masklen = masklen;
- xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+ if ((error = table_do_create(oh, &xi)) != 0)
+ err(EX_OSERR, "Table creation failed");
}
-static void
-table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx)
+/*
+ * Creates new table
+ *
+ * Request: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * Returns 0 on success.
+ */
+static int
+table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
{
+ char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
+ int error;
- ntlv->head.type = IPFW_TLV_TBL_NAME;
- ntlv->head.length = sizeof(ipfw_obj_ntlv);
- ntlv->idx = uidx;
- strlcpy(ntlv->name, name, sizeof(ntlv->name));
-}
+ memcpy(tbuf, oh, sizeof(*oh));
+ memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
+ oh = (ipfw_obj_header *)tbuf;
-static void
-table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
-{
+ error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
- oh->set = i->set;
- oh->idx = 1;
- table_fill_ntlv(&oh->ntlv, i->tablename, 1);
+ return (error);
}
/*
- * Destroys given table @name in given @set.
+ * Destroys given table specified by @oh->ntlv.
* Returns 0 on success.
*/
static int
-table_destroy(char *name, uint32_t set)
+table_destroy(ipfw_obj_header *oh)
{
- ipfw_obj_header oh;
- memset(&oh, 0, sizeof(oh));
- oh.idx = 1;
- table_fill_ntlv(&oh.ntlv, name, 1);
- if (do_set3(IP_FW_TABLE_XDESTROY, &oh.opheader, sizeof(oh)) != 0)
+ if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
return (-1);
return (0);
}
/*
- * Flushes given table @name in given @set.
+ * Flushes given table specified by @oh->ntlv.
* Returns 0 on success.
*/
static int
-table_flush(char *name, uint32_t set)
+table_flush(ipfw_obj_header *oh)
{
- ipfw_obj_header oh;
- memset(&oh, 0, sizeof(oh));
- oh.idx = 1;
- table_fill_ntlv(&oh.ntlv, name, 1);
- if (do_set3(IP_FW_TABLE_XFLUSH, &oh.opheader, sizeof(oh)) != 0)
+ if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
return (-1);
return (0);
}
/*
- * Retrieves info for given table @name in given @set and stores
+ * Retrieves table in given table specified by @oh->ntlv.
* it inside @i.
* Returns 0 on success.
*/
static int
-table_get_info(char *name, uint32_t set, ipfw_xtable_info *i)
+table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
{
- char tbuf[sizeof(ipfw_obj_header)+sizeof(ipfw_xtable_info)];
- ipfw_obj_header *oh;
+ char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
+ int error;
size_t sz;
sz = sizeof(tbuf);
memset(tbuf, 0, sizeof(tbuf));
+ memcpy(tbuf, oh, sizeof(*oh));
oh = (ipfw_obj_header *)tbuf;
- i->set = set;
- strlcpy(i->tablename, name, sizeof(i->tablename));
-
- table_fill_objheader(oh, i);
-
- if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) < 0)
- return (-1);
+ if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0)
+ return (error);
if (sz < sizeof(tbuf))
- return (-1);
+ return (EINVAL);
*i = *(ipfw_xtable_info *)(oh + 1);
@@ -394,21 +403,16 @@ table_get_info(char *name, uint32_t set, ipfw_xtable_info *i)
static int
table_show_info(ipfw_xtable_info *i, void *arg)
{
- char *type;
+ const char *ttype, *vtype;
printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
- switch (i->type) {
- case IPFW_TABLE_CIDR:
- type = "cidr";
- break;
- case IPFW_TABLE_INTERFACE:
- type = "iface";
- break;
- default:
- type = "unknown";
- }
- printf(" type: %s, kindex: %d\n", type, i->kidx);
- printf(" ftype: %d, algorithm: %d\n", i->ftype, i->atype);
+ if ((ttype = match_value(tabletypes, i->type)) == NULL)
+ ttype = "unknown";
+ if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
+ vtype = "unknown";
+
+ printf(" type: %s, kindex: %d\n", ttype, i->kidx);
+ printf(" valtype: %s, algorithm: %s\n", vtype, i->algoname);
printf(" references: %u\n", i->refcnt);
printf(" items: %u, size: %u\n", i->count, i->size);
@@ -426,7 +430,7 @@ table_show_one(ipfw_xtable_info *i, void *arg)
{
ipfw_obj_header *oh;
- if ((oh = malloc(i->size)) == NULL)
+ if ((oh = calloc(1, i->size)) == NULL)
return (ENOMEM);
if (table_get_list(i, oh) == 0)
@@ -439,10 +443,243 @@ table_show_one(ipfw_xtable_info *i, void *arg)
static int
table_flush_one(ipfw_xtable_info *i, void *arg)
{
+ ipfw_obj_header *oh;
+
+ oh = (ipfw_obj_header *)arg;
+
+ table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
+
+ return (table_flush(oh));
+}
+
+static int
+table_do_modify_record(int cmd, ipfw_obj_header *oh,
+ ipfw_obj_tentry *tent, int update)
+{
+ char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
+ int error;
+
+ memset(xbuf, 0, sizeof(xbuf));
+ memcpy(xbuf, oh, sizeof(*oh));
+ oh = (ipfw_obj_header *)xbuf;
+ oh->opheader.version = 1;
+
+ memcpy(oh + 1, tent, sizeof(*tent));
+ tent = (ipfw_obj_tentry *)(oh + 1);
+ if (update != 0)
+ tent->flags |= IPFW_TF_UPDATE;
+ tent->head.length = sizeof(ipfw_obj_tentry);
+
+ error = do_set3(cmd, &oh->opheader, sizeof(xbuf));
+
+ return (error);
+}
+
+static void
+table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update)
+{
+ ipfw_obj_tentry tent;
+ uint8_t type, vtype;
+ int cmd;
+ char *texterr;
+
+ if (ac == 0)
+ errx(EX_USAGE, "address required");
+
+ memset(&tent, 0, sizeof(tent));
+ tent.head.length = sizeof(tent);
+ tent.idx = 1;
+
+ tentry_fill_key(oh, &tent, *av, &type, &vtype);
+ oh->ntlv.type = type;
+ ac--; av++;
+
+ if (add != 0) {
+ if (ac > 0)
+ tentry_fill_value(oh, &tent, *av, type, vtype);
+ cmd = IP_FW_TABLE_XADD;
+ texterr = "setsockopt(IP_FW_TABLE_XADD)";
+ } else {
+ cmd = IP_FW_TABLE_XDEL;
+ texterr = "setsockopt(IP_FW_TABLE_XDEL)";
+ }
+
+ if (table_do_modify_record(cmd, oh, &tent, update) != 0)
+ err(EX_OSERR, "%s", texterr);
+}
+
+
+static void
+tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type)
+{
+ char *p;
+ int mask, af;
+ struct in6_addr *paddr;
+ uint32_t key, *pkey;
+ int masklen;
+
+ masklen = 0;
+ af = 0;
+ paddr = (struct in6_addr *)&tentry->k;
+
+ switch (type) {
+ case IPFW_TABLE_CIDR:
+ /* Remove / if exists */
+ if ((p = strchr(arg, '/')) != NULL) {
+ *p = '\0';
+ mask = atoi(p + 1);
+ }
+
+ if (inet_pton(AF_INET, arg, paddr) == 1) {
+ if (p != NULL && mask > 32)
+ errx(EX_DATAERR, "bad IPv4 mask width: %s",
+ p + 1);
+
+ masklen = p ? mask : 32;
+ af = AF_INET;
+ } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
+ if (IN6_IS_ADDR_V4COMPAT(paddr))
+ errx(EX_DATAERR,
+ "Use IPv4 instead of v4-compatible");
+ if (p != NULL && mask > 128)
+ errx(EX_DATAERR, "bad IPv6 mask width: %s",
+ p + 1);
+
+ masklen = p ? mask : 128;
+ af = AF_INET6;
+ } else {
+ /* Assume FQDN */
+ if (lookup_host(arg, (struct in_addr *)paddr) != 0)
+ errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
+
+ masklen = 32;
+ type = IPFW_TABLE_CIDR;
+ af = AF_INET;
+ }
+ break;
+ case IPFW_TABLE_INTERFACE:
+ /* Assume interface name. Copy significant data only */
+ mask = MIN(strlen(arg), IF_NAMESIZE - 1);
+ memcpy(paddr, arg, mask);
+ /* Set mask to exact match */
+ masklen = 8 * IF_NAMESIZE;
+ break;
+ case IPFW_TABLE_U32:
+ /* Port or any other key */
+ key = strtol(arg, &p, 10);
+ if (*p != '\0')
+ errx(EX_DATAERR, "Invalid number: %s", arg);
+
+ pkey = (uint32_t *)paddr;
+ *pkey = key;
+ masklen = 32;
+ break;
+ default:
+ errx(EX_DATAERR, "Unsupported table type: %d", type);
+ }
+
+ tentry->subtype = af;
+ tentry->masklen = masklen;
+}
+
+static void
+tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
+ uint8_t *ptype, uint8_t *pvtype)
+{
+ 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 {
+
+ /*
+ * 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)
+ 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);
- return (table_flush(i->tablename, i->set));
+ *ptype = type;
+ *pvtype = vtype;
}
+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);
+ if (*p != '\0')
+ errx(EX_USAGE, "Invalid number: %s", arg);
+ break;
+ case IPFW_VTYPE_IP:
+ if (inet_pton(AF_INET, arg, &tent->value) == 1)
+ break;
+ /* Try hostname */
+ if (lookup_host(arg, (struct in_addr *)&tent->value) != 0)
+ errx(EX_USAGE, "Invalid IPv4 address: %s", arg);
+ break;
+ case IPFW_VTYPE_DSCP:
+ if (isalpha(*arg)) {
+ if ((code = match_token(f_ipdscp, arg)) == -1)
+ errx(EX_DATAERR, "Unknown DSCP code");
+ } else {
+ code = strtoul(arg, NULL, 10);
+ if (code < 0 || code > 63)
+ errx(EX_DATAERR, "Invalid DSCP value");
+ }
+ tent->value = code;
+ break;
+ default:
+ errx(EX_OSERR, "Unsupported format type %d", vtype);
+ }
+}
/*
* Compare table names.
@@ -668,14 +905,11 @@ table_check_name(char *tablename)
/*
* Check if tablename is null-terminated and contains
* valid symbols only. Valid mask is:
- * [a-zA-Z\-\.][a-zA-Z0-9\-_\.]{0,62}
+ * [a-zA-Z0-9\-_\.]{1,63}
*/
l = strlen(tablename);
if (l == 0 || l >= 64)
return (EINVAL);
- /* Restrict first symbol to non-digit */
- if (isdigit(tablename[0]))
- return (EINVAL);
for (i = 0; i < l; i++) {
c = tablename[i];
if (isalpha(c) || isdigit(c) || c == '_' ||
@@ -684,6 +918,10 @@ table_check_name(char *tablename)
return (EINVAL);
}
+ /* Restrict some 'special' names */
+ if (strcmp(tablename, "all") == 0)
+ return (EINVAL);
+
return (0);
}
OpenPOWER on IntegriCloud