Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Dec 2009 09:46:27 +0000 (UTC)
From:      Luigi Rizzo <luigi@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r200567 - in head: sbin/ipfw sys/netinet/ipfw
Message-ID:  <200912150946.nBF9kRHE056939@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: luigi
Date: Tue Dec 15 09:46:27 2009
New Revision: 200567
URL: http://svn.freebsd.org/changeset/base/200567

Log:
  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

Modified:
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/ipfw2.c
  head/sbin/ipfw/ipfw2.h
  head/sys/netinet/ipfw/ip_fw2.c

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8	Tue Dec 15 09:32:35 2009	(r200566)
+++ head/sbin/ipfw/ipfw.8	Tue Dec 15 09:46:27 2009	(r200567)
@@ -1391,6 +1391,20 @@ of source and destination addresses and 
 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

Modified: head/sbin/ipfw/ipfw2.c
==============================================================================
--- head/sbin/ipfw/ipfw2.c	Tue Dec 15 09:32:35 2009	(r200566)
+++ head/sbin/ipfw/ipfw2.c	Tue Dec 15 09:46:27 2009	(r200567)
@@ -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 *
 	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);
 		}

Modified: head/sbin/ipfw/ipfw2.h
==============================================================================
--- head/sbin/ipfw/ipfw2.h	Tue Dec 15 09:32:35 2009	(r200566)
+++ head/sbin/ipfw/ipfw2.h	Tue Dec 15 09:46:27 2009	(r200567)
@@ -186,6 +186,7 @@ enum tokens {
 
 	TOK_FIB,
 	TOK_SETFIB,
+	TOK_LOOKUP,
 };
 /*
  * the following macro returns an error message if we run out of

Modified: head/sys/netinet/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netinet/ipfw/ip_fw2.c	Tue Dec 15 09:32:35 2009	(r200566)
+++ head/sys/netinet/ipfw/ip_fw2.c	Tue Dec 15 09:46:27 2009	(r200567)
@@ -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, in
 				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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912150946.nBF9kRHE056939>