the system is inconsistent wrt to tunnels and ipv6 link local
addresses.

there are three things to consider here:

1. configuring addresses on a tunnel
2. using addresses to encapsulate traffic
3. reading the addresses a tunnel uses

the ioctls used for 1 and 3 use sockaddr_in6 to pass v6 addresses
in and out of the kernel for tunnel configuration. sin6 structures
have a sin6_scope_id member that is supposed to represent the scope.

i get the impression sin6_scope_id wasnt always there thoughway.
kame had (has) a hack where it embeds the scope id into bits that
are guaranteed to be zero.

both ifconfig and the kernel have code to pack sin6_scope_id into
a v6 address, and to unpack it later.

currently 1 uses getaddrinfo to parse an address on the command
line and submit it to the kernel. getaddrinfo reads scope (eg, %ix0)
and puts it into sin6_scope_id.

for some reason 3 currently assumes that needs to unpack a kame
packed address and. that means it reads from the "zero" bits in the
address into sin6_scope_id.

1 and 3 are therefore inconsistent. 1 submits a nice neat sin6_scope_id
to the kernel, but 3 assumes its a kame packed address.

to resolve this im suggesting we pick 1 as the right way to do
things. sin6_scope_id is portable, and less confusing. i havent met
anyone who likes the kame hack.

for 2, ipv6 packets end up in ip6_output, and ip6_output relies on
scope embedded into link local addresses. at the moment there are
3 tunnel interfaces that let you use v6 addresses for the enpoints:
gif, etherip, and vxlan. they all use the sockaddr_sin6 from userland
to fill in a v6 header, but none of them use the scope id.

the diff below should fix all this. the most important fix is vxlan.

ok?

Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.333
diff -u -p -r1.333 ifconfig.c
--- sbin/ifconfig/ifconfig.c    10 Nov 2016 14:36:03 -0000      1.333
+++ sbin/ifconfig/ifconfig.c    12 Dec 2016 09:44:48 -0000
@@ -2873,8 +2873,6 @@ phys_status(int force)
        (void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
        if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0)
                return;
-       if (req.addr.ss_family == AF_INET6)
-               in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
        if (getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
            psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0)
                strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
@@ -2883,10 +2881,8 @@ phys_status(int force)
 
        if (req.dstaddr.ss_family == AF_INET)
                dstport = ((struct sockaddr_in *)&req.dstaddr)->sin_port;
-       else if (req.dstaddr.ss_family == AF_INET6) {
-               in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
+       else if (req.dstaddr.ss_family == AF_INET6)
                dstport = ((struct sockaddr_in6 *)&req.dstaddr)->sin6_port;
-       }
        if (getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
            pdstaddr, sizeof(pdstaddr), 0, 0, niflag) != 0)
                strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
Index: sys/net/if_etherip.c
===================================================================
RCS file: /cvs/src/sys/net/if_etherip.c,v
retrieving revision 1.7
diff -u -p -r1.7 if_etherip.c
--- sys/net/if_etherip.c        13 Apr 2016 11:41:15 -0000      1.7
+++ sys/net/if_etherip.c        12 Dec 2016 09:44:48 -0000
@@ -514,18 +514,19 @@ ip6_etherip_output(struct ifnet *ifp, st
        struct sockaddr_in6 *src, *dst;
        struct etherip_header *eip;
        struct ip6_hdr *ip6;
+       int error;
 
        src = (struct sockaddr_in6 *)&sc->sc_src;
        dst = (struct sockaddr_in6 *)&sc->sc_dst;
 
        if (src == NULL || dst == NULL ||
            src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6) {
-               m_freem(m);
-               return EAFNOSUPPORT;
+               error = EAFNOSUPPORT;
+               goto drop;
        }
        if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
-               m_freem(m);
-               return ENETUNREACH;
+               error = ENETUNREACH;
+               goto drop;
        }
 
        m->m_flags &= ~(M_BCAST|M_MCAST);
@@ -552,8 +553,12 @@ ip6_etherip_output(struct ifnet *ifp, st
        ip6->ip6_nxt  = IPPROTO_ETHERIP;
        ip6->ip6_hlim = ip6_defhlim;
        ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
-       ip6->ip6_src  = src->sin6_addr;
-       ip6->ip6_dst = dst->sin6_addr;
+       error = in6_embedscope(&ip6->ip6_src, src, NULL);
+       if (error != 0)
+               goto drop;
+       error = in6_embedscope(&ip6->ip6_dst, dst, NULL);
+       if (error != 0)
+               goto drop;
 
        m->m_pkthdr.ph_rtableid = sc->sc_rdomain;
 
@@ -565,6 +570,10 @@ ip6_etherip_output(struct ifnet *ifp, st
            (sizeof(struct ip6_hdr) + sizeof(struct etherip_header)));
 
        return ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL);
+
+drop:
+       m_freem(m);
+       return (error);
 }
 
 int
Index: sys/net/if_vxlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vxlan.c,v
retrieving revision 1.50
diff -u -p -r1.50 if_vxlan.c
--- sys/net/if_vxlan.c  14 Oct 2016 10:25:02 -0000      1.50
+++ sys/net/if_vxlan.c  12 Dec 2016 09:44:48 -0000
@@ -724,7 +724,6 @@ vxlan_encap6(struct ifnet *ifp, struct m
        struct vxlan_softc      *sc = (struct vxlan_softc *)ifp->if_softc;
        struct ip6_hdr          *ip6;
        struct in6_addr         *in6a;
-       int                      error;
 
        M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
        if (m == NULL)
@@ -736,8 +735,10 @@ vxlan_encap6(struct ifnet *ifp, struct m
        ip6->ip6_vfc |= IPV6_VERSION;
        ip6->ip6_nxt = IPPROTO_UDP;
        ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
-       ip6->ip6_src  = satosin6(src)->sin6_addr;
-       ip6->ip6_dst = satosin6(dst)->sin6_addr;
+       if (in6_embedscope(&ip6->ip6_src, satosin6(src), NULL) != 0)
+               goto drop;
+       if (in6_embedscope(&ip6->ip6_dst, satosin6(dst), NULL) != 0)
+               goto drop;
 
        if (sc->sc_ttl > 0)
                ip6->ip6_hlim = sc->sc_ttl;
@@ -745,12 +746,10 @@ vxlan_encap6(struct ifnet *ifp, struct m
                ip6->ip6_hlim = ip6_defhlim;
 
        if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr)) {
-               error = in6_selectsrc(&in6a, satosin6(dst), NULL, NULL,
-                   sc->sc_rdomain);
-               if (error != 0) {
-                       m_freem(m);
-                       return (NULL);
-               }
+               if (in6_selectsrc(&in6a, satosin6(dst), NULL, NULL,
+                   sc->sc_rdomain) != 0)
+                       goto drop;
+
                ip6->ip6_src = *in6a;
        }
 
@@ -763,6 +762,10 @@ vxlan_encap6(struct ifnet *ifp, struct m
        m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
 
        return (m);
+
+drop:
+       m_freem(m);
+       return (NULL);
 }
 
 int

Reply via email to