Do not treat loopback interfaces as p2p interfaces and create only
authormpi <mpi@openbsd.org>
Mon, 20 Apr 2015 09:07:42 +0000 (09:07 +0000)
committermpi <mpi@openbsd.org>
Mon, 20 Apr 2015 09:07:42 +0000 (09:07 +0000)
one route to "::1".

Due to a clever BSD trick, the `ifa_dstaddr` field of addresses on
IFF_LOOPBACK ifps is set to the same value that `ifa_addr`.  That's
why filtering for broadcast addresses is so complicated, because
guess what, `ifa_broadaddr` is the same as `ifa_dstaddr`!

Sadly our IPv6 code was "only" checking for `ifa_dstaddr` without
looking if the ifa was attached to a IFF_POINTOTPOINT interface.
So it always tried to create two routes to "::1" and, with the
recent RTF_LOCAL work, succeed.

You should now have only one local route to "::1".

 ::1             ::1         UHl       14  0 32768     1 lo0
-::1             ::1         UH         0  0 32768     4 lo0

ok henning@

sys/netinet6/in6.c

index 85db120..4792207 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in6.c,v 1.155 2015/04/20 08:53:36 mpi Exp $   */
+/*     $OpenBSD: in6.c,v 1.156 2015/04/20 09:07:42 mpi Exp $   */
 /*     $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $   */
 
 /*
@@ -751,7 +751,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
         * install the new destination.  Note that the interface must be
         * p2p or loopback (see the check above.)
         */
-       if (dst6.sin6_family == AF_INET6 &&
+       if ((ifp->if_flags & IFF_POINTOPOINT) && dst6.sin6_family == AF_INET6 &&
            !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia6->ia_dstaddr.sin6_addr)) {
                struct ifaddr *ifa = &ia6->ia_ifa;
 
@@ -1020,7 +1020,8 @@ in6_purgeaddr(struct ifaddr *ifa)
         * delete route to the destination of the address being purged.
         * The interface must be p2p or loopback in this case.
         */
-       if ((ia6->ia_flags & IFA_ROUTE) != 0 && ia6->ia_dstaddr.sin6_len != 0) {
+       if ((ifp->if_flags & IFF_POINTOPOINT) && (ia6->ia_flags & IFA_ROUTE) &&
+           ia6->ia_dstaddr.sin6_len != 0) {
                int e;
 
                if ((e = rt_ifa_del(ifa, RTF_HOST, ifa->ifa_dstaddr)) != 0) {
@@ -1364,7 +1365,8 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia6, int newhost)
         * direct route.
         */
        plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL); /* XXX */
-       if (plen == 128 && ia6->ia_dstaddr.sin6_family == AF_INET6) {
+       if ((ifp->if_flags & IFF_POINTOPOINT) && plen == 128 &&
+           ia6->ia_dstaddr.sin6_family == AF_INET6) {
                ifa = &ia6->ia_ifa;
                error = rt_ifa_add(ifa, RTF_UP | RTF_HOST, ifa->ifa_dstaddr);
                if (error != 0)