Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 5 Mar 2017 23:48:24 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314716 - head/sys/netpfil/ipfw
Message-ID:  <201703052348.v25NmOI1032562@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Sun Mar  5 23:48:24 2017
New Revision: 314716
URL: https://svnweb.freebsd.org/changeset/base/314716

Log:
  Add IPv6 support to O_IP_DST_LOOKUP opcode.
  
  o check the size of O_IP_SRC_LOOKUP opcode, it can not exceed the size of
    ipfw_insn_u32;
  o rename ipfw_lookup_table_extended() function into ipfw_lookup_table() and
    remove old ipfw_lookup_table();
  o use args->f_id.flow_id6 that is in host byte order to get DSCP value;
  o add SCTP ports support to 'lookup src/dst-port' opcode;
  o add IPv6 support to 'lookup src/dst-ip' opcode.
  
  PR:		217292
  Reviewed by:	melifaro
  MFC after:	2 weeks
  Sponsored by:	Yandex LLC
  Differential Revision:	https://reviews.freebsd.org/D9873

Modified:
  head/sys/netpfil/ipfw/ip_fw2.c
  head/sys/netpfil/ipfw/ip_fw_private.h
  head/sys/netpfil/ipfw/ip_fw_sockopt.c
  head/sys/netpfil/ipfw/ip_fw_table.c

Modified: head/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw2.c	Sun Mar  5 22:19:43 2017	(r314715)
+++ head/sys/netpfil/ipfw/ip_fw2.c	Sun Mar  5 23:48:24 2017	(r314716)
@@ -382,8 +382,8 @@ iface_match(struct ifnet *ifp, ipfw_insn
 	/* Check by name or by IP address */
 	if (cmd->name[0] != '\0') { /* match by name */
 		if (cmd->name[0] == '\1') /* use tablearg to match */
-			return ipfw_lookup_table_extended(chain, cmd->p.kidx, 0,
-				&ifp->if_index, tablearg);
+			return ipfw_lookup_table(chain, cmd->p.kidx, 0,
+			    &ifp->if_index, tablearg);
 		/* Check name */
 		if (cmd->p.glob) {
 			if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -1455,86 +1455,130 @@ do {								\
 				    src_ip.s_addr);
 				break;
 
-			case O_IP_SRC_LOOKUP:
 			case O_IP_DST_LOOKUP:
-				if (is_ipv4) {
-				    uint32_t key =
-					(cmd->opcode == O_IP_DST_LOOKUP) ?
-					    dst_ip.s_addr : src_ip.s_addr;
-				    uint32_t v = 0;
-
-				    if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
-					/* generic lookup. The key must be
-					 * in 32bit big-endian format.
-					 */
-					v = ((ipfw_insn_u32 *)cmd)->d[1];
-					if (v == 0)
-					    key = dst_ip.s_addr;
-					else if (v == 1)
-					    key = src_ip.s_addr;
-					else if (v == 6) /* dscp */
-					    key = (ip->ip_tos >> 2) & 0x3f;
-					else if (offset != 0)
-					    break;
-					else if (proto != IPPROTO_TCP &&
-						proto != IPPROTO_UDP)
-					    break;
-					else if (v == 2)
-					    key = dst_port;
-					else if (v == 3)
-					    key = src_port;
+			{
+				void *pkey;
+				uint32_t vidx, key;
+				uint16_t keylen;
+
+				if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+					/* Determine lookup key type */
+					vidx = ((ipfw_insn_u32 *)cmd)->d[1];
+					if (vidx != 4 /* uid */ &&
+					    vidx != 5 /* jail */ &&
+					    is_ipv6 == 0 && is_ipv4 == 0)
+						break;
+					/* Determine key length */
+					if (vidx == 0 /* dst-ip */ ||
+					    vidx == 1 /* src-ip */)
+						keylen = is_ipv6 ?
+						    sizeof(struct in6_addr):
+						    sizeof(in_addr_t);
+					else {
+						keylen = sizeof(key);
+						pkey = &key;
+					}
+					if (vidx == 0 /* dst-ip */)
+						pkey = is_ipv4 ? (void *)&dst_ip:
+						    (void *)&args->f_id.dst_ip6;
+					else if (vidx == 1 /* src-ip */)
+						pkey = is_ipv4 ? (void *)&src_ip:
+						    (void *)&args->f_id.src_ip6;
+					else if (vidx == 6 /* dscp */) {
+						if (is_ipv4)
+							key = ip->ip_tos >> 2;
+						else {
+							key = args->f_id.flow_id6;
+							key = (key & 0x0f) << 2 |
+							    (key & 0xf000) >> 14;
+						}
+						key &= 0x3f;
+					} else if (vidx == 2 /* dst-port */ ||
+					    vidx == 3 /* src-port */) {
+						/* Skip fragments */
+						if (offset != 0)
+							break;
+						/* Skip proto without ports */
+						if (proto != IPPROTO_TCP &&
+						    proto != IPPROTO_UDP &&
+						    proto != IPPROTO_SCTP)
+							break;
+						if (vidx == 2 /* dst-port */)
+							key = dst_port;
+						else
+							key = src_port;
+					}
 #ifndef USERSPACE
-					else if (v == 4 || v == 5) {
-					    check_uidgid(
-						(ipfw_insn_u32 *)cmd,
-						args, &ucred_lookup,
+					else if (vidx == 4 /* uid */ ||
+					    vidx == 5 /* jail */) {
+						check_uidgid(
+						    (ipfw_insn_u32 *)cmd,
+						    args, &ucred_lookup,
 #ifdef __FreeBSD__
-						&ucred_cache);
-					    if (v == 4 /* O_UID */)
-						key = ucred_cache->cr_uid;
-					    else if (v == 5 /* O_JAIL */)
-						key = ucred_cache->cr_prison->pr_id;
+						    &ucred_cache);
+						if (vidx == 4 /* uid */)
+							key = ucred_cache->cr_uid;
+						else if (vidx == 5 /* jail */)
+							key = ucred_cache->cr_prison->pr_id;
 #else /* !__FreeBSD__ */
-						(void *)&ucred_cache);
-					    if (v ==4 /* O_UID */)
-						key = ucred_cache.uid;
-					    else if (v == 5 /* O_JAIL */)
-						key = ucred_cache.xid;
+						    (void *)&ucred_cache);
+						if (vidx == 4 /* uid */)
+							key = ucred_cache.uid;
+						else if (vidx == 5 /* jail */)
+							key = ucred_cache.xid;
 #endif /* !__FreeBSD__ */
 					}
 #endif /* !USERSPACE */
 					else
-					    break;
-				    }
-				    match = ipfw_lookup_table(chain,
-					cmd->arg1, key, &v);
-				    if (!match)
+						break;
+					match = ipfw_lookup_table(chain,
+					    cmd->arg1, keylen, pkey, &vidx);
+					if (!match)
+						break;
+					tablearg = vidx;
 					break;
-				    if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
-					match = ((ipfw_insn_u32 *)cmd)->d[0] ==
-					    TARG_VAL(chain, v, tag);
-				    else
-					tablearg = v;
+				}
+				/* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */
+				/* FALLTHROUGH */
+			}
+			case O_IP_SRC_LOOKUP:
+			{
+				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) {
-					uint32_t v = 0;
-					void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
-						&args->f_id.dst_ip6: &args->f_id.src_ip6;
-					match = ipfw_lookup_table_extended(chain,
-							cmd->arg1,
-							sizeof(struct in6_addr),
-							pkey, &v);
-					if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
-						match = ((ipfw_insn_u32 *)cmd)->d[0] ==
-						    TARG_VAL(chain, v, tag);
-					if (match)
-						tablearg = v;
+					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, cmd->arg1,
+				    keylen, pkey, &vidx);
+				if (!match)
+					break;
+				if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
+					match = ((ipfw_insn_u32 *)cmd)->d[0] ==
+					    TARG_VAL(chain, vidx, tag);
+					if (!match)
+						break;
 				}
+				tablearg = vidx;
 				break;
+			}
 
 			case O_IP_FLOW_LOOKUP:
 				{
 					uint32_t v = 0;
-					match = ipfw_lookup_table_extended(chain,
+					match = ipfw_lookup_table(chain,
 					    cmd->arg1, 0, &args->f_id, &v);
 					if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
 						match = ((ipfw_insn_u32 *)cmd)->d[0] ==

Modified: head/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_private.h	Sun Mar  5 22:19:43 2017	(r314715)
+++ head/sys/netpfil/ipfw/ip_fw_private.h	Sun Mar  5 23:48:24 2017	(r314716)
@@ -741,10 +741,8 @@ struct table_info;
 typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen,
     uint32_t *val);
 
-int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
-    uint32_t *val);
-int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl,
-    uint16_t plen, void *paddr, uint32_t *val);
+int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+    void *paddr, uint32_t *val);
 struct named_object *ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch,
     uint16_t kidx);
 int ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx);

Modified: head/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Mar  5 22:19:43 2017	(r314715)
+++ head/sys/netpfil/ipfw/ip_fw_sockopt.c	Sun Mar  5 23:48:24 2017	(r314716)
@@ -1826,6 +1826,8 @@ check_ipfw_rule_body(ipfw_insn *cmd, int
 			break;
 
 		case O_IP_SRC_LOOKUP:
+			if (cmdlen > F_INSN_SIZE(ipfw_insn_u32))
+				goto bad_size;
 		case O_IP_DST_LOOKUP:
 			if (cmd->arg1 >= V_fw_tables_max) {
 				printf("ipfw: invalid table number %d\n",

Modified: head/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_table.c	Sun Mar  5 22:19:43 2017	(r314715)
+++ head/sys/netpfil/ipfw/ip_fw_table.c	Sun Mar  5 23:48:24 2017	(r314716)
@@ -1657,30 +1657,13 @@ ipfw_unref_table(struct ip_fw_chain *ch,
 }
 
 /*
- * Lookup an IP @addr in table @tbl.
- * Stores found value in @val.
- *
- * Returns 1 if @addr was found.
- */
-int
-ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
-    uint32_t *val)
-{
-	struct table_info *ti;
-
-	ti = KIDX_TO_TI(ch, tbl);
-
-	return (ti->lookup(ti, &addr, sizeof(in_addr_t), val));
-}
-
-/*
  * Lookup an arbtrary key @paddr of legth @plen in table @tbl.
  * Stores found value in @val.
  *
  * Returns 1 if key was found.
  */
 int
-ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
     void *paddr, uint32_t *val)
 {
 	struct table_info *ti;



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