From 15f0a5b39a2bb226b44457ed81a5d989cfee0393 Mon Sep 17 00:00:00 2001 From: mpi Date: Tue, 27 Jan 2015 10:31:19 +0000 Subject: [PATCH] Ensure that link-local addresses are correctly configured on loopback interfaces. When the kernel automagically configures IPv6 addresses on loopback interfaces, start by assigning a link-local address and then try to assign "::1". Only the first configured loopback interface per rdomain can have the "::1" address. But even if other loopback interfaces failed to get this address, because it is already taken, give them a chance to have a link-local address. While here change in6_ifattach() to return an error value and remove duplicated code. Fix a regression introduced by the NOINET6 flag removal. ok henning@, stsp@, florian@, benno@ --- sys/net/if.c | 33 +++++--------- sys/netinet6/in6.c | 5 +-- sys/netinet6/in6_ifattach.c | 88 +++++++++++-------------------------- sys/netinet6/in6_ifattach.h | 4 +- 4 files changed, 42 insertions(+), 88 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index 4b70862449a..a4dc97f0139 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.314 2015/01/27 03:17:36 dlg Exp $ */ +/* $OpenBSD: if.c,v 1.315 2015/01/27 10:31:19 mpi Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -1238,10 +1238,9 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) #ifdef INET6 case AF_INET6: s = splsoftnet(); - if (cmd == SIOCIFAFATTACH) { - if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) - in6_ifattach(ifp); - } else + if (cmd == SIOCIFAFATTACH) + in6_ifattach(ifp); + else in6_ifdetach(ifp); splx(s); return (0); @@ -1307,16 +1306,11 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) #ifdef INET6 if (ISSET(ifr->ifr_flags, IFXF_AUTOCONF6)) { - if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) { - s = splsoftnet(); - in6_ifattach(ifp); - splx(s); - } + s = splsoftnet(); + in6_ifattach(ifp); + splx(s); } - if (ifr->ifr_flags & IFXF_AUTOCONF6) - nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL); - if ((ifr->ifr_flags & IFXF_AUTOCONF6) && !(ifp->if_xflags & IFXF_AUTOCONF6)) { nd6_rs_timeout_count++; @@ -2199,19 +2193,16 @@ ifnewlladdr(struct ifnet *ifp) arp_ifinit((struct arpcom *)ifp, ifa); } #ifdef INET6 - /* Update the link-local address. Don't do it if we're - * a router to avoid confusing hosts on the network. */ + /* + * Update the link-local address. Don't do it if we're + * a router to avoid confusing hosts on the network. + */ if (!ip6_forwarding) { ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa; if (ifa) { in6_purgeaddr(ifa); dohooks(ifp->if_addrhooks, 0); - in6_ifattach_linklocal(ifp, NULL); - if (in6if_do_dad(ifp)) { - ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa; - if (ifa) - nd6_dad_start(ifa, NULL); - } + in6_ifattach(ifp); } } #endif diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 21553e6a220..39fe98d6c4e 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.c,v 1.150 2015/01/24 00:29:06 deraadt Exp $ */ +/* $OpenBSD: in6.c,v 1.151 2015/01/27 10:31:19 mpi Exp $ */ /* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */ /* @@ -478,8 +478,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp) * is no link-local yet. */ s = splsoftnet(); - if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) - in6_ifattach(ifp); + in6_ifattach(ifp); error = in6_update_ifa(ifp, ifra, ia6); splx(s); if (error != 0) diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 75ddd13d91b..a9363527df8 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_ifattach.c,v 1.82 2015/01/26 11:38:37 mpi Exp $ */ +/* $OpenBSD: in6_ifattach.c,v 1.83 2015/01/27 10:31:19 mpi Exp $ */ /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */ /* @@ -57,8 +57,6 @@ #include #endif -int ip6_auto_linklocal = 1; /* enable by default */ - int get_last_resort_ifid(struct ifnet *, struct in6_addr *); int get_hw_ifid(struct ifnet *, struct in6_addr *); int get_ifid(struct ifnet *, struct in6_addr *); @@ -431,15 +429,12 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid) return 0; } -/* - * ifp - must be IFT_LOOP - */ - int in6_ifattach_loopback(struct ifnet *ifp) { struct in6_aliasreq ifra; - int error; + + KASSERT(ifp->if_flags & IFF_LOOPBACK); bzero(&ifra, sizeof(ifra)); @@ -476,14 +471,7 @@ in6_ifattach_loopback(struct ifnet *ifp) * We are sure that this is a newly assigned address, so we can set * NULL to the 3rd arg. */ - if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { - nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " - "the loopback address on %s (errno=%d)\n", - ifp->if_xname, error)); - return (-1); - } - - return 0; + return (in6_update_ifa(ifp, &ifra, NULL)); } /* @@ -542,12 +530,11 @@ in6_nigroup(struct ifnet *ifp, const char *name, int namelen, * nodelocal address needs to be configured onto only one of them. * XXX multiple link-local address case */ -void +int in6_ifattach(struct ifnet *ifp) { struct ifaddr *ifa; - struct in6_ifaddr *ia6; - int dad_delay; /* delay ticks before DAD output */ + int dad_delay = 0; /* delay ticks before DAD output */ /* some of the interfaces are inherently not IPv6 capable */ switch (ifp->if_type) { @@ -555,7 +542,7 @@ in6_ifattach(struct ifnet *ifp) case IFT_ENC: case IFT_PFLOG: case IFT_PFSYNC: - return; + return (0); } /* @@ -563,63 +550,40 @@ in6_ifattach(struct ifnet *ifp) * remember there could be some link-layer that has special * fragmentation logic. */ - if (ifp->if_mtu < IPV6_MMTU) { - nd6log((LOG_INFO, "in6_ifattach: " - "%s has too small MTU, IPv6 not enabled\n", - ifp->if_xname)); - return; - } + if (ifp->if_mtu < IPV6_MMTU) + return (EINVAL); - /* - * usually, we require multicast capability to the interface - */ - if ((ifp->if_flags & IFF_MULTICAST) == 0) { - nd6log((LOG_INFO, "in6_ifattach: " - "%s is not multicast capable, IPv6 not enabled\n", - ifp->if_xname)); - return; - } + if ((ifp->if_flags & IFF_MULTICAST) == 0) + return (EINVAL); - /* - * assign loopback address for loopback interface. - * XXX multiple loopback interface case. - */ - if ((ifp->if_flags & IFF_LOOPBACK) != 0) { - struct in6_addr in6 = in6addr_loopback; - if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { - if (in6_ifattach_loopback(ifp) != 0) - return; + /* Assign a link-local address, if there's none. */ + if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) { + if (in6_ifattach_linklocal(ifp, NULL) != 0) { + /* failed to assign linklocal address. bark? */ } } - /* - * assign a link-local address, if there's none. - */ - if (ip6_auto_linklocal) { - ia6 = in6ifa_ifpforlinklocal(ifp, 0); - if (ia6 == NULL) { - if (in6_ifattach_linklocal(ifp, NULL) == 0) { - /* linklocal address assigned */ - } else { - /* failed to assign linklocal address. bark? */ - } - } + /* Assign loopback address, if there's none. */ + if (ifp->if_flags & IFF_LOOPBACK) { + struct in6_addr in6 = in6addr_loopback; + if (in6ifa_ifpwithaddr(ifp, &in6) != NULL) + return (0); + + return (in6_ifattach_loopback(ifp)); } - /* - * perform DAD. - */ - dad_delay = 0; + /* Perform DAD. */ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; - ia6 = ifatoia6(ifa); - if (ia6->ia6_flags & IN6_IFF_TENTATIVE) + if (ifatoia6(ifa)->ia6_flags & IN6_IFF_TENTATIVE) nd6_dad_start(ifa, &dad_delay); } if (ifp->if_xflags & IFXF_AUTOCONF6) nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL); + + return (0); } /* diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h index 6f574d6e1be..6160fb984a6 100644 --- a/sys/netinet6/in6_ifattach.h +++ b/sys/netinet6/in6_ifattach.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_ifattach.h,v 1.6 2014/01/07 16:34:05 stsp Exp $ */ +/* $OpenBSD: in6_ifattach.h,v 1.7 2015/01/27 10:31:19 mpi Exp $ */ /* $KAME: in6_ifattach.h,v 1.9 2000/04/12 05:35:48 itojun Exp $ */ /* @@ -34,7 +34,7 @@ #define _NETINET6_IN6_IFATTACH_H_ #ifdef _KERNEL -void in6_ifattach(struct ifnet *); +int in6_ifattach(struct ifnet *); void in6_ifdetach(struct ifnet *); int in6_nigroup(struct ifnet *, const char *, int, struct sockaddr_in6 *); int in6_ifattach_linklocal(struct ifnet *, struct in6_addr *); -- 2.20.1