svn commit: r270906 - in projects/ipfw: sbin/ipfw sys/conf sys/modules/ipfw sys/netinet sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Sun Aug 31 23:51:11 UTC 2014
Author: melifaro
Date: Sun Aug 31 23:51:09 2014
New Revision: 270906
URL: http://svnweb.freebsd.org/changeset/base/270906
Log:
Add support for multi-field values inside ipfw tables.
This is the last major change in given branch.
Kernel changes:
* Use 64-bytes structures to hold multi-value variables.
* Use shared array to hold values from all tables (assume
each table algo is capable of holding 32-byte variables).
* Add some placeholders to support per-table value arrays in future.
* Use simple eventhandler-style API to ease the process of adding new
table items. Currently table addition may required multiple UH drops/
acquires which is quite tricky due to atomic table modificatio/swap
support, shared array resize, etc. Deal with it by calling special
notifier capable of rolling back state before actually performing
swap/resize operations. Original operation then restarts itself after
acquiring UH lock.
* Bump all objhash users default values to at least 64
* Fix custom hashing inside objhash.
Userland changes:
* Add support for dumping shared value array via "vlist" internal cmd.
* Some small print/fill_flags dixes to support u32 values.
* valtype is now bitmask of
<skipto|pipe|fib|nat|dscp|tag|divert|netgraph|limit|ipv4|ipv6>.
New values can hold distinct values for each of this types.
* Provide special "legacy" type which assumes all values are the same.
* More helpers/docs following..
Some examples:
3:41 [1] zfscurr0# ipfw table mimimi create valtype skipto,limit,ipv4,ipv6
3:41 [1] zfscurr0# ipfw table mimimi info
+++ table(mimimi), set(0) +++
kindex: 2, type: addr
references: 0, valtype: skipto,limit,ipv4,ipv6
algorithm: addr:radix
items: 0, size: 296
3:42 [1] zfscurr0# ipfw table mimimi add 10.0.0.5 3000,10,10.0.0.1,2a02:978:2::1
added: 10.0.0.5/32 3000,10,10.0.0.1,2a02:978:2::1
3:42 [1] zfscurr0# ipfw table mimimi list
+++ table(mimimi), set(0) +++
10.0.0.5/32 3000,0,10.0.0.1,2a02:978:2::1
Added:
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_value.c
Modified:
projects/ipfw/sbin/ipfw/ipfw2.c
projects/ipfw/sbin/ipfw/ipfw2.h
projects/ipfw/sbin/ipfw/tables.c
projects/ipfw/sys/conf/files
projects/ipfw/sys/modules/ipfw/Makefile
projects/ipfw/sys/netinet/ip_fw.h
projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_log.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sbin/ipfw/ipfw2.c Sun Aug 31 23:51:09 2014 (r270906)
@@ -712,12 +712,13 @@ concat_tokens(char *buf, size_t bufsize,
* helper function to process a set of flags and set bits in the
* appropriate masks.
*/
-void
-fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear)
+int
+fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+ uint32_t *clear)
{
char *q; /* points to the separator */
int val;
- uint8_t *which; /* mask we are working on */
+ uint32_t *which; /* mask we are working on */
while (p && *p) {
if (*p == '!') {
@@ -729,15 +730,19 @@ fill_flags(struct _s_x *flags, char *p,
if (q)
*q++ = '\0';
val = match_token(flags, p);
- if (val <= 0)
- errx(EX_DATAERR, "invalid flag %s", p);
- *which |= (uint8_t)val;
+ if (val <= 0) {
+ if (e != NULL)
+ *e = p;
+ return (-1);
+ }
+ *which |= (uint32_t)val;
p = q;
}
+ return (0);
}
void
-print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set)
+print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set)
{
char const *comma = "";
int i, l;
@@ -2992,9 +2997,11 @@ static void
fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode,
struct _s_x *flags, char *p)
{
- uint8_t set = 0, clear = 0;
+ char *e;
+ uint32_t set = 0, clear = 0;
- fill_flags(flags, p, &set, &clear);
+ if (fill_flags(flags, p, &e, &set, &clear) != 0)
+ errx(EX_DATAERR, "invalid flag %s", e);
cmd->opcode = opcode;
cmd->len = (cmd->len & (F_NOT | F_OR)) | 1;
@@ -4825,6 +4832,7 @@ ipfw_flush(int force)
static struct _s_x intcmds[] = {
{ "talist", TOK_TALIST },
{ "iflist", TOK_IFLIST },
+ { "vlist", TOK_VLIST },
{ NULL, 0 }
};
@@ -4846,6 +4854,9 @@ ipfw_internal_handler(int ac, char *av[]
case TOK_TALIST:
ipfw_list_ta(ac, av);
break;
+ case TOK_VLIST:
+ ipfw_list_values(ac, av);
+ break;
}
}
Modified: projects/ipfw/sbin/ipfw/ipfw2.h
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.h Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sbin/ipfw/ipfw2.h Sun Aug 31 23:51:09 2014 (r270906)
@@ -223,10 +223,10 @@ enum tokens {
TOK_VALTYPE,
TOK_ALGO,
TOK_TALIST,
- TOK_FTYPE,
TOK_ATOMIC,
TOK_LOCK,
TOK_UNLOCK,
+ TOK_VLIST,
};
/*
@@ -265,8 +265,9 @@ int match_token_relaxed(struct _s_x *tab
char const *match_value(struct _s_x *p, int value);
size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
char *delimiter);
-void fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear);
-void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set);
+int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+ uint32_t *clear);
+void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set);
struct _ip_fw3_opheader;
int do_cmd(int optname, void *optval, uintptr_t optlen);
@@ -347,4 +348,5 @@ char *table_search_ctlv(struct _ipfw_obj
void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv);
int table_check_name(char *tablename);
void ipfw_list_ta(int ac, char *av[]);
+void ipfw_list_values(int ac, char *av[]);
Modified: projects/ipfw/sbin/ipfw/tables.c
==============================================================================
--- projects/ipfw/sbin/ipfw/tables.c Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sbin/ipfw/tables.c Sun Aug 31 23:51:09 2014 (r270906)
@@ -67,9 +67,11 @@ static void table_show_list(ipfw_obj_hea
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, int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi);
+ char *key, int add, uint8_t *ptype, uint32_t *pvmask, 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);
+ char *arg, uint8_t type, uint32_t vmask);
+static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
+ uint32_t vmask, int print_ip);
typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
static int tables_foreach(table_cb_t *f, void *arg, int sort);
@@ -87,13 +89,17 @@ static struct _s_x tabletypes[] = {
};
static struct _s_x tablevaltypes[] = {
- { "number", IPFW_VTYPE_U32 },
- { NULL, 0 }
-};
-
-static struct _s_x tablefvaltypes[] = {
- { "ip", IPFW_VFTYPE_IP },
- { "number", IPFW_VFTYPE_U32 },
+ { "skipto", IPFW_VTYPE_SKIPTO },
+ { "pipe", IPFW_VTYPE_PIPE },
+ { "fib", IPFW_VTYPE_FIB },
+ { "nat", IPFW_VTYPE_NAT },
+ { "dscp", IPFW_VTYPE_DSCP },
+ { "tag", IPFW_VTYPE_TAG },
+ { "divert", IPFW_VTYPE_DIVERT },
+ { "netgraph", IPFW_VTYPE_NETGRAPH },
+ { "limit", IPFW_VTYPE_LIMIT },
+ { "ipv4", IPFW_VTYPE_NH4 },
+ { "ipv6", IPFW_VTYPE_NH6 },
{ NULL, 0 }
};
@@ -311,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh
static struct _s_x tablenewcmds[] = {
{ "type", TOK_TYPE },
- { "ftype", TOK_FTYPE },
{ "valtype", TOK_VALTYPE },
{ "algo", TOK_ALGO },
{ "limit", TOK_LIMIT },
@@ -331,14 +336,16 @@ static struct _s_x flowtypecmds[] = {
int
table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
{
- uint8_t fset, fclear;
+ uint32_t fset, fclear;
+ char *e;
/* Parse type options */
switch(ttype) {
case IPFW_TABLE_FLOW:
fset = fclear = 0;
- fill_flags(flowtypecmds, p, &fset,
- &fclear);
+ if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0)
+ errx(EX_USAGE,
+ "unable to parse flow option %s", e);
*tflags = fset;
break;
default:
@@ -383,8 +390,9 @@ table_create(ipfw_obj_header *oh, int ac
{
ipfw_xtable_info xi;
int error, tcmd, val;
+ uint32_t fset, fclear;
size_t sz;
- char *p;
+ char *e, *p;
char tbuf[128];
sz = sizeof(tbuf);
@@ -424,27 +432,16 @@ table_create(ipfw_obj_header *oh, int ac
break;
case TOK_VALTYPE:
NEED1("table value type required");
- val = match_token(tablevaltypes, *av);
+ fset = fclear = 0;
+ val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear);
if (val != -1) {
- xi.vtype = val;
+ xi.vmask = fset;
ac--; av++;
break;
}
concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
- *av, tbuf);
- break;
- case TOK_FTYPE:
- NEED1("table value format type required");
- val = match_token(tablefvaltypes, *av);
- if (val != -1) {
- xi.vftype = val;
- ac--; av++;
- break;
- }
- concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
- errx(EX_USAGE, "Unknown format type: %s. Supported: %s",
- *av, tbuf);
+ e, tbuf);
break;
case TOK_ALGO:
NEED1("table algorithm name required");
@@ -462,8 +459,8 @@ table_create(ipfw_obj_header *oh, int ac
/* Set some defaults to preserve compability */
if (xi.algoname[0] == '\0' && xi.type == 0)
xi.type = IPFW_TABLE_ADDR;
- if (xi.vtype == 0)
- xi.vtype = IPFW_VTYPE_U32;
+ if (xi.vmask == 0)
+ xi.vmask = IPFW_VTYPE_LEGACY;
if ((error = table_do_create(oh, &xi)) != 0)
err(EX_OSERR, "Table creation failed");
@@ -494,13 +491,13 @@ table_do_create(ipfw_obj_header *oh, ipf
/*
* Modifies existing table
*
- * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ]
+ * ipfw table NAME modify [ limit number ]
*/
static void
table_modify(ipfw_obj_header *oh, int ac, char *av[])
{
ipfw_xtable_info xi;
- int error, tcmd, val;
+ int error, tcmd;
size_t sz;
char tbuf[128];
@@ -518,19 +515,8 @@ table_modify(ipfw_obj_header *oh, int ac
xi.mflags |= IPFW_TMFLAGS_LIMIT;
ac--; av++;
break;
- case TOK_FTYPE:
- NEED1("table value format type required");
- val = match_token(tablefvaltypes, *av);
- if (val != -1) {
- xi.vftype = val;
- xi.mflags |= IPFW_TMFLAGS_FTYPE;
- ac--; av++;
- break;
- }
- concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", ");
- errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
- *av, tbuf);
- break;
+ default:
+ errx(EX_USAGE, "cmd is not supported for modificatiob");
}
}
@@ -726,34 +712,39 @@ table_show_tainfo(ipfw_xtable_info *i, s
}
}
+static void
+table_print_valheader(char *buf, size_t bufsize, uint32_t vmask)
+{
+
+ if (vmask == IPFW_VTYPE_LEGACY) {
+ snprintf(buf, bufsize, "legacy");
+ return;
+ }
+
+ print_flags_buffer(buf, bufsize, tablevaltypes, vmask);
+}
+
/*
* Prints table info struct @i in human-readable form.
*/
static int
table_show_info(ipfw_xtable_info *i, void *arg)
{
- const char *vtype, *vftype;
+ const char *vtype;
ipfw_ta_tinfo *tainfo;
int afdata, afitem;
struct ta_cldata d;
char ttype[64], tvtype[64];
table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
- if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL)
- vtype = "unknown";
- if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL)
- vftype = "unknown";
- if (strcmp(vtype, vftype) != 0)
- snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype);
- else
- snprintf(tvtype, sizeof(tvtype), "%s", vtype);
+ table_print_valheader(tvtype, sizeof(tvtype), i->vmask);
printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
else
printf(" kindex: %d, type: %s\n", i->kidx, ttype);
- printf(" valtype: %s, references: %u\n", tvtype, i->refcnt);
+ printf(" references: %u, valtype: %s\n", i->refcnt, tvtype);
printf(" algorithm: %s\n", i->algoname);
printf(" items: %u, size: %u\n", i->count, i->size);
if (i->limit > 0)
@@ -895,7 +886,8 @@ table_modify_record(ipfw_obj_header *oh,
{
ipfw_obj_tentry *ptent, tent, *tent_buf;
ipfw_xtable_info xi;
- uint8_t type, vtype;
+ uint8_t type;
+ uint32_t vmask;
int cmd, count, error, i, ignored;
char *texterr, *etxt, *px;
@@ -933,14 +925,14 @@ table_modify_record(ipfw_obj_header *oh,
memset(&xi, 0, sizeof(xi));
count = 0;
while (ac > 0) {
- tentry_fill_key(oh, ptent, *av, add, &type, &vtype, &xi);
+ tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi);
/*
* compability layer: auto-create table if not exists
*/
if (xi.tablename[0] == '\0') {
xi.type = type;
- xi.vtype = vtype;
+ xi.vmask = vmask;
strlcpy(xi.tablename, oh->ntlv.name,
sizeof(xi.tablename));
fprintf(stderr, "DEPRECATED: inserting data info "
@@ -953,7 +945,7 @@ table_modify_record(ipfw_obj_header *oh,
ac--; av++;
if (add != 0 && ac > 0) {
- tentry_fill_value(oh, ptent, *av, type, vtype);
+ tentry_fill_value(oh, ptent, *av, type, vmask);
ac--; av++;
}
@@ -966,6 +958,8 @@ table_modify_record(ipfw_obj_header *oh,
error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
+ quiet = 0;
+
/*
* Compatibility stuff: do not yell on duplicate keys or
* failed deletions.
@@ -1062,7 +1056,8 @@ table_do_lookup(ipfw_obj_header *oh, cha
{
char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
ipfw_obj_tentry *tent;
- uint8_t type, vtype;
+ uint8_t type;
+ uint32_t vmask;
int error;
size_t sz;
@@ -1074,7 +1069,7 @@ table_do_lookup(ipfw_obj_header *oh, cha
tent->head.length = sizeof(*tent);
tent->idx = 1;
- tentry_fill_key(oh, tent, key, 0, &type, &vtype, xi);
+ tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi);
oh->ntlv.type = type;
sz = sizeof(xbuf);
@@ -1321,15 +1316,16 @@ tentry_fill_key_type(char *arg, ipfw_obj
static void
tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
- int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi)
+ int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi)
{
- uint8_t type, tflags, vtype;
+ uint8_t type, tflags;
+ uint32_t vmask;
int error;
char *del;
type = 0;
tflags = 0;
- vtype = 0;
+ vmask = 0;
if (xi->tablename[0] == '\0')
error = table_get_info(oh, xi);
@@ -1340,7 +1336,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
/* Table found. */
type = xi->type;
tflags = xi->tflags;
- vtype = xi->vtype;
+ vmask = xi->vmask;
} else {
if (error != ESRCH)
errx(EX_OSERR, "Error requesting table %s info",
@@ -1359,11 +1355,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
/* OK Prepare and send */
type = IPFW_TABLE_ADDR;
- /*
- * XXX: Value type is forced to be u32.
- * This should be changed for MFC.
- */
- vtype = IPFW_VTYPE_U32;
+ vmask = IPFW_VTYPE_LEGACY;
} else {
/* Inknown key */
errx(EX_USAGE, "Table %s does not exist, cannot guess "
@@ -1376,57 +1368,156 @@ tentry_fill_key(ipfw_obj_header *oh, ipf
tentry_fill_key_type(key, tent, type, tflags);
*ptype = type;
- *pvtype = vtype;
+ *pvmask = vmask;
}
static void
-tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
- uint8_t type, uint8_t vtype)
+set_legacy_value(uint32_t val, ipfw_table_value *v)
{
- uint32_t val;
- char *p;
+ v->tag = val;
+ v->pipe = val;
+ v->divert = val;
+ v->skipto = val;
+ v->netgraph = val;
+ v->fib = val;
+ v->nat = val;
+ v->nh4 = val;
+ v->dscp = (uint8_t)val;
+ v->limit = val;
+}
- /* Try to interpret as number first */
- tent->v.value = strtoul(arg, &p, 0);
- if (*p == '\0')
- return;
- if (inet_pton(AF_INET, arg, &val) == 1) {
- tent->v.value = ntohl(val);
- return;
+static void
+tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
+ uint8_t type, uint32_t vmask)
+{
+ uint32_t a4, flag, val, vm;
+ ipfw_table_value *v;
+ uint32_t i;
+ char *comma, *e, *etype, *n, *p;
+
+ v = &tent->v.value;
+ vm = vmask;
+
+ /* Compat layer: keep old behavior for legacy value types */
+ if (vmask == IPFW_VTYPE_LEGACY) {
+ /* Try to interpret as number first */
+ val = strtoul(arg, &p, 0);
+ if (*p == '\0') {
+ set_legacy_value(val, v);
+ return;
+ }
+ if (inet_pton(AF_INET, arg, &val) == 1) {
+ set_legacy_value(ntohl(val), v);
+ return;
+ }
+ /* Try hostname */
+ if (lookup_host(arg, (struct in_addr *)&val) == 0) {
+ set_legacy_value(val, v);
+ return;
+ }
+ errx(EX_OSERR, "Unable to parse value %s", arg);
}
- /* Try hostname */
- if (lookup_host(arg, (struct in_addr *)&tent->v.value) == 0)
- return;
- errx(EX_OSERR, "Unable to parse value %s", arg);
-#if 0
- 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)
+
+ /*
+ * Shorthands: handle single value if vmask consists
+ * of numbers only. e.g.:
+ * vmask = "fib,skipto" -> treat input "1" as "1,1"
+ */
+
+ n = arg;
+ etype = NULL;
+ for (i = 1; i < (1 << 31); i *= 2) {
+ if ((flag = (vmask & i)) == 0)
+ continue;
+ vmask &= ~flag;
+
+ if ((comma = strchr(n, ',')) != NULL)
+ *comma = '\0';
+
+ switch (flag) {
+ case IPFW_VTYPE_TAG:
+ v->tag = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "tag";
+ break;
+ case IPFW_VTYPE_PIPE:
+ v->pipe = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "pipe";
+ break;
+ case IPFW_VTYPE_DIVERT:
+ v->divert = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "divert";
+ break;
+ case IPFW_VTYPE_SKIPTO:
+ v->skipto = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "skipto";
+ break;
+ case IPFW_VTYPE_NETGRAPH:
+ v->netgraph = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "netgraph";
+ break;
+ case IPFW_VTYPE_FIB:
+ v->fib = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "fib";
+ break;
+ case IPFW_VTYPE_NAT:
+ v->nat = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "nat";
+ break;
+ case IPFW_VTYPE_LIMIT:
+ v->limit = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "limit";
+ break;
+ case IPFW_VTYPE_NH4:
+ if (strchr(n, '.') != NULL &&
+ inet_pton(AF_INET, n, &a4) == 1) {
+ v->nh4 = ntohl(a4);
+ break;
+ }
+ if (lookup_host(n, (struct in_addr *)&v->nh4) == 0)
+ break;
+ etype = "ipv4";
+ break;
+ case IPFW_VTYPE_DSCP:
+ if (isalpha(*n)) {
+ if ((v->dscp = match_token(f_ipdscp, n)) != -1)
+ break;
+ else
+ etype = "DSCP code";
+ } else {
+ v->dscp = strtol(n, &e, 10);
+ if (v->dscp > 63 || *e != '\0')
+ etype = "DSCP value";
+ }
+ break;
+ case IPFW_VTYPE_NH6:
+ if (strchr(n, ':') != NULL &&
+ inet_pton(AF_INET6, n, &v->nh6) == 1)
+ break;
+ etype = "ipv6";
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);
+
+ if (etype != NULL)
+ errx(EX_USAGE, "Unable to parse %s as %s", n, etype);
+
+ if (comma != NULL)
+ *comma++ = ',';
+
+ if ((n = comma) != NULL)
+ continue;
+
+ /* End of input. */
+ if (vmask != 0)
+ errx(EX_USAGE, "Not enough fields inside value");
}
-#endif
}
/*
@@ -1558,20 +1649,90 @@ table_show_list(ipfw_obj_header *oh, int
}
static void
+table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
+ uint32_t vmask, int print_ip)
+{
+ uint32_t flag, i, l;
+ size_t sz;
+ struct in_addr a4;
+ char abuf[INET6_ADDRSTRLEN];
+
+ sz = bufsize;
+
+ /*
+ * Some shorthands for printing values:
+ * legacy assumes all values are equal, so keep the first one.
+ */
+ if (vmask == IPFW_VTYPE_LEGACY) {
+ if (print_ip != 0) {
+ flag = htonl(v->tag);
+ inet_ntop(AF_INET, &flag, buf, sz);
+ } else
+ snprintf(buf, sz, "%u", v->tag);
+ return;
+ }
+
+ for (i = 1; i < (1 << 31); i *= 2) {
+ if ((flag = (vmask & i)) == 0)
+ continue;
+ l = 0;
+
+ switch (flag) {
+ case IPFW_VTYPE_TAG:
+ l = snprintf(buf, sz, "%u,", v->tag);
+ break;
+ case IPFW_VTYPE_PIPE:
+ l = snprintf(buf, sz, "%u,", v->pipe);
+ break;
+ case IPFW_VTYPE_DIVERT:
+ l = snprintf(buf, sz, "%d,", v->divert);
+ break;
+ case IPFW_VTYPE_SKIPTO:
+ l = snprintf(buf, sz, "%d,", v->skipto);
+ break;
+ case IPFW_VTYPE_NETGRAPH:
+ l = snprintf(buf, sz, "%u,", v->netgraph);
+ break;
+ case IPFW_VTYPE_FIB:
+ l = snprintf(buf, sz, "%u,", v->fib);
+ break;
+ case IPFW_VTYPE_NAT:
+ l = snprintf(buf, sz, "%u,", v->nat);
+ break;
+ case IPFW_VTYPE_LIMIT:
+ l = snprintf(buf, sz, "%u,", v->limit);
+ break;
+ case IPFW_VTYPE_NH4:
+ a4.s_addr = htonl(v->nh4);
+ inet_ntop(AF_INET, &a4, abuf, sizeof(abuf));
+ l = snprintf(buf, sz, "%s,", abuf);
+ break;
+ case IPFW_VTYPE_DSCP:
+ l = snprintf(buf, sz, "%d,", v->dscp);
+ break;
+ case IPFW_VTYPE_NH6:
+ inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf));
+ l = snprintf(buf, sz, "%s,", abuf);
+ break;
+ }
+
+ buf += l;
+ sz -= l;
+ }
+
+ if (sz != bufsize)
+ *(buf - 1) = '\0';
+}
+
+static void
table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
{
- char *comma, tbuf[128], pval[32];
+ char *comma, tbuf[128], pval[128];
void *paddr;
- uint32_t tval;
struct tflow_entry *tfe;
- tval = tent->v.value;
-
- if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) {
- tval = htonl(tval);
- inet_ntop(AF_INET, &tval, pval, sizeof(pval));
- } else
- snprintf(pval, sizeof(pval), "%u", tval);
+ table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask,
+ co.do_value_as_ip);
switch (i->type) {
case IPFW_TABLE_ADDR:
@@ -1633,7 +1794,7 @@ table_show_entry(ipfw_xtable_info *i, ip
}
static int
-table_do_get_algolist(ipfw_obj_lheader **polh)
+table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh)
{
ipfw_obj_lheader req, *olh;
size_t sz;
@@ -1642,7 +1803,7 @@ table_do_get_algolist(ipfw_obj_lheader *
memset(&req, 0, sizeof(req));
sz = sizeof(req);
- error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz);
+ error = do_get3(opcode, &req.opheader, &sz);
if (error != 0 && error != ENOMEM)
return (error);
@@ -1651,7 +1812,7 @@ table_do_get_algolist(ipfw_obj_lheader *
return (ENOMEM);
olh->size = sz;
- if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) {
+ if ((error = do_get3(opcode, &olh->opheader, &sz)) != 0) {
free(olh);
return (error);
}
@@ -1660,6 +1821,20 @@ table_do_get_algolist(ipfw_obj_lheader *
return (0);
}
+static int
+table_do_get_algolist(ipfw_obj_lheader **polh)
+{
+
+ return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh));
+}
+
+static int
+table_do_get_vlist(ipfw_obj_lheader **polh)
+{
+
+ return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh));
+}
+
void
ipfw_list_ta(int ac, char *av[])
{
@@ -1685,6 +1860,71 @@ ipfw_list_ta(int ac, char *av[])
free(olh);
}
+
+/* Copy of current kernel table_value structure */
+struct _table_value {
+ uint32_t tag; /* O_TAG/O_TAGGED */
+ uint32_t pipe; /* O_PIPE/O_QUEUE */
+ uint16_t divert; /* O_DIVERT/O_TEE */
+ uint16_t skipto; /* skipto, CALLRET */
+ uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */
+ uint32_t fib; /* O_SETFIB */
+ uint32_t nat; /* O_NAT */
+ uint32_t nh4;
+ uint8_t dscp;
+ uint8_t spare0[3];
+ /* -- 32 bytes -- */
+ struct in6_addr nh6;
+ uint32_t limit; /* O_LIMIT */
+ uint32_t spare1;
+ uint64_t refcnt; /* Number of references */
+};
+
+int
+compare_values(const void *_a, const void *_b)
+{
+ struct _table_value *a, *b;
+
+ a = (struct _table_value *)_a;
+ b = (struct _table_value *)_b;
+
+ if (a->spare1 < b->spare1)
+ return (-1);
+ else if (a->spare1 > b->spare1)
+ return (1);
+
+ return (0);
+}
+
+void
+ipfw_list_values(int ac, char *av[])
+{
+ ipfw_obj_lheader *olh;
+ struct _table_value *v;
+ int error, i;
+ uint32_t vmask;
+ char buf[128];
+
+ error = table_do_get_vlist(&olh);
+ if (error != 0)
+ err(EX_OSERR, "Unable to request value list");
+
+ vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */
+
+ table_print_valheader(buf, sizeof(buf), vmask);
+ printf("HEADER: %s\n", buf);
+ v = (struct _table_value *)(olh + 1);
+ qsort(v, olh->count, olh->objsize, compare_values);
+ for (i = 0; i < olh->count; i++) {
+ table_show_value(buf, sizeof(buf), (ipfw_table_value *)v,
+ vmask, 0);
+ printf("[%u] refs=%lu %s\n", v->spare1, v->refcnt, buf);
+ v = (struct _table_value *)((caddr_t)v + olh->objsize);
+ }
+
+ free(olh);
+}
+
int
compare_ntlv(const void *_a, const void *_b)
{
Modified: projects/ipfw/sys/conf/files
==============================================================================
--- projects/ipfw/sys/conf/files Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sys/conf/files Sun Aug 31 23:51:09 2014 (r270906)
@@ -3494,6 +3494,7 @@ netpfil/ipfw/ip_fw_pfil.c optional inet
netpfil/ipfw/ip_fw_sockopt.c optional inet ipfirewall
netpfil/ipfw/ip_fw_table.c optional inet ipfirewall
netpfil/ipfw/ip_fw_table_algo.c optional inet ipfirewall
+netpfil/ipfw/ip_fw_table_value.c optional inet ipfirewall
netpfil/ipfw/ip_fw_iface.c optional inet ipfirewall
netpfil/ipfw/ip_fw_nat.c optional inet ipfirewall_nat
netpfil/pf/if_pflog.c optional pflog pf inet
Modified: projects/ipfw/sys/modules/ipfw/Makefile
==============================================================================
--- projects/ipfw/sys/modules/ipfw/Makefile Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sys/modules/ipfw/Makefile Sun Aug 31 23:51:09 2014 (r270906)
@@ -8,6 +8,7 @@ KMOD= ipfw
SRCS= ip_fw2.c ip_fw_pfil.c
SRCS+= ip_fw_dynamic.c ip_fw_log.c
SRCS+= ip_fw_sockopt.c ip_fw_table.c ip_fw_table_algo.c ip_fw_iface.c
+SRCS+= ip_fw_table_value.c
SRCS+= opt_inet.h opt_inet6.h opt_ipdivert.h opt_ipfw.h opt_ipsec.h
CFLAGS+= -DIPFIREWALL
Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sys/netinet/ip_fw.h Sun Aug 31 23:51:09 2014 (r270906)
@@ -96,6 +96,7 @@ typedef struct _ip_fw3_opheader {
#define IP_FW_XIFLIST 107 /* list tracked interfaces */
#define IP_FW_TABLES_ALIST 108 /* list table algorithms */
#define IP_FW_TABLE_XSWAP 109 /* swap two tables */
+#define IP_FW_TABLE_VLIST 110 /* dump table value hash */
/*
* The kernel representation of ipfw rules is made of a list of
@@ -663,11 +664,18 @@ struct _ipfw_dyn_rule {
#define IPFW_TABLE_CIDR IPFW_TABLE_ADDR /* compat */
/* Value types */
-#define IPFW_VTYPE_U32 1 /* Skipto/tablearg integer */
-
-/* Value format types */
-#define IPFW_VFTYPE_U32 0 /* Skipto/tablearg integer */
-#define IPFW_VFTYPE_IP 1 /* Nexthop IP address */
+#define IPFW_VTYPE_LEGACY 0xFFFFFFFF /* All data is filled in */
+#define IPFW_VTYPE_SKIPTO 0x00000001 /* skipto/call/callreturn */
+#define IPFW_VTYPE_PIPE 0x00000002 /* pipe/queue */
+#define IPFW_VTYPE_FIB 0x00000004 /* setfib */
+#define IPFW_VTYPE_NAT 0x00000008 /* nat */
+#define IPFW_VTYPE_DSCP 0x00000010 /* dscp */
+#define IPFW_VTYPE_TAG 0x00000020 /* tag/untag */
+#define IPFW_VTYPE_DIVERT 0x00000040 /* divert/tee */
+#define IPFW_VTYPE_NETGRAPH 0x00000080 /* netgraph/ngtee */
+#define IPFW_VTYPE_LIMIT 0x00000100 /* IPv6 nexthop */
+#define IPFW_VTYPE_NH4 0x00000200 /* IPv4 nexthop */
+#define IPFW_VTYPE_NH6 0x00000400 /* IPv6 nexthop */
typedef struct _ipfw_table_entry {
in_addr_t addr; /* network address */
@@ -751,6 +759,23 @@ struct tflow_entry {
} a;
};
+typedef struct _ipfw_table_value {
+ uint32_t tag; /* O_TAG/O_TAGGED */
+ uint32_t pipe; /* O_PIPE/O_QUEUE */
+ uint16_t divert; /* O_DIVERT/O_TEE */
+ uint16_t skipto; /* skipto, CALLRET */
+ uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */
+ uint32_t fib; /* O_SETFIB */
+ uint32_t nat; /* O_NAT */
+ uint32_t nh4;
+ uint8_t dscp;
+ uint8_t spare0[3];
+ struct in6_addr nh6;
+ uint32_t limit; /* O_LIMIT */
+ uint32_t spare1;
+ uint64_t reserved;
+} ipfw_table_value;
+
/* Table entry TLV */
typedef struct _ipfw_obj_tentry {
ipfw_obj_tlv head; /* TLV header */
@@ -769,8 +794,8 @@ typedef struct _ipfw_obj_tentry {
struct tflow_entry flow;
} k;
union {
- uint32_t value; /* 32-bit value */
- char storage[64]; /* Future needs */
+ ipfw_table_value value; /* value data */
+ uint32_t kidx; /* value kernel index */
} v;
} ipfw_obj_tentry;
#define IPFW_TF_UPDATE 0x01 /* Update record if exists */
@@ -839,10 +864,10 @@ typedef struct _ipfw_ta_tinfo {
typedef struct _ipfw_xtable_info {
uint8_t type; /* table type (addr,iface,..) */
uint8_t tflags; /* type flags */
- uint8_t vtype; /* value type (u32) */
- uint8_t vftype; /* value format type (ip,number)*/
uint16_t mflags; /* modification flags */
uint16_t flags; /* generic table flags */
+ uint16_t spare[3];
+ uint32_t vmask; /* bitmask with value types */
uint32_t set; /* set table is in */
uint32_t kidx; /* kernel index */
uint32_t refcnt; /* number of references */
@@ -862,7 +887,6 @@ typedef struct _ipfw_xtable_info {
#define IPFW_TFFLAG_DSTPORT 0x08
#define IPFW_TFFLAG_PROTO 0x10
/* Table modification flags */
-#define IPFW_TMFLAGS_FTYPE 0x0001 /* Change ftype field */
#define IPFW_TMFLAGS_LIMIT 0x0002 /* Change limit value */
#define IPFW_TMFLAGS_LOCK 0x0004 /* Change table lock state */
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sun Aug 31 23:09:23 2014 (r270905)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sun Aug 31 23:51:09 2014 (r270906)
@@ -817,7 +817,7 @@ jump_fast(struct ip_fw_chain *chain, str
if (num != IP_FW_TARG && f->cached_id == chain->id)
f_pos = f->cached_pos;
else {
- int i = IP_FW_ARG_TABLEARG(num);
+ int i = IP_FW_ARG_TABLEARG(chain, num, skipto);
/* make sure we do not jump backward */
if (jump_backwards == 0 && i <= f->rulenum)
i = f->rulenum + 1;
@@ -844,7 +844,7 @@ jump_linear(struct ip_fw_chain *chain, s
{
int f_pos;
- num = IP_FW_ARG_TABLEARG(num);
+ num = IP_FW_ARG_TABLEARG(chain, num, skipto);
/* make sure we do not jump backward */
if (jump_backwards == 0 && num <= f->rulenum)
num = f->rulenum + 1;
@@ -853,6 +853,7 @@ jump_linear(struct ip_fw_chain *chain, s
return (f_pos);
}
+#define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f)
/*
* The main check routine for the firewall.
*
@@ -1841,7 +1842,7 @@ do { \
}
case O_LOG:
- ipfw_log(f, hlen, args, m,
+ ipfw_log(chain, f, hlen, args, m,
oif, offset | ip6f_mf, tablearg, ip);
match = 1;
break;
@@ -1963,7 +1964,7 @@ do { \
case O_TAG: {
struct m_tag *mtag;
- uint32_t tag = IP_FW_ARG_TABLEARG(cmd->arg1);
+ uint32_t tag = TARG(cmd->arg1, tag);
/* Packet is already tagged with this tag? */
mtag = m_tag_locate(m, MTAG_IPFW, tag, NULL);
@@ -2044,7 +2045,7 @@ do { \
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list