Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Apr 2015 16:46:31 +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: r281693 - head/sys/netipsec
Message-ID:  <201504181646.t3IGkVLY044384@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Sat Apr 18 16:46:31 2015
New Revision: 281693
URL: https://svnweb.freebsd.org/changeset/base/281693

Log:
  Fix handling of scoped IPv6 addresses in IPSec code.
  
  * in ipsec_encap() embed scope zone ids into link-local addresses
    in the new IPv6 header, this helps ip6_output() disambiguate the
    scope;
  * teach key_ismyaddr6() use in6_localip(). in6_localip() is less
    strict than key_sockaddrcmp(). It doesn't compare all fileds of
    struct sockaddr_in6, but it is faster and it should be safe,
    because all SA's data was checked for correctness. Also, since
    IPv6 link-local addresses in the &V_in6_ifaddrhead are stored in
    kernel-internal form, we need to embed scope zone id from SA into
    the address before calling in6_localip.
  * in ipsec_common_input() take scope zone id embedded in the address
    and use it to initialize sin6_scope_id, then use this sockaddr
    structure to lookup SA, because we keep addresses in the SADB without
    embedded scope zone id.
  
  Differential Revision:	https://reviews.freebsd.org/D2304
  Reviewed by:	gnn
  Sponsored by:	Yandex LLC

Modified:
  head/sys/netipsec/ipsec_input.c
  head/sys/netipsec/ipsec_output.c
  head/sys/netipsec/key.c

Modified: head/sys/netipsec/ipsec_input.c
==============================================================================
--- head/sys/netipsec/ipsec_input.c	Sat Apr 18 16:38:45 2015	(r281692)
+++ head/sys/netipsec/ipsec_input.c	Sat Apr 18 16:46:31 2015	(r281693)
@@ -195,6 +195,13 @@ ipsec_common_input(struct mbuf *m, int s
 		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
 		    sizeof(struct in6_addr),
 		    (caddr_t) &dst_address.sin6.sin6_addr);
+		/* We keep addresses in SADB without embedded scope id */
+		if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) {
+			/* XXX: sa6_recoverscope() */
+			dst_address.sin6.sin6_scope_id =
+			    ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]);
+			dst_address.sin6.sin6_addr.s6_addr16[1] = 0;
+		}
 		break;
 #endif /* INET6 */
 	default:

Modified: head/sys/netipsec/ipsec_output.c
==============================================================================
--- head/sys/netipsec/ipsec_output.c	Sat Apr 18 16:38:45 2015	(r281692)
+++ head/sys/netipsec/ipsec_output.c	Sat Apr 18 16:46:31 2015	(r281693)
@@ -503,7 +503,14 @@ ipsec_encap(struct mbuf **mp, struct sec
 		ip6->ip6_hlim = V_ip6_defhlim;
 		ip6->ip6_nxt = proto;
 		ip6->ip6_dst = saidx->dst.sin6.sin6_addr;
+		/* For link-local address embed scope zone id */
+		if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
+			ip6->ip6_dst.s6_addr16[1] =
+			    htons(saidx->dst.sin6.sin6_scope_id & 0xffff);
 		ip6->ip6_src = saidx->src.sin6.sin6_addr;
+		if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
+			ip6->ip6_src.s6_addr16[1] =
+			    htons(saidx->src.sin6.sin6_scope_id & 0xffff);
 		ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6));
 		ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos);
 		ip6->ip6_flow |= htonl((uint32_t)proto << 20);

Modified: head/sys/netipsec/key.c
==============================================================================
--- head/sys/netipsec/key.c	Sat Apr 18 16:38:45 2015	(r281692)
+++ head/sys/netipsec/key.c	Sat Apr 18 16:46:31 2015	(r281693)
@@ -3856,48 +3856,19 @@ key_ismyaddr(struct sockaddr *sa)
  * compare my own address for IPv6.
  * 1: ours
  * 0: other
- * NOTE: derived ip6_input() in KAME. This is necessary to modify more.
  */
-#include <netinet6/in6_var.h>
-
 static int
 key_ismyaddr6(struct sockaddr_in6 *sin6)
 {
-	struct in6_ifaddr *ia;
-#if 0
-	struct in6_multi *in6m;
-#endif
-
-	IN6_IFADDR_RLOCK();
-	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
-		if (key_sockaddrcmp((struct sockaddr *)sin6,
-		    (struct sockaddr *)&ia->ia_addr, 0) == 0) {
-			IN6_IFADDR_RUNLOCK();
-			return 1;
-		}
-
-#if 0
-		/*
-		 * XXX Multicast
-		 * XXX why do we care about multlicast here while we don't care
-		 * about IPv4 multicast??
-		 * XXX scope
-		 */
-		in6m = NULL;
-		IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m);
-		if (in6m) {
-			IN6_IFADDR_RUNLOCK();
-			return 1;
-		}
-#endif
-	}
-	IN6_IFADDR_RUNLOCK();
+	struct in6_addr in6;
 
-	/* loopback, just for safety */
-	if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
-		return 1;
+	if (!IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
+		return (in6_localip(&sin6->sin6_addr));
 
-	return 0;
+	/* Convert address into kernel-internal form */
+	in6 = sin6->sin6_addr;
+	in6.s6_addr16[1] = htons(sin6->sin6_scope_id & 0xffff);
+	return (in6_localip(&in6));
 }
 #endif /*INET6*/
 



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