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*/
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to