implement a new match option,

lookup {dst-ip|src-ip|dst-port|src-port|uid|jail} N

which searches the specified field in table N and sets tablearg
accordingly.
With dst-ip or src-ip the option replicates two existing options.
When used with other arguments, the option can be useful to
quickly dispatch traffic based on other fields.

Work supported by the Onelab project.

MFC after:	1 week
This commit is contained in:
Luigi Rizzo 2009-12-15 09:46:27 +00:00
parent 2f12516b1f
commit 472099c4b0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=200567
4 changed files with 91 additions and 0 deletions

View File

@ -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

View File

@ -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 @@ ipfw_add(int ac, char *av[])
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);
}

View File

@ -186,6 +186,7 @@ enum tokens {
TOK_FIB,
TOK_SETFIB,
TOK_LOOKUP,
};
/*
* the following macro returns an error message if we run out of

View File

@ -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;