Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Mar 2015 09:03:26 +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: r279948 - in head: sbin/ipfw sys/netinet sys/netpfil/ipfw
Message-ID:  <201503130903.t2D93Qwg062580@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Fri Mar 13 09:03:25 2015
New Revision: 279948
URL: https://svnweb.freebsd.org/changeset/base/279948

Log:
  Fix `ipfw fwd tablearg'. Use dedicated field nh4 in struct table_value
  to obtain IPv4 next hop address in tablearg case.
  
  Add `fwd tablearg' support for IPv6. ipfw(8) uses INADDR_ANY as next hop
  address in O_FORWARD_IP opcode for specifying tablearg case. For IPv6 we
  still use this opcode, but when packet identified as IPv6 packet, we
  obtain next hop address from dedicated field nh6 in struct table_value.
  
  Replace hopstore field in struct ip_fw_args with anonymous union and add
  hopstore6 field. Use this field to copy tablearg value for IPv6.
  
  Replace spare1 field in struct table_value with zoneid. Use it to keep
  scope zone id for link-local IPv6 addresses. Since spare1 was used
  internally, replace spare0 array with two variables spare0 and spare1.
  
  Use getaddrinfo(3)/getnameinfo(3) functions for parsing and formatting
  IPv6 addresses in table_value. Use zoneid field in struct table_value
  to store sin6_scope_id value.
  
  Since the kernel still uses embedded scope zone id to represent
  link-local addresses, convert next_hop6 address into this form before
  return from pfil processing. This also fixes in6_localip() check
  for link-local addresses.
  
  Differential Revision:	https://reviews.freebsd.org/D2015
  Obtained from:	Yandex LLC
  Sponsored by:	Yandex LLC

Modified:
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/tables.c
  head/sys/netinet/ip_fw.h
  head/sys/netpfil/ipfw/ip_fw2.c
  head/sys/netpfil/ipfw/ip_fw_pfil.c
  head/sys/netpfil/ipfw/ip_fw_private.h
  head/sys/netpfil/ipfw/ip_fw_table_value.c

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sbin/ipfw/ipfw.8	Fri Mar 13 09:03:25 2015	(r279948)
@@ -1,7 +1,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd Aug 13, 2014
+.Dd March 13, 2015
 .Dt IPFW 8
 .Os
 .Sh NAME
@@ -2078,6 +2078,8 @@ hook number to move packet to.
 maximum number of connections.
 .It Cm ipv4
 IPv4 nexthop to fwd packets to.
+.It Cm ipv6
+IPv6 nexthop to fwd packets to.
 .El
 .Pp
 The

Modified: head/sbin/ipfw/tables.c
==============================================================================
--- head/sbin/ipfw/tables.c	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sbin/ipfw/tables.c	Fri Mar 13 09:03:25 2015	(r279948)
@@ -35,6 +35,7 @@
 #include <netinet/in.h>
 #include <netinet/ip_fw.h>
 #include <arpa/inet.h>
+#include <netdb.h>
 
 #include "ipfw2.h"
 
@@ -1384,6 +1385,7 @@ static void
 tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
     uint8_t type, uint32_t vmask)
 {
+	struct addrinfo hints, *res;
 	uint32_t a4, flag, val, vm;
 	ipfw_table_value *v;
 	uint32_t i;
@@ -1494,9 +1496,19 @@ tentry_fill_value(ipfw_obj_header *oh, i
 			}
 			break;
 		case IPFW_VTYPE_NH6:
-			if (strchr(n, ':') != NULL &&
-			    inet_pton(AF_INET6, n, &v->nh6) == 1)
-				break;
+			if (strchr(n, ':') != NULL) {
+				memset(&hints, 0, sizeof(hints));
+				hints.ai_family = AF_INET6;
+				hints.ai_flags = AI_NUMERICHOST;
+				if (getaddrinfo(n, NULL, &hints, &res) == 0) {
+					v->nh6 = ((struct sockaddr_in6 *)
+					    res->ai_addr)->sin6_addr;
+					v->zoneid = ((struct sockaddr_in6 *)
+					    res->ai_addr)->sin6_scope_id;
+					freeaddrinfo(res);
+					break;
+				}
+			}
 			etype = "ipv6";
 			break;
 		}
