From f6d9e53b78e65766486feaae9c253def963df851 Mon Sep 17 00:00:00 2001 From: florian Date: Wed, 5 Jul 2017 09:51:37 +0000 Subject: [PATCH] If we are sending a neighbor solicitation for a link local address send it with a link local source address as well. This helps upstream routers with their own source address selection. A reoccurring scenario is: - gateway on fe80::1%if - the gateway does not have an IP in the same prefix as our global address When we want to talk to the outside world we first need to resolve the gateway. We copy the source address from our outgoing packet to the neighbor solicitation packet (a global address) and ask for layer2 information of a link local address. The upstream router now needs to do source address selection of it's own. Since we are coming from a global address and there is no address from the same prefix the router uses another global address lying around. We then drop this with "ND packet from non-neighbor". Reported over the years by a few people, most recently by Marc Peters on bugs@ who confirmed that this fixes the problem. OK stsp@, mpi@ --- sys/netinet6/nd6_nbr.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index fa8d3ed1472..b9c985a31b9 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6_nbr.c,v 1.117 2017/06/08 13:28:03 mpi Exp $ */ +/* $OpenBSD: nd6_nbr.c,v 1.118 2017/07/05 09:51:37 florian Exp $ */ /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ /* @@ -445,7 +445,8 @@ nd6_ns_output(struct ifnet *ifp, struct in6_addr *daddr6, * We use the source address for the prompting packet * (saddr6), if: * - saddr6 is given from the caller (by giving "ln"), and - * - saddr6 belongs to the outgoing interface. + * - saddr6 belongs to the outgoing interface and + * - if taddr is link local saddr6 must be link local as well * Otherwise, we perform the source address selection as usual. */ struct ip6_hdr *hip6; /* hold ip6 */ @@ -453,9 +454,12 @@ nd6_ns_output(struct ifnet *ifp, struct in6_addr *daddr6, if (ln && ln->ln_hold) { hip6 = mtod(ln->ln_hold, struct ip6_hdr *); - if (sizeof(*hip6) <= ln->ln_hold->m_len) + if (sizeof(*hip6) <= ln->ln_hold->m_len) { saddr6 = &hip6->ip6_src; - else + if (saddr6 && IN6_IS_ADDR_LINKLOCAL(taddr6) && + !IN6_IS_ADDR_LINKLOCAL(saddr6)) + saddr6 = NULL; + } else saddr6 = NULL; } else saddr6 = NULL; -- 2.20.1