When choosing IPv6 source addresses, respect the ifaddr preference
level such as one might set with 'ifconfig xx0 inet6 <address> preference <pref>'. I've been running this for many months without any problems.
This commit is contained in:
parent
7254a559b2
commit
cb401b7946
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: in6.c,v 1.155 2010/04/07 22:59:15 oki Exp $ */
|
||||
/* $NetBSD: in6.c,v 1.156 2010/04/22 20:05:15 dyoung Exp $ */
|
||||
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
|
||||
|
||||
/*
|
||||
@ -62,7 +62,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.155 2010/04/07 22:59:15 oki Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.156 2010/04/22 20:05:15 dyoung Exp $");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_pfil_hooks.h"
|
||||
@ -1792,6 +1792,14 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct ifaddr *
|
||||
bestifa(struct ifaddr *best_ifa, struct ifaddr *ifa)
|
||||
{
|
||||
if (best_ifa == NULL || best_ifa->ifa_preference < ifa->ifa_preference)
|
||||
return ifa;
|
||||
return best_ifa;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an IPv6 interface link-local address specific to an interface.
|
||||
*/
|
||||
@ -1809,10 +1817,7 @@ in6ifa_ifpforlinklocal(const struct ifnet *ifp, const int ignoreflags)
|
||||
continue;
|
||||
if ((((struct in6_ifaddr *)ifa)->ia6_flags & ignoreflags) != 0)
|
||||
continue;
|
||||
if (best_ifa == NULL)
|
||||
best_ifa = ifa;
|
||||
else if (best_ifa->ifa_preference < ifa->ifa_preference)
|
||||
best_ifa = ifa;
|
||||
best_ifa = bestifa(best_ifa, ifa);
|
||||
}
|
||||
|
||||
return (struct in6_ifaddr *)best_ifa;
|
||||
@ -1825,18 +1830,28 @@ in6ifa_ifpforlinklocal(const struct ifnet *ifp, const int ignoreflags)
|
||||
struct in6_ifaddr *
|
||||
in6ifa_ifpwithaddr(const struct ifnet *ifp, const struct in6_addr *addr)
|
||||
{
|
||||
struct ifaddr *ifa;
|
||||
struct ifaddr *best_ifa = NULL, *ifa;
|
||||
|
||||
IFADDR_FOREACH(ifa, ifp) {
|
||||
if (ifa->ifa_addr == NULL)
|
||||
continue; /* just for safety */
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
|
||||
break;
|
||||
if (!IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
|
||||
continue;
|
||||
best_ifa = bestifa(best_ifa, ifa);
|
||||
}
|
||||
|
||||
return (struct in6_ifaddr *)ifa;
|
||||
return (struct in6_ifaddr *)best_ifa;
|
||||
}
|
||||
|
||||
static struct in6_ifaddr *
|
||||
bestia(struct in6_ifaddr *best_ia, struct in6_ifaddr *ia)
|
||||
{
|
||||
if (best_ia == NULL ||
|
||||
best_ia->ia_ifa.ifa_preference < ia->ia_ifa.ifa_preference)
|
||||
return ia;
|
||||
return best_ia;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1847,7 +1862,7 @@ struct in6_ifaddr *
|
||||
in6ifa_ifplocaladdr(const struct ifnet *ifp, const struct in6_addr *addr)
|
||||
{
|
||||
struct ifaddr *ifa;
|
||||
struct in6_ifaddr *ia;
|
||||
struct in6_ifaddr *best_ia = NULL, *ia;
|
||||
|
||||
IFADDR_FOREACH(ifa, ifp) {
|
||||
if (ifa->ifa_addr == NULL)
|
||||
@ -1855,13 +1870,14 @@ in6ifa_ifplocaladdr(const struct ifnet *ifp, const struct in6_addr *addr)
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
ia = (struct in6_ifaddr *)ifa;
|
||||
if (IN6_ARE_MASKED_ADDR_EQUAL(addr,
|
||||
if (!IN6_ARE_MASKED_ADDR_EQUAL(addr,
|
||||
&ia->ia_addr.sin6_addr,
|
||||
&ia->ia_prefixmask.sin6_addr))
|
||||
return ia;
|
||||
continue;
|
||||
best_ia = bestia(best_ia, ia);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return best_ia;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2043,7 +2059,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
|
||||
{
|
||||
int dst_scope = in6_addrscope(dst), blen = -1, tlen;
|
||||
struct ifaddr *ifa;
|
||||
struct in6_ifaddr *besta = 0;
|
||||
struct in6_ifaddr *best_ia = NULL, *ia;
|
||||
struct in6_ifaddr *dep[2]; /* last-resort: deprecated */
|
||||
|
||||
dep[0] = dep[1] = NULL;
|
||||
@ -2057,54 +2073,60 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
|
||||
IFADDR_FOREACH(ifa, ifp) {
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
|
||||
ia = (struct in6_ifaddr *)ifa;
|
||||
if (ia->ia6_flags & IN6_IFF_ANYCAST)
|
||||
continue; /* XXX: is there any case to allow anycast? */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
|
||||
if (ia->ia6_flags & IN6_IFF_NOTREADY)
|
||||
continue; /* don't use this interface */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
|
||||
if (ia->ia6_flags & IN6_IFF_DETACHED)
|
||||
continue;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
|
||||
if (ia->ia6_flags & IN6_IFF_DEPRECATED) {
|
||||
if (ip6_use_deprecated)
|
||||
dep[0] = (struct in6_ifaddr *)ifa;
|
||||
dep[0] = ia;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
|
||||
/*
|
||||
* call in6_matchlen() as few as possible
|
||||
*/
|
||||
if (besta) {
|
||||
if (blen == -1)
|
||||
blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
|
||||
tlen = in6_matchlen(IFA_IN6(ifa), dst);
|
||||
if (tlen > blen) {
|
||||
blen = tlen;
|
||||
besta = (struct in6_ifaddr *)ifa;
|
||||
}
|
||||
} else
|
||||
besta = (struct in6_ifaddr *)ifa;
|
||||
if (dst_scope != in6_addrscope(IFA_IN6(ifa)))
|
||||
continue;
|
||||
/*
|
||||
* call in6_matchlen() as few as possible
|
||||
*/
|
||||
if (best_ia == NULL) {
|
||||
best_ia = ia;
|
||||
continue;
|
||||
}
|
||||
if (blen == -1)
|
||||
blen = in6_matchlen(&best_ia->ia_addr.sin6_addr, dst);
|
||||
tlen = in6_matchlen(IFA_IN6(ifa), dst);
|
||||
if (tlen > blen) {
|
||||
blen = tlen;
|
||||
best_ia = ia;
|
||||
} else if (tlen == blen)
|
||||
best_ia = bestia(best_ia, ia);
|
||||
}
|
||||
if (besta)
|
||||
return besta;
|
||||
if (best_ia != NULL)
|
||||
return best_ia;
|
||||
|
||||
IFADDR_FOREACH(ifa, ifp) {
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
|
||||
ia = (struct in6_ifaddr *)ifa;
|
||||
if (ia->ia6_flags & IN6_IFF_ANYCAST)
|
||||
continue; /* XXX: is there any case to allow anycast? */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
|
||||
if (ia->ia6_flags & IN6_IFF_NOTREADY)
|
||||
continue; /* don't use this interface */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
|
||||
if (ia->ia6_flags & IN6_IFF_DETACHED)
|
||||
continue;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
|
||||
if (ia->ia6_flags & IN6_IFF_DEPRECATED) {
|
||||
if (ip6_use_deprecated)
|
||||
dep[1] = (struct in6_ifaddr *)ifa;
|
||||
continue;
|
||||
}
|
||||
|
||||
return (struct in6_ifaddr *)ifa;
|
||||
best_ia = bestia(best_ia, ia);
|
||||
}
|
||||
if (best_ia != NULL)
|
||||
return best_ia;
|
||||
|
||||
/* use the last-resort values, that are, deprecated addresses */
|
||||
if (dep[0])
|
||||
|
Loading…
x
Reference in New Issue
Block a user