@@ -1643,10 +1655,11 @@ static void
 table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
     uint32_t vmask, int print_ip)
 {
+	char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
+	struct sockaddr_in6 sa6;
 	uint32_t flag, i, l;
 	size_t sz;
 	struct in_addr a4;
-	char abuf[INET6_ADDRSTRLEN];
 
 	sz = bufsize;
 
@@ -1702,8 +1715,15 @@ table_show_value(char *buf, size_t bufsi
 			l = snprintf(buf, sz, "%d,", v->dscp);
 			break;
 		case IPFW_VTYPE_NH6:
-			inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf));
-			l = snprintf(buf, sz, "%s,", abuf);
+			sa6.sin6_family = AF_INET6;
+			sa6.sin6_len = sizeof(sa6);
+			sa6.sin6_addr = v->nh6;
+			sa6.sin6_port = 0;
+			sa6.sin6_scope_id = v->zoneid;
+			if (getnameinfo((const struct sockaddr *)&sa6,
+			    sa6.sin6_len, abuf, sizeof(abuf), NULL, 0,
+			    NI_NUMERICHOST) == 0)
+				l = snprintf(buf, sz, "%s,", abuf);
 			break;
 		}
 
@@ -1862,11 +1882,12 @@ struct _table_value {
 	uint32_t	nat;		/* O_NAT */
 	uint32_t	nh4;
 	uint8_t		dscp;
-	uint8_t		spare0[3];
+	uint8_t		spare0;
+	uint16_t	spare1;
 	/* -- 32 bytes -- */
 	struct in6_addr	nh6;
 	uint32_t	limit;		/* O_LIMIT */
-	uint32_t	spare1;
+	uint32_t	zoneid;
 	uint64_t	refcnt;		/* Number of references */
 };
 

