summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/in6_src.c
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2010-04-27 15:05:03 +0000
committerbz <bz@FreeBSD.org>2010-04-27 15:05:03 +0000
commite66b2bd00b8aeff7786ee941efdd1b5c067e459c (patch)
treee8f5f7bbdb45d9497a7945fa48e9b2d9619a71fa /sys/netinet6/in6_src.c
parent6def960c90c238bc5be3dd59b7704373f0b3989c (diff)
downloadFreeBSD-src-e66b2bd00b8aeff7786ee941efdd1b5c067e459c.zip
FreeBSD-src-e66b2bd00b8aeff7786ee941efdd1b5c067e459c.tar.gz
Make sure IPv6 source address selection does not change interface
addresses while walking the IPv6 address list if in the jail case something is connecting to ::1. Reported by: Pieter de Boer (pieter thedarkside.nl) Tested by: Pieter de Boer (pieter thedarkside.nl) MFC after: 4 days
Diffstat (limited to 'sys/netinet6/in6_src.c')
-rw-r--r--sys/netinet6/in6_src.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index ea302a5..e6c2cd8 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -182,7 +182,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct inpcb *inp, struct route_in6 *ro, struct ucred *cred,
struct ifnet **ifpp, struct in6_addr *srcp)
{
- struct in6_addr dst;
+ struct in6_addr dst, tmp;
struct ifnet *ifp = NULL;
struct in6_ifaddr *ia = NULL, *ia_best = NULL;
struct in6_pktinfo *pi = NULL;
@@ -326,10 +326,9 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (!V_ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))
continue;
+ /* If jailed only take addresses of the jail into account. */
if (cred != NULL &&
- prison_local_ip6(cred, &ia->ia_addr.sin6_addr,
- (inp != NULL &&
- (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
+ prison_check_ip6(cred, &ia->ia_addr.sin6_addr) != 0)
continue;
/* Rule 1: Prefer same address */
@@ -476,10 +475,26 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
return (EADDRNOTAVAIL);
}
+ /*
+ * At this point at least one of the addresses belonged to the jail
+ * but it could still be, that we want to further restrict it, e.g.
+ * theoratically IN6_IS_ADDR_LOOPBACK.
+ * It must not be IN6_IS_ADDR_UNSPECIFIED anymore.
+ * prison_local_ip6() will fix an IN6_IS_ADDR_LOOPBACK but should
+ * let all others previously selected pass.
+ * Use tmp to not change ::1 on lo0 to the primary jail address.
+ */
+ tmp = ia->ia_addr.sin6_addr;
+ if (cred != NULL && prison_local_ip6(cred, &tmp, (inp != NULL &&
+ (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) {
+ IN6_IFADDR_RUNLOCK();
+ return (EADDRNOTAVAIL);
+ }
+
if (ifpp)
*ifpp = ifp;
- bcopy(&ia->ia_addr.sin6_addr, srcp, sizeof(*srcp));
+ bcopy(&tmp, srcp, sizeof(*srcp));
IN6_IFADDR_RUNLOCK();
return (0);
}
OpenPOWER on IntegriCloud