Page MenuHomeFreeBSD

D53694.id166867.diff
No OneTemporary

D53694.id166867.diff

diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1421,8 +1421,7 @@
with multiple addresses) is provided for convenience only and
its use is discouraged.
.It Ar addr : Oo Cm not Oc Bro
-.Cm any | me | me6 |
-.Cm table Ns Pq Ar name Ns Op , Ns Ar value
+.Cm any | me | me6 | Ar table-ref
.Ar | addr-list | addr-set
.Brc
.Bl -tag -width indent
@@ -1434,16 +1433,32 @@
Matches any IPv6 address configured on an interface in the system.
The address list is evaluated at the time the packet is
analysed.
-.It Cm table Ns Pq Ar name Ns Op , Ns Ar value
+.El
+.It Ar table-ref :
+A table lookup can be specified in one of the following ways:
+.Bl -tag -width indent
+.It table Ns Pq Ar name Ns
Matches any IPv4 or IPv6 address for which an entry exists in the lookup table
.Ar number .
-If an optional 32-bit unsigned
+.It table Ns Pq Ar name , Ns Ar value
+Matches any IPv4 or IPv6 address for which an entry exists in the lookup table
+.Ar number
+and 32-bit unsigned
.Ar value
-is also specified, an entry will match only if it has this value.
+specified matchess entry value.
+.It table Ns Pq Ar name , Ns Ar value-type Ns = Ns Ar value
+Matches any IPv4 or IPv6 address for which an entry exists in the lookup table
+.Ar number
+and 32-bit unsigned
+.Ar value
+specified matches corresponding
+.Ar value-type
+field for the record found.
+.El
+.Pp
See the
.Sx LOOKUP TABLES
section below for more information on lookup tables.
-.El
.It Ar addr-list : ip-addr Ns Op , Ns Ar addr-list
.It Ar ip-addr :
A host or subnet address specified in one of the following ways:
@@ -1664,9 +1679,9 @@
.It Cm fib Ar fibnum
Matches a packet that has been tagged to use
the given FIB (routing table) number.
-.It Cm flow Ar table Ns Pq Ar name Ns Op , Ns Ar value
-Search for the flow entry in lookup table
-.Ar name .
+.It Cm flow Ar table-ref
+Search for the flow entry in lookup table specified by
+.Ar table-ref .
If not found, the match fails.
Otherwise, the match succeeds and
.Cm tablearg
@@ -1682,16 +1697,16 @@
.Ar labels .
.Ar labels
is a comma separated list of numeric flow labels.
-.It Cm dst-mac Ar table Ns Pq Ar name Ns Op , Ns Ar value
-Search for the destination MAC address entry in lookup table
-.Ar name .
+.It Cm dst-mac Ar table-ref
+Search for the destination MAC address entry in lookup table specified by
+.Ar table-ref .
If not found, the match fails.
Otherwise, the match succeeds and
.Cm tablearg
is set to the value extracted from the table.
-.It Cm src-mac Ar table Ns Pq Ar name Ns Op , Ns Ar value
-Search for the source MAC address entry in lookup table
-.Ar name .
+.It Cm src-mac Ar table-ref
+Search for the source MAC address entry in lookup table specified by
+.Ar table-ref .
If not found, the match fails.
Otherwise, the match succeeds and
.Cm tablearg
@@ -1909,8 +1924,10 @@
One or more
of source and destination addresses and ports can be
specified.
-.It Cm lookup Bro Cm dst-ip | dst-port | dst-mac | src-ip | src-port | src-mac | uid |
-.Cm jail | dscp | mark Brc Ar name
+.It Cm lookup Bro Cm dst-ip | dst-ip4 | dst-ip6 | dst-port | dst-mac | src-ip |
+.Cm src-ip4 | src-ip6 | src-port | src-mac | uid | jail | dscp | mark
+.Brc Ns Bo : Ns
+.Ar bitmask Bc Ar name
Search an entry in lookup table
.Ar name
that matches the field specified as argument.
@@ -1919,8 +1936,58 @@
.Cm tablearg
is set to the value extracted from the table.
.Pp
+If an optional 32-bit unsigned
+.Ar bitmask
+is specified, value of the field is altered by bitwize AND with
+.Ar bitmask
+and resulting value is being searched instead of original one.
+The
+.Ar bitmask
+is accepted in the following formats:
+.Bl -enum -width indent
+.It
+A dotted-quad form, e.g. 127.88.34.0
+.It
+A number, e.g. 0xf00baa1 or 255
+.It
+As an IPv6 address when specified alongwith
+.Cm dst-ip6
+or
+.Cm src-ip6
+field.
+If used, the rule will match IPv6 packets only.
+Example: src-ip6:afff:ff00:ffff:ffff:0:0:0:0f0f.
+.It
+As a Ethernet mac address when specified alongwith
+.Cm dst-mac
+or
+.Cm src-mac
+field.
+.El
+.Pp
+The
+.Ar bitmask
+can not be specified for
+.Cm dst-ip
+or
+.Cm src-ip
+as these field specifiers lookup both IPv4 and IPv6 addresses.
+.Pp
This option can be useful to quickly dispatch traffic based on
certain packet fields.
+The
+.Ar bitmask
+allows to implement wildcard lookups by inserting into table masked prefix and
+appying
+.Ar bitmask
+upon each lookup.
+.Pp
+Note:
+.Cm dst-mac
+and
+.Cm src-mac
+lookups currently do not support masking.
+.Pp
See the
.Sx LOOKUP TABLES
section below for more information on lookup tables.
@@ -1983,7 +2050,7 @@
.Cm check-state
in contrast to
.Cm keep-state .
-.It Cm recv | xmit | via Brq Ar ifX | Ar ifmask | Ar table Ns Po Ar name Ns Oo , Ns Ar value Oc Pc | Ar ipno | Ar any
+.It Cm recv | xmit | via Brq Ar ifX | Ar ifmask | Ar table-ref | Ar ipno | Ar any
Matches packets received, transmitted or going through,
respectively, the interface specified by exact name
.Po Ar ifX Pc ,
@@ -2001,8 +2068,8 @@
.Sx EXAMPLES
section.
.Pp
-Table
-.Ar name
+A lookup table specified by
+.Ar table-ref
may be used to match interface by its kernel ifindex.
See the
.Sx LOOKUP TABLES
@@ -4309,7 +4376,8 @@
.Xr route 4
socket, that were logged using rules with
.Cm log Cm logdst Ar rtsock
-opcode. Optional
+opcode.
+Optional
.Ar filter-comment
can be specified to show only those messages, that were logged
by rules with specific rule comment.
@@ -4664,10 +4732,41 @@
The following example illustrate usage of flow tables:
.Pp
.Dl "ipfw table fl create type flow:src-ip,proto,dst-ip,dst-port"
-.Dl "ipfw table fl add 2a02:6b8:77::88,tcp,2a02:6b8:77::99,80 11"
+.Dl "ipfw table fl add 2001:db8:77::88,tcp,2001:db8:77::99,80 11"
.Dl "ipfw table fl add 10.0.0.1,udp,10.0.0.2,53 12"
.Dl ".."
.Dl "ipfw add 100 allow ip from any to any flow 'table(fl,11)' recv ix0"
+.Pp
+The following example illustrate masked table lookups to aid uniform client
+distribution among multiple NAT instances:
+.Bd -literal -offset indent
+# Configure NAT instances
+ipfw nat 10 config ip 192.0.2.0
+ipfw nat 11 config ip 192.0.2.1
+ipfw nat 12 config ip 192.0.2.2
+ipfw nat 13 config ip 192.0.2.3
+
+ipfw table mynats create type addr valtype nat
+# Map external NAT address to NAT instance
+ipfw table mynats add 192.0.2.0 10
+ipfw table mynats add 192.0.2.1 11
+ipfw table mynats add 192.0.2.2 12
+ipfw table mynats add 192.0.2.3 13
+
+# Map last 2 bits of client's IP address to NAT instance
+ipfw table mynats add 0.0.0.0 10
+ipfw table mynats add 0.0.0.1 11
+ipfw table mynats add 0.0.0.2 12
+ipfw table mynats add 0.0.0.3 13
+
+# In -> Out NAT, zero out all bits in a client's IP exept
+# 2 least significant prior to table lookup
+ipfw add nat tablearg ip from 10.0.0.0/24 to any
+ lookup src-ip4:0.0.0.3 mynats
+# Out -> In NAT
+ipfw add nat tablearg ip from any to 192.0.2.0/30
+ lookup dst-ip mynats
+.Ed
.Ss SETS OF RULES
To add a set of rules atomically, e.g.\& set 18:
.Pp
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -317,6 +317,10 @@
static struct _s_x lookup_keys[] = {
{ "dst-ip", LOOKUP_DST_IP },
{ "src-ip", LOOKUP_SRC_IP },
+ { "dst-ip6", LOOKUP_DST_IP6 },
+ { "src-ip6", LOOKUP_SRC_IP6 },
+ { "dst-ip4", LOOKUP_DST_IP4 },
+ { "src-ip4", LOOKUP_SRC_IP4 },
{ "dst-port", LOOKUP_DST_PORT },
{ "src-port", LOOKUP_SRC_PORT },
{ "dst-mac", LOOKUP_DST_MAC },
@@ -342,6 +346,7 @@
{ "fib", TVALUE_FIB },
{ "nat", TVALUE_NAT },
{ "nh4", TVALUE_NH4 },
+ { "nh6", TVALUE_NH6 },
{ "dscp", TVALUE_DSCP },
{ "limit", TVALUE_LIMIT },
{ "mark", TVALUE_MARK },
@@ -1319,12 +1324,27 @@
}
static void
-print_tvalue(struct buf_pr *bp, const ipfw_insn_table *cmd)
+print_tvalue(struct buf_pr *bp, const ipfw_insn_lookup *cmd)
{
+ char maskbuf[INET6_ADDRSTRLEN];
const char *name;
name = match_value(tvalue_names, IPFW_TVALUE_TYPE(&cmd->o));
- bprintf(bp, ",%s=%u", name != NULL ? name: "<invalid>", cmd->value);
+ switch(IPFW_TVALUE_TYPE(&cmd->o)) {
+ case TVALUE_NH6:
+ if (inet_ntop(AF_INET6, &insntoc(&cmd->o, lookup)->ip6,
+ maskbuf, sizeof(maskbuf)) == NULL)
+ strcpy(maskbuf, "<invalid>");
+ bprintf(bp, ",%s=%s", name != NULL ? name: "<invalid>",
+ maskbuf);
+ return;
+ case TVALUE_NH4:
+ bprintf(bp, ",%s=%s", name != NULL ? name: "<invalid>",
+ inet_ntoa(cmd->ip4));
+ return;
+ }
+ bprintf(bp, ",%s=%u", name != NULL ? name: "<invalid>",
+ cmd->u32);
}
@@ -1335,11 +1355,14 @@
print_ip(struct buf_pr *bp, const struct format_opts *fo,
const ipfw_insn_ip *cmd)
{
+ char maskbuf[INET6_ADDRSTRLEN];
+ const uint32_t *a = insntoc(cmd, u32)->d;
struct hostent *he = NULL;
const struct in_addr *ia;
- const uint32_t *a = ((const ipfw_insn_u32 *)cmd)->d;
- uint32_t len = F_LEN(&cmd->o);
+ const ipfw_insn_lookup *l = insntoc(cmd, lookup);
+ const char *key;
char *t;
+ uint32_t len = F_LEN(&cmd->o);
bprintf(bp, " ");
switch (cmd->o.opcode) {
@@ -1348,32 +1371,65 @@
bprintf(bp, "me");
return;
- case O_IP_DST_LOOKUP:
- if ((len == F_INSN_SIZE(ipfw_insn_kidx) ||
- len == F_INSN_SIZE(ipfw_insn_table)) &&
- IPFW_LOOKUP_TYPE(&cmd->o) != LOOKUP_NONE) {
- const char *key;
-
- key = match_value(lookup_keys,
- IPFW_LOOKUP_TYPE(&cmd->o));
- t = table_search_ctlv(fo->tstate,
- insntoc(&cmd->o, kidx)->kidx);
- if (len == F_INSN_SIZE(ipfw_insn_table)) {
- bprintf(bp, "lookup %s:%#x %s",
- (key != NULL ? key : "<invalid>"),
- insntoc(&cmd->o, table)->value, t);
- } else
- bprintf(bp, "lookup %s %s", key != NULL ? key:
- "<invalid>", t);
+ case O_TABLE_LOOKUP: {
+ key = match_value(lookup_keys,
+ IPFW_LOOKUP_TYPE(&cmd->o));
+ t = table_search_ctlv(fo->tstate,
+ insntoc(&cmd->o, kidx)->kidx);
+ if (IPFW_LOOKUP_MASKING(&cmd->o) == 0 ||
+ len != F_INSN_SIZE(ipfw_insn_lookup)) {
+ bprintf(bp, "lookup %s %s",
+ (key != NULL ? key : "<invalid>"), t);
return;
}
- /* FALLTHROUGH */
+ switch (IPFW_LOOKUP_TYPE(&cmd->o)) {
+ case LOOKUP_DST_IP6:
+ case LOOKUP_SRC_IP6:
+ if (inet_ntop(AF_INET6, &l->ip6,
+ maskbuf, sizeof(maskbuf)) == NULL)
+ strcpy(maskbuf, "<invalid>");
+ bprintf(bp, "lookup %s:%s %s", key, maskbuf, t);
+ break;
+ case LOOKUP_DST_IP:
+ case LOOKUP_SRC_IP:
+ case LOOKUP_DST_IP4:
+ case LOOKUP_SRC_IP4:
+ bprintf(bp, "lookup %s:%s %s", key,
+ inet_ntoa(l->ip4), t);
+ break;
+ case LOOKUP_DST_MAC:
+ case LOOKUP_SRC_MAC:
+ bprintf(bp, "lookup %s:%s %s", key,
+ ether_ntoa((const struct ether_addr *)&l->mac), t);
+ break;
+ default:
+ bprintf(bp, "lookup %s:%#x %s",
+ (key != NULL ? key : "<invalid>"),
+ l->u32, t);
+ }
+ return;
+ }
+ case O_IP_DST_LOOKUP:
case O_IP_SRC_LOOKUP:
t = table_search_ctlv(fo->tstate,
insntoc(&cmd->o, kidx)->kidx);
+ /*
+ * D53694 compatibility layer, to be removed.
+ * Properly show rules loaded into new kernel modules by
+ * an old ipfw binary.
+ */
+ if (IPFW_LOOKUP_MASKING(&cmd->o) != 0 &&
+ len == F_INSN_SIZE(ipfw_insn_table)) {
+ key = match_value(lookup_keys,
+ IPFW_LOOKUP_TYPE(&cmd->o));
+ bprintf(bp, "lookup %s:%#x %s",
+ (key != NULL ? key : "<invalid>"),
+ insntoc(&cmd->o, table)->value, t);
+ return;
+ }
bprintf(bp, "table(%s", t);
- if (len == F_INSN_SIZE(ipfw_insn_table))
- print_tvalue(bp, insntoc(&cmd->o, table));
+ if (IPFW_LOOKUP_MATCH_TVALUE(&cmd->o) != 0)
+ print_tvalue(bp, l);
bprintf(bp, ")");
return;
}
@@ -1478,15 +1534,14 @@
print_mac_lookup(struct buf_pr *bp, const struct format_opts *fo,
const ipfw_insn *cmd)
{
- uint32_t len = F_LEN(cmd);
char *t;
bprintf(bp, " ");
t = table_search_ctlv(fo->tstate, insntoc(cmd, kidx)->kidx);
bprintf(bp, "table(%s", t);
- if (len == F_INSN_SIZE(ipfw_insn_table))
- print_tvalue(bp, insntoc(cmd, table));
+ if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0)
+ print_tvalue(bp, insntoc(cmd, lookup));
bprintf(bp, ")");
}
@@ -1651,6 +1706,8 @@
case O_IP_SRC_SET:
if (state->flags & HAVE_SRCIP)
bprintf(bp, " src-ip");
+ /* FALLTHROUGH */
+ case O_TABLE_LOOKUP:
print_ip(bp, fo, insntoc(cmd, ip));
break;
case O_IP_DST:
@@ -1775,8 +1832,8 @@
s = table_search_ctlv(fo->tstate,
insntoc(cmd, kidx)->kidx);
bprintf(bp, " flow table(%s", s);
- if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_table))
- print_tvalue(bp, insntoc(cmd, table));
+ if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0)
+ print_tvalue(bp, insntoc(cmd, lookup));
bprintf(bp, ")");
break;
case O_IPID:
@@ -3312,8 +3369,11 @@
return (pack_object(tstate, name, IPFW_TLV_TBL_NAME));
}
+/*
+ * Parse table(NAME, value) and table(NAME,key=value)
+ */
static void
-fill_table_value(ipfw_insn *cmd, char *s)
+fill_table_value(ipfw_insn_lookup *cmd, char *s)
{
char *p;
int i;
@@ -3330,8 +3390,20 @@
p = s;
}
- IPFW_SET_TVALUE_TYPE(cmd, i);
- insntod(cmd, table)->value = strtoul(p, NULL, 0);
+ IPFW_SET_TVALUE_TYPE(&cmd->o, i);
+
+ if (i == TVALUE_NH6) {
+ if (inet_pton(AF_INET6, p, &cmd->ip6) != 1)
+ errx(EX_USAGE, "invalid IPv6 address provided");
+ /* mask in a dotted-quad notation */
+ } else if (strchr(p, '.') != NULL) {
+ if (inet_aton(p, &cmd->ip4) != 1)
+ errx(EX_USAGE, "invalid IPv4 address provided");
+ if (i == TVALUE_NH4)
+ return;
+ cmd->u32 = ntohl(cmd->u32);
+ } else
+ cmd->u32 = strtoul(p, NULL, 0);
}
void
@@ -3352,9 +3424,11 @@
cmd->opcode = opcode;
if (p) {
- cmd->len |= F_INSN_SIZE(ipfw_insn_table);
- fill_table_value(cmd, p);
+ cmd->len |= F_INSN_SIZE(ipfw_insn_lookup);
+ IPFW_SET_LOOKUP_MATCH_TVALUE(cmd, 1);
+ fill_table_value(insntod(cmd, lookup), p);
} else {
+ /* table(NAME) */
IPFW_SET_LOOKUP_TYPE(cmd, LOOKUP_NONE);
cmd->len |= F_INSN_SIZE(ipfw_insn_kidx);
}
@@ -4133,6 +4207,36 @@
return (ntohs(s->s_port));
}
+static void
+get_lookup_bitmask(int opcode, ipfw_insn_lookup *cmd, const char *src)
+{
+ struct ether_addr *mac;
+ const char *macset = "0123456789abcdefABCDEF:";
+
+ if (opcode == LOOKUP_SRC_IP6 || opcode == LOOKUP_DST_IP6) {
+ if (inet_pton(AF_INET6, src, &cmd->ip6) != 1)
+ errx(EX_USAGE, "invalid IPv6 mask provided");
+ } else if (opcode == LOOKUP_SRC_MAC || opcode == LOOKUP_DST_MAC) {
+ if (strspn(src, macset) != strlen(src) ||
+ (mac = ether_aton(src)) == NULL)
+ errx(EX_DATAERR, "Incorrect MAC address");
+
+ bcopy(mac, cmd->mac, ETHER_ADDR_LEN);
+ /* mask in a dotted-quad notation */
+ } else if (strchr(src, '.') != NULL) {
+ if (inet_aton(src, &cmd->ip4) != 1)
+ errx(EX_USAGE, "invalid dotted-quad mask provided");
+ switch (opcode) {
+ case LOOKUP_SRC_IP4:
+ case LOOKUP_DST_IP4:
+ return;
+ }
+ cmd->u32 = ntohl(cmd->u32);
+ return;
+ }
+ cmd->u32 = strtoul(src, NULL, 0);
+}
+
/*
* Parse arguments and assemble the microinstructions which make up a rule.
* Rules are added into the 'rulebuf' and then copied in the correct order
@@ -5469,13 +5573,13 @@
case TOK_LOOKUP: {
/* optional mask for some LOOKUP types */
- ipfw_insn_table *c = insntod(cmd, table);
+ ipfw_insn_lookup *c = insntod(cmd, lookup);
char *lkey;
if (!av[0] || !av[1])
errx(EX_USAGE,
"format: lookup argument tablenum");
- cmd->opcode = O_IP_DST_LOOKUP;
+ cmd->opcode = O_TABLE_LOOKUP;
lkey = strsep(av, ":");
i = match_token(lookup_keys, lkey);
@@ -5492,18 +5596,21 @@
case LOOKUP_DSCP:
case LOOKUP_MARK:
case LOOKUP_RULENUM:
+ case LOOKUP_SRC_MAC:
+ case LOOKUP_DST_MAC:
+ case LOOKUP_SRC_IP6:
+ case LOOKUP_DST_IP6:
+ case LOOKUP_SRC_IP4:
+ case LOOKUP_DST_IP4:
break;
default:
errx(EX_USAGE,
"masked lookup is not supported "
"for %s", lkey);
}
- cmd->len |= F_INSN_SIZE(ipfw_insn_table);
- c->value = strtoul(*av, NULL, 0);
- if (c->value == 0)
- errx(EX_USAGE,
- "all-zeroes bitmask for lookup "
- "is meaningless");
+ cmd->len |= F_INSN_SIZE(ipfw_insn_lookup);
+ IPFW_SET_LOOKUP_MASKING(cmd, 1);
+ get_lookup_bitmask(i, c, *av);
} else {
cmd->len |= F_INSN_SIZE(ipfw_insn_kidx);
}
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -250,9 +250,11 @@
*/
O_IPSEC = 58, /* has ipsec history */
O_IP_SRC_LOOKUP = 59, /* v0:arg1=table number, u32=value */
- /* v1:kidx=name, u32=value, arg1=key */
+ /* v1:lookup: kidx=name, arg1=key and */
+ /* flags, bitmask */
O_IP_DST_LOOKUP = 60, /* arg1=table number, u32=value */
- /* v1:kidx=name, u32=value, arg1=key */
+ /* v1:lookup: kidx=name, arg1=key and */
+ /* flags, bitmask */
O_ANTISPOOF = 61, /* none */
O_JAIL = 62, /* u32 = id */
O_ALTQ = 63, /* u32 = altq classif. qid */
@@ -295,7 +297,8 @@
O_DSCP = 87, /* 2 u32 = DSCP mask */
O_SETDSCP = 88, /* arg1=DSCP value */
O_IP_FLOW_LOOKUP = 89, /* v0:arg1=table number, u32=value */
- /* v1:kidx=name, u32=value */
+ /* v1:lookup: kidx=name, arg1=key and */
+ /* flags, bitmask */
O_EXTERNAL_ACTION = 90, /* v0:arg1=id of external action handler */
/* v1:kidx=id of external action handler */
@@ -306,12 +309,20 @@
O_SKIP_ACTION = 93, /* none */
O_TCPMSS = 94, /* arg1=MSS value */
- O_MAC_SRC_LOOKUP = 95, /* kidx=name, u32=value, arg1=key */
- O_MAC_DST_LOOKUP = 96, /* kidx=name, u32=value, arg1=key */
+ O_MAC_SRC_LOOKUP = 95, /* kidx=name */
+ /* v1:lookup: kidx=name, arg1=key and */
+ /* flags, bitmask */
+ O_MAC_DST_LOOKUP = 96, /* kidx=name */
+ /* v1:lookup: kidx=name, arg1=key and */
+ /* flags, bitmask */
O_SETMARK = 97, /* u32 = value */
O_MARK = 98, /* 2 u32 = value, bitmask */
+ O_TABLE_LOOKUP = 99, /* kidx=name */
+ /* v1:lookup: kidx=name, arg1=key and */
+ /* flags, bitmask */
+
O_LAST_OPCODE /* not an opcode! */
};
@@ -409,12 +420,32 @@
uint32_t value; /* table value */
} ipfw_insn_table;
-#define IPFW_LOOKUP_TYPE_MASK 0x00FF
+typedef struct _ipfw_insn_lookup {
+ ipfw_insn o; /* arg1 is flags and lookup key */
+ uint32_t kidx; /* table name index */
+ union { /* lookup mask */
+ uint64_t __mask64[2];
+ struct in6_addr ip6;
+ struct in_addr ip4;
+ char mac[6];
+ uint32_t u32;
+ };
+} ipfw_insn_lookup;
+
+#define IPFW_LOOKUP_TYPE_MASK 0x007F
#define IPFW_LOOKUP_TYPE(insn) ((insn)->arg1 & IPFW_LOOKUP_TYPE_MASK)
#define IPFW_SET_LOOKUP_TYPE(insn, type) do { \
(insn)->arg1 &= ~IPFW_LOOKUP_TYPE_MASK; \
(insn)->arg1 |= (type) & IPFW_LOOKUP_TYPE_MASK; \
} while (0)
+#define IPFW_LOOKUP_F_MASKING 0x0080
+#define IPFW_LOOKUP_MASKING(insn) ((insn)->arg1 & IPFW_LOOKUP_F_MASKING)
+#define IPFW_SET_LOOKUP_MASKING(insn, value) do { \
+ if (value) \
+ (insn)->arg1 |= IPFW_LOOKUP_F_MASKING; \
+ else \
+ (insn)->arg1 &= ~IPFW_LOOKUP_F_MASKING; \
+} while (0)
/*
* Defines key types used by lookup instruction
@@ -432,6 +463,10 @@
LOOKUP_SRC_MAC,
LOOKUP_MARK,
LOOKUP_RULENUM,
+ LOOKUP_DST_IP4,
+ LOOKUP_SRC_IP4,
+ LOOKUP_DST_IP6,
+ LOOKUP_SRC_IP6,
};
enum ipfw_return_type {
@@ -941,12 +976,20 @@
} a;
};
-#define IPFW_TVALUE_TYPE_MASK 0xFF00
+#define IPFW_TVALUE_TYPE_MASK 0x7F00
#define IPFW_TVALUE_TYPE(insn) (((insn)->arg1 & IPFW_TVALUE_TYPE_MASK) >> 8)
#define IPFW_SET_TVALUE_TYPE(insn, type) do { \
(insn)->arg1 &= ~IPFW_TVALUE_TYPE_MASK; \
(insn)->arg1 |= ((type) << 8) & IPFW_TVALUE_TYPE_MASK; \
} while (0)
+#define IPFW_LOOKUP_F_MATCH_TVALUE 0x8000
+#define IPFW_LOOKUP_MATCH_TVALUE(insn) ((insn)->arg1 & IPFW_LOOKUP_F_MATCH_TVALUE)
+#define IPFW_SET_LOOKUP_MATCH_TVALUE(insn, value) do { \
+ if (value) \
+ (insn)->arg1 |= IPFW_LOOKUP_F_MATCH_TVALUE; \
+ else \
+ (insn)->arg1 &= ~IPFW_LOOKUP_F_MATCH_TVALUE; \
+} while (0)
enum ipfw_table_value_type {
TVALUE_TAG = 0,
@@ -960,6 +1003,7 @@
TVALUE_DSCP,
TVALUE_LIMIT,
TVALUE_MARK,
+ TVALUE_NH6,
};
/* 64-byte structure representing multi-field table value */
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -1317,7 +1317,7 @@
#define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f)
static inline int
-tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd,
+tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_lookup *cmd,
uint32_t tablearg)
{
uint32_t tvalue;
@@ -1344,6 +1344,11 @@
case TVALUE_NH4:
tvalue = TARG_VAL(ch, tablearg, nh4);
break;
+ case TVALUE_NH6:
+ if (F_LEN(&cmd->o) != F_INSN_SIZE(ipfw_insn_lookup))
+ return (0);
+ return (0 == memcmp(&TARG_VAL(ch, tablearg, nh6),
+ &cmd->ip6, sizeof(struct in6_addr)));
case TVALUE_DSCP:
tvalue = TARG_VAL(ch, tablearg, dscp);
break;
@@ -1358,7 +1363,13 @@
tvalue = TARG_VAL(ch, tablearg, tag);
break;
}
- return (tvalue == cmd->value);
+ /*
+ * D53694 compatibility layer, to be removed.
+ * Match u32 values specified as ipfw_insn_table structure.
+ */
+ if (F_LEN(&cmd->o) == F_INSN_SIZE(ipfw_insn_table))
+ return (tvalue == insntoc(cmd, table)->value);
+ return (tvalue == cmd->u32);
}
/*
@@ -2102,45 +2113,101 @@
break;
case O_IP_DST_LOOKUP:
- if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE) {
- void *pkey = NULL;
- uint32_t key, vidx;
- uint16_t keylen = 0; /* zero if can't match the packet */
- uint8_t lookup_type;
+ case O_IP_SRC_LOOKUP:
+ /*
+ * D53694 compatibility layer, to be removed.
+ * The following if and subsequent fallthrough
+ * are here for backward opcode compatibility
+ * used for lookup opcode until O_TABLE_LOOKUP
+ * appeared.
+ */
+ if (IPFW_LOOKUP_TYPE(cmd) == LOOKUP_NONE) {
+ void *pkey;
+ uint32_t vidx;
+ uint16_t keylen;
+
+ if (is_ipv4) {
+ keylen = sizeof(in_addr_t);
+ if (cmd->opcode == O_IP_DST_LOOKUP)
+ pkey = &dst_ip;
+ else
+ pkey = &src_ip;
+ } else if (is_ipv6) {
+ keylen = sizeof(struct in6_addr);
+ if (cmd->opcode == O_IP_DST_LOOKUP)
+ pkey = &args->f_id.dst_ip6;
+ else
+ pkey = &args->f_id.src_ip6;
+ } else
+ break;
+ match = ipfw_lookup_table(chain,
+ insntod(cmd, kidx)->kidx,
+ keylen, pkey, &vidx);
+ if (!match)
+ break;
+ if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) {
+ match = tvalue_match(chain,
+ insntod(cmd, lookup), vidx);
+ if (!match)
+ break;
+ }
+ tablearg = vidx;
+ break;
+ }
+ /* FALLTHROUGH */
+ case O_TABLE_LOOKUP:
+ {
+ ipfw_insn_lookup key;
+ uint32_t vidx;
+ uint16_t keylen = 0; /* zero if can't match the packet */
+ uint8_t lookup_type;
lookup_type = IPFW_LOOKUP_TYPE(cmd);
switch (lookup_type) {
case LOOKUP_DST_IP:
+ case LOOKUP_DST_IP4:
+ if (is_ipv4) {
+ keylen = sizeof(in_addr_t);
+ key.ip4 = dst_ip;
+ break;
+ }
+ if (lookup_type == LOOKUP_DST_IP4)
+ break;
+ /* FALLTHOUGH */
+ case LOOKUP_DST_IP6:
+ if (is_ipv6 == 0)
+ break;
+ keylen = sizeof(struct in6_addr);
+ key.ip6 = args->f_id.dst_ip6;
+ break;
case LOOKUP_SRC_IP:
+ case LOOKUP_SRC_IP4:
if (is_ipv4) {
keylen = sizeof(in_addr_t);
- if (lookup_type == LOOKUP_DST_IP)
- pkey = &dst_ip;
- else
- pkey = &src_ip;
- } else if (is_ipv6) {
- keylen = sizeof(struct in6_addr);
- if (lookup_type == LOOKUP_DST_IP)
- pkey = &args->f_id.dst_ip6;
- else
- pkey = &args->f_id.src_ip6;
+ key.ip4 = src_ip;
+ break;
}
+ if (lookup_type == LOOKUP_SRC_IP4)
+ break;
+ /* FALLTHOUGH */
+ case LOOKUP_SRC_IP6:
+ if (is_ipv6 == 0)
+ break;
+ keylen = sizeof(struct in6_addr);
+ key.ip6 = args->f_id.src_ip6;
break;
case LOOKUP_DSCP:
if (is_ipv4)
- key = ip->ip_tos >> 2;
+ key.u32 = ip->ip_tos >> 2;
else if (is_ipv6)
- key = IPV6_DSCP(
+ key.u32 = IPV6_DSCP(
(struct ip6_hdr *)ip) >> 2;
else
break; /* only for L3 */
- key &= 0x3f;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table))
- key &= insntod(cmd, table)->value;
- pkey = &key;
- keylen = sizeof(key);
+ keylen = sizeof(key.u32);
+ key.u32 &= 0x3f;
break;
case LOOKUP_DST_PORT:
case LOOKUP_SRC_PORT:
@@ -2159,23 +2226,26 @@
proto != IPPROTO_SCTP)
break;
if (lookup_type == LOOKUP_DST_PORT)
- key = dst_port;
+ key.u32 = dst_port;
else
- key = src_port;
- pkey = &key;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table))
- key &= insntod(cmd, table)->value;
- keylen = sizeof(key);
+ key.u32 = src_port;
+ keylen = sizeof(key.u32);
break;
case LOOKUP_DST_MAC:
+ /* only for L2 */
+ if ((args->flags & IPFW_ARGS_ETHER) == 0)
+ break;
+ keylen = ETHER_ADDR_LEN;
+ memcpy(key.mac, eh->ether_dhost,
+ sizeof(key.mac));
+ break;
case LOOKUP_SRC_MAC:
/* only for L2 */
if ((args->flags & IPFW_ARGS_ETHER) == 0)
break;
-
- pkey = lookup_type == LOOKUP_DST_MAC ?
- eh->ether_dhost : eh->ether_shost;
keylen = ETHER_ADDR_LEN;
+ memcpy(key.mac, eh->ether_shost,
+ sizeof(key.mac));
break;
#ifndef USERSPACE
case LOOKUP_UID:
@@ -2185,84 +2255,61 @@
#ifdef __FreeBSD__
&ucred_cache);
if (lookup_type == LOOKUP_UID)
- key = ucred_cache->cr_uid;
+ key.u32 = ucred_cache->cr_uid;
else if (lookup_type == LOOKUP_JAIL)
- key = ucred_cache->cr_prison->pr_id;
+ key.u32 = ucred_cache->cr_prison->pr_id;
#else /* !__FreeBSD__ */
(void *)&ucred_cache);
if (lookup_type == LOOKUP_UID)
- key = ucred_cache.uid;
+ key.u32 = ucred_cache.uid;
else if (lookup_type == LOOKUP_JAIL)
- key = ucred_cache.xid;
+ key.u32 = ucred_cache.xid;
#endif /* !__FreeBSD__ */
- pkey = &key;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table))
- key &= insntod(cmd, table)->value;
- keylen = sizeof(key);
+ keylen = sizeof(key.u32);
break;
#endif /* !USERSPACE */
case LOOKUP_MARK:
- key = args->rule.pkt_mark;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table))
- key &= insntod(cmd, table)->value;
- pkey = &key;
- keylen = sizeof(key);
+ key.u32 = args->rule.pkt_mark;
+ keylen = sizeof(key.u32);
break;
case LOOKUP_RULENUM:
- key = f->rulenum;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table))
- key &= insntod(cmd, table)->value;
- pkey = &key;
- keylen = sizeof(key);
+ key.u32 = f->rulenum;
+ keylen = sizeof(key.u32);
break;
}
/* unknown key type */
if (keylen == 0)
break;
- match = ipfw_lookup_table(chain,
- insntod(cmd, kidx)->kidx, keylen,
- pkey, &vidx);
- if (match)
- tablearg = vidx;
- break;
- }
- /* LOOKUP_NONE */
- /* FALLTHROUGH */
- case O_IP_SRC_LOOKUP:
- {
- void *pkey;
- uint32_t vidx;
- uint16_t keylen;
+ if (IPFW_LOOKUP_MASKING(cmd) == 0) {
+ /* no masking needed */
+ } else if (cmdlen ==
+ F_INSN_SIZE(ipfw_insn_table)) {
+ /*
+ * D53694 compatibility layer,
+ * to be removed.
+ */
+ key.u32 &= insntod(cmd, table)->value;
+ } else {
+ key.__mask64[0] &=
+ insntod(cmd, lookup)->__mask64[0];
+ key.__mask64[1] &=
+ insntod(cmd, lookup)->__mask64[1];
+ }
- if (is_ipv4) {
- keylen = sizeof(in_addr_t);
- if (cmd->opcode == O_IP_DST_LOOKUP)
- pkey = &dst_ip;
- else
- pkey = &src_ip;
- } else if (is_ipv6) {
- keylen = sizeof(struct in6_addr);
- if (cmd->opcode == O_IP_DST_LOOKUP)
- pkey = &args->f_id.dst_ip6;
- else
- pkey = &args->f_id.src_ip6;
- } else
- break;
match = ipfw_lookup_table(chain,
- insntod(cmd, kidx)->kidx,
- keylen, pkey, &vidx);
+ insntod(cmd, kidx)->kidx, keylen,
+ key.__mask64, &vidx);
+
if (!match)
break;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) {
- match = tvalue_match(chain,
- insntod(cmd, table), vidx);
- if (!match)
- break;
- }
+ /*
+ * XXX should we support check for value
+ * simultaneously with masked lookup?
+ */
tablearg = vidx;
break;
- }
+ } /* O_TABLE_LOOKUP */
case O_MAC_SRC_LOOKUP:
case O_MAC_DST_LOOKUP:
@@ -2285,9 +2332,9 @@
keylen, pkey, &vidx);
if (!match)
break;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) {
+ if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) {
match = tvalue_match(chain,
- insntod(cmd, table), vidx);
+ insntod(cmd, lookup), vidx);
if (!match)
break;
}
@@ -2304,9 +2351,9 @@
&args->f_id, &vidx);
if (!match)
break;
- if (cmdlen == F_INSN_SIZE(ipfw_insn_table))
+ if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0)
match = tvalue_match(chain,
- insntod(cmd, table), vidx);
+ insntod(cmd, lookup), vidx);
if (match)
tablearg = vidx;
break;
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1469,6 +1469,7 @@
case O_MAC_SRC_LOOKUP:
case O_MAC_DST_LOOKUP:
if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) &&
+ cmdlen != F_INSN_SIZE(ipfw_insn_lookup) &&
cmdlen != F_INSN_SIZE(ipfw_insn_table))
return (BAD_SIZE);
if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) {
@@ -1477,6 +1478,37 @@
return (FAILED);
}
ci->object_opcodes++;
+ /*
+ * D53694 compatibility layer, to be removed.
+
+ * ipfw_insn_table was used to match table value for u32
+ * values and cmdlen was used to detect such intention.
+ * A special flag is now used for that in module so
+ * adopt legacy sbin/ipfw behavior and set it for all
+ * lookup instructions with ipfw_insn_table opcode.
+ *
+ * Lookup type different from LOOKUP_NONE was used for
+ * 32-bit bitmasking prior to lookup.
+ * Table value matching was expected otherwise.
+ */
+ if (cmdlen != F_INSN_SIZE(ipfw_insn_table))
+ break;
+
+ if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE)
+ IPFW_SET_LOOKUP_MASKING(cmd, 1);
+ else
+ IPFW_SET_LOOKUP_MATCH_TVALUE(cmd, 1);
+ break;
+ case O_TABLE_LOOKUP:
+ if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) &&
+ cmdlen != F_INSN_SIZE(ipfw_insn_lookup))
+ return (BAD_SIZE);
+ if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) {
+ printf("ipfw: invalid table index %u\n",
+ insntod(cmd, kidx)->kidx);
+ return (FAILED);
+ }
+ ci->object_opcodes++;
break;
case O_MACADDR2:
if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -2422,14 +2422,18 @@
static int
classify_srcdst(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype)
{
- ipfw_insn_table *cmd;
+ ipfw_insn_lookup *cmd;
/* Basic IPv4/IPv6 or u32 lookups */
- cmd = insntod(cmd0, table);
+ cmd = insntod(cmd0, lookup);
*puidx = cmd->kidx;
- switch(cmd0->arg1) {
+ switch(IPFW_LOOKUP_TYPE(cmd0)) {
case LOOKUP_DST_IP:
case LOOKUP_SRC_IP:
+ case LOOKUP_DST_IP4:
+ case LOOKUP_SRC_IP4:
+ case LOOKUP_DST_IP6:
+ case LOOKUP_SRC_IP6:
default:
/* IPv4 src/dst */
*ptype = IPFW_TABLE_ADDR;
@@ -2469,7 +2473,7 @@
static int
classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype)
{
- *puidx = insntod(cmd0, table)->kidx;
+ *puidx = insntod(cmd0, kidx)->kidx;
*ptype = IPFW_TABLE_FLOW;
return (0);
}
@@ -2477,7 +2481,7 @@
static int
classify_mac_lookup(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype)
{
- *puidx = insntod(cmd0, table)->kidx;
+ *puidx = insntod(cmd0, kidx)->kidx;
*ptype = IPFW_TABLE_MAC;
return (0);
}
@@ -2485,7 +2489,7 @@
static void
update_kidx(ipfw_insn *cmd0, uint32_t idx)
{
- insntod(cmd0, table)->kidx = idx;
+ insntod(cmd0, kidx)->kidx = idx;
}
static void
@@ -2618,6 +2622,16 @@
.create_object = create_table_compat,
.manage_sets = table_manage_sets,
},
+ {
+ .opcode = O_TABLE_LOOKUP,
+ .etlv = IPFW_TLV_TBL_NAME,
+ .classifier = classify_srcdst,
+ .update = update_kidx,
+ .find_byname = table_findbyname,
+ .find_bykidx = table_findbykidx,
+ .create_object = create_table_compat,
+ .manage_sets = table_manage_sets,
+ },
{
.opcode = O_IP_FLOW_LOOKUP,
.etlv = IPFW_TLV_TBL_NAME,
diff --git a/tests/atf_python/sys/netpfil/ipfw/insn_headers.py b/tests/atf_python/sys/netpfil/ipfw/insn_headers.py
--- a/tests/atf_python/sys/netpfil/ipfw/insn_headers.py
+++ b/tests/atf_python/sys/netpfil/ipfw/insn_headers.py
@@ -101,7 +101,8 @@
O_MAC_DST_LOOKUP = 96
O_SETMARK = 97
O_MARK = 98
- O_LAST_OPCODE = 99
+ O_TABLE_LOOKUP = 99
+ O_LAST_OPCODE = 100
class Op3CmdType(Enum):
diff --git a/tests/atf_python/sys/netpfil/ipfw/ioctl_headers.py b/tests/atf_python/sys/netpfil/ipfw/ioctl_headers.py
--- a/tests/atf_python/sys/netpfil/ipfw/ioctl_headers.py
+++ b/tests/atf_python/sys/netpfil/ipfw/ioctl_headers.py
@@ -71,6 +71,11 @@
LOOKUP_DST_MAC = 7
LOOKUP_SRC_MAC = 8
LOOKUP_MARK = 9
+ LOOKUP_RULENUM = 10
+ LOOKUP_DST_IP4 = 11
+ LOOKUP_SRC_IP4 = 12
+ LOOKUP_DST_IP6 = 13
+ LOOKUP_SRC_IP6 = 14
class IpFwTlvType(Enum):

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 24, 2:45 AM (14 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27893029
Default Alt Text
D53694.id166867.diff (32 KB)

Event Timeline