summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/ipfw/ipfw.814
-rw-r--r--sbin/ipfw/ipfw2.c45
-rw-r--r--sbin/ipfw/ipfw2.h1
-rw-r--r--sys/netinet/ipfw/ip_fw2.c31
4 files changed, 91 insertions, 0 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 1483dd0..fc83ecc 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1391,6 +1391,20 @@ of source and destination addresses and ports can be
specified.
Currently,
only IPv4 flows are supported.
+.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar N
+Search an entry in lookup table
+.Ar N
+that matches the field specified as argument.
+If not found, the match fails.
+Otherwise, the match succeeds and
+.Cm tablearg
+is set to the value extracted from the table.
+.Br
+This option can be useful to quickly dispatch traffic based on
+certain packet fields.
+See the
+.Sx LOOKUP TABLES
+section below for more information on lookup tables.
.It Cm { MAC | mac } Ar dst-mac src-mac
Match packets with a given
.Ar dst-mac
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 7edfbd5..d4740c9 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -224,6 +224,15 @@ static struct _s_x rule_action_params[] = {
{ NULL, 0 } /* terminator */
};
+/*
+ * The 'lookup' instruction accepts one of the following arguments.
+ * -1 is a terminator for the list.
+ * Arguments are passed as v[1] in O_DST_LOOKUP options.
+ */
+static int lookup_key[] = {
+ TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,
+ TOK_UID, TOK_JAIL, -1 };
+
static struct _s_x rule_options[] = {
{ "tagged", TOK_TAGGED },
{ "uid", TOK_UID },
@@ -290,6 +299,7 @@ static struct _s_x rule_options[] = {
{ "dst-ip6", TOK_DSTIP6},
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
+ { "lookup", TOK_LOOKUP},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -742,6 +752,16 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
int len = F_LEN((ipfw_insn *)cmd);
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
+ if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
+ uint32_t d = a[1];
+ const char *arg = "<invalid>";
+
+ if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
+ arg = match_value(rule_options, lookup_key[d]);
+ printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "",
+ arg, cmd->o.arg1);
+ return;
+ }
printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
@@ -3479,6 +3499,31 @@ read_options:
ac--; av++;
break;
+ case TOK_LOOKUP: {
+ ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
+ char *p;
+ int j;
+
+ if (ac < 2)
+ errx(EX_USAGE, "format: lookup argument tablenum");
+ cmd->opcode = O_IP_DST_LOOKUP;
+ cmd->len |= F_INSN_SIZE(ipfw_insn) + 2;
+ i = match_token(rule_options, *av);
+ for (j = 0; lookup_key[j] >= 0 ; j++) {
+ if (i == lookup_key[j])
+ break;
+ }
+ if (lookup_key[j] <= 0)
+ errx(EX_USAGE, "format: cannot lookup on %s", *av);
+ c->d[1] = j; // i converted to option
+ ac--; av++;
+ cmd->arg1 = strtoul(*av, &p, 0);
+ if (p && *p)
+ errx(EX_USAGE, "format: lookup argument tablenum");
+ ac--; av++;
+ }
+ break;
+
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
}
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index d3ce7fb..b393a7d 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -186,6 +186,7 @@ enum tokens {
TOK_FIB,
TOK_SETFIB,
+ TOK_LOOKUP,
};
/*
* the following macro returns an error message if we run out of
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index 601d80e..7010e19 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -2819,6 +2819,36 @@ do { \
dst_ip.s_addr : src_ip.s_addr;
uint32_t v = 0;
+ if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+ /* generic lookup */
+ v = ((ipfw_insn_u32 *)cmd)->d[1];
+ if (v == 0)
+ a = dst_ip.s_addr;
+ else if (v == 1)
+ a = src_ip.s_addr;
+ else if (offset != 0)
+ break;
+ else if (proto != IPPROTO_TCP &&
+ proto != IPPROTO_UDP)
+ break;
+ else if (v == 2)
+ a = dst_port;
+ else if (v == 3)
+ a = src_port;
+ else if (v == 4 || v == 5) {
+ check_uidgid(
+ (ipfw_insn_u32 *)cmd,
+ proto, oif,
+ dst_ip, dst_port,
+ src_ip, src_port, &ucred_cache,
+ &ucred_lookup, args->inp);
+ if (v == 4 /* O_UID */)
+ a = ucred_cache->cr_uid;
+ else if (v == 5 /* O_JAIL */)
+ a = ucred_cache->cr_prison->pr_id;
+ } else
+ break;
+ }
match = lookup_table(chain, cmd->arg1, a,
&v);
if (!match)
@@ -4160,6 +4190,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
return (EINVAL);
}
if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
+ cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
cmdlen != F_INSN_SIZE(ipfw_insn_u32))
goto bad_size;
break;
OpenPOWER on IntegriCloud