Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142761826
D53694.id166868.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
32 KB
Referenced Files
None
Subscribers
None
D53694.id166868.diff
View Options
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,52 @@
.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
See the
.Sx LOOKUP TABLES
section below for more information on lookup tables.
@@ -1983,7 +2044,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 +2062,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 +4370,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 +4726,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
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 24, 7:03 AM (19 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27894739
Default Alt Text
D53694.id166868.diff (32 KB)
Attached To
Mode
D53694: [ipfw] Add support for masked ip-address lookups
Attached
Detach File
Event Timeline
Log In to Comment