Modified: head/sys/netinet/ip_fw.h
==============================================================================
--- head/sys/netinet/ip_fw.h	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sys/netinet/ip_fw.h	Fri Mar 13 09:03:25 2015	(r279948)
@@ -721,7 +721,7 @@ struct _ipfw_dyn_rule {
 #define	IPFW_VTYPE_TAG		0x00000020	/* tag/untag */
 #define	IPFW_VTYPE_DIVERT	0x00000040	/* divert/tee */
 #define	IPFW_VTYPE_NETGRAPH	0x00000080	/* netgraph/ngtee */
-#define	IPFW_VTYPE_LIMIT	0x00000100	/* IPv6 nexthop */
+#define	IPFW_VTYPE_LIMIT	0x00000100	/* limit */
 #define	IPFW_VTYPE_NH4		0x00000200	/* IPv4 nexthop */
 #define	IPFW_VTYPE_NH6		0x00000400	/* IPv6 nexthop */
 
@@ -817,10 +817,11 @@ typedef struct _ipfw_table_value {
 	uint32_t	nat;		/* O_NAT */
 	uint32_t	nh4;
 	uint8_t		dscp;
-	uint8_t		spare0[3];
+	uint8_t		spare0;
+	uint16_t	spare1;
 	struct in6_addr	nh6;
 	uint32_t	limit;		/* O_LIMIT */
-	uint32_t	spare1;
+	uint32_t	zoneid;		/* scope zone id for nh6 */
 	uint64_t	reserved;
 } ipfw_table_value;
 

Modified: head/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw2.c	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sys/netpfil/ipfw/ip_fw2.c	Fri Mar 13 09:03:25 2015	(r279948)
@@ -2387,13 +2387,48 @@ do {								\
 				if (q == NULL || q->rule != f ||
 				    dyn_dir == MATCH_FORWARD) {
 				    struct sockaddr_in *sa;
+
 				    sa = &(((ipfw_insn_sa *)cmd)->sa);
 				    if (sa->sin_addr.s_addr == INADDR_ANY) {
-					bcopy(sa, &args->hopstore,
-							sizeof(*sa));
-					args->hopstore.sin_addr.s_addr =
-						    htonl(tablearg);
-					args->next_hop = &args->hopstore;
+#ifdef INET6
+					/*
+					 * We use O_FORWARD_IP opcode for
+					 * fwd rule with tablearg, but tables
+					 * now support IPv6 addresses. And
+					 * when we are inspecting IPv6 packet,
+					 * we can use nh6 field from
+					 * table_value as next_hop6 address.
+					 */
+					if (is_ipv6) {
+						struct sockaddr_in6 *sa6;
+
+						sa6 = args->next_hop6 =
+						    &args->hopstore6;
+						sa6->sin6_family = AF_INET6;
+						sa6->sin6_len = sizeof(*sa6);
+						sa6->sin6_addr = TARG_VAL(
+						    chain, tablearg, nh6);
+						/*
+						 * Set sin6_scope_id only for
+						 * link-local unicast addresses.
+						 */
+						if (IN6_IS_ADDR_LINKLOCAL(
+						    &sa6->sin6_addr))
+							sa6->sin6_scope_id =
+							    TARG_VAL(chain,
+								tablearg,
+								zoneid);
+					} else
+#endif
+					{
+						sa = args->next_hop =
+						    &args->hopstore;
+						sa->sin_family = AF_INET;
+						sa->sin_len = sizeof(*sa);
+						sa->sin_addr.s_addr = htonl(
+						    TARG_VAL(chain, tablearg,
+						    nh4));
+					}
 				    } else {
 					args->next_hop = sa;
 				    }

Modified: head/sys/netpfil/ipfw/ip_fw_pfil.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_pfil.c	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sys/netpfil/ipfw/ip_fw_pfil.c	Fri Mar 13 09:03:25 2015	(r279948)
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
 #ifdef INET6
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
+#include <netinet6/scope6_var.h>
 #endif
 
 #include <netgraph/ng_ipfw.h>
@@ -197,8 +198,20 @@ again:
 		}
 #ifdef INET6
 		if (args.next_hop6 != NULL) {
-			bcopy(args.next_hop6, (fwd_tag+1), len);
-			if (in6_localip(&args.next_hop6->sin6_addr))
+			struct sockaddr_in6 *sa6;
+
+			sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
+			bcopy(args.next_hop6, sa6, len);
+			/*
+			 * If nh6 address is link-local we should convert
+			 * it to kernel internal form before doing any
+			 * comparisons.
+			 */
+			if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
+				ret = EACCES;
+				break;
+			}
+			if (in6_localip(&sa6->sin6_addr))
 				(*m0)->m_flags |= M_FASTFWD_OURS;
 			(*m0)->m_flags |= M_IP6_NEXTHOP;
 		}

Modified: head/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_private.h	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sys/netpfil/ipfw/ip_fw_private.h	Fri Mar 13 09:03:25 2015	(r279948)
@@ -102,7 +102,10 @@ struct ip_fw_args {
 	struct inpcb	*inp;
 
 	struct _ip6dn_args	dummypar; /* dummynet->ip6_output */
-	struct sockaddr_in hopstore;	/* store here if cannot use a pointer */
+	union {		/* store here if cannot use a pointer */
+		struct sockaddr_in hopstore;
+		struct sockaddr_in6 hopstore6;
+	};
 };
 
 MALLOC_DECLARE(M_IPFW);
@@ -294,11 +297,12 @@ struct table_value {
 	uint32_t	nat;		/* O_NAT */
 	uint32_t	nh4;
 	uint8_t		dscp;
-	uint8_t		spare0[3];
+	uint8_t		spare0;
+	uint16_t	spare1;
 	/* -- 32 bytes -- */
 	struct in6_addr	nh6;
 	uint32_t	limit;		/* O_LIMIT */
-	uint32_t	spare1;
+	uint32_t	zoneid;		/* scope zone id for nh6 */
 	uint64_t	refcnt;		/* Number of references */
 };
 

Modified: head/sys/netpfil/ipfw/ip_fw_table_value.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_table_value.c	Fri Mar 13 07:29:49 2015	(r279947)
+++ head/sys/netpfil/ipfw/ip_fw_table_value.c	Fri Mar 13 09:03:25 2015	(r279948)
@@ -117,6 +117,7 @@ mask_table_value(struct table_value *src
 	_MCPY(dscp, IPFW_VTYPE_DSCP);
 	_MCPY(nh4, IPFW_VTYPE_NH4);
 	_MCPY(nh6, IPFW_VTYPE_NH6);
+	_MCPY(zoneid, IPFW_VTYPE_NH6);
 #undef	_MCPY
 }
 
@@ -666,6 +667,7 @@ ipfw_import_table_value_v1(ipfw_table_va
 	v.nh4 = iv->nh4;
 	v.nh6 = iv->nh6;
 	v.limit = iv->limit;
+	v.zoneid = iv->zoneid;
 
 	memcpy(iv, &v, sizeof(ipfw_table_value));
 }
@@ -691,6 +693,7 @@ ipfw_export_table_value_v1(struct table_
 	iv.limit = v->limit;
 	iv.nh4 = v->nh4;
 	iv.nh6 = v->nh6;
+	iv.zoneid = v->zoneid;
 
 	memcpy(piv, &iv, sizeof(iv));
 }



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