svn commit: r259795 - user/ae/inet6/sys/netinet6
Andrey V. Elsukov
ae at FreeBSD.org
Mon Dec 23 22:20:48 UTC 2013
Author: ae
Date: Mon Dec 23 22:20:47 2013
New Revision: 259795
URL: http://svnweb.freebsd.org/changeset/base/259795
Log:
Highly simplify, deduplicate and make more readable the socket options
handling code. Use new prison_xxx_ip6() functions where they were in
original code.
Modified:
user/ae/inet6/sys/netinet6/in6_src.c
Modified: user/ae/inet6/sys/netinet6/in6_src.c
==============================================================================
--- user/ae/inet6/sys/netinet6/in6_src.c Mon Dec 23 22:20:00 2013 (r259794)
+++ user/ae/inet6/sys/netinet6/in6_src.c Mon Dec 23 22:20:47 2013 (r259795)
@@ -130,15 +130,10 @@ VNET_DEFINE(int, ip6_prefer_tempaddr) =
static int cached_rtlookup(const struct sockaddr_in6 *dst,
struct route_in6 *ro, u_int fibnum);
-static int check_scopezones(const struct sockaddr_in6 *dst,
- struct route_in6 *ro, u_int fibnum, const struct ip6_moptions *mopts,
- const struct in6_addr *src, const struct ifnet *ifp);
static int handle_nexthop(struct ip6po_nhinfo *nh, u_int fibnum,
struct ifnet **ifpp);
-static int handle_pktinfo(const struct sockaddr_in6 *dst,
- const struct in6_pktinfo* pi, const struct ip6_moptions *mopts,
- struct route_in6 *ro, u_int fibnum, struct ifnet **ifpp,
- struct in6_addr *srcp, int *done);
+static int handle_pktinfo(const struct in6_pktinfo* pi, struct ifnet **ifpp,
+ struct in6_addr *srcp);
static int lookup_policy_label(const struct in6_addr *, uint32_t);
@@ -327,65 +322,20 @@ cached_rtlookup(const struct sockaddr_in
return (0);
}
-static int
-check_scopezones(const struct sockaddr_in6 *dst, struct route_in6 *ro,
- u_int fibnum, const struct ip6_moptions *mopts, const struct in6_addr *src,
- const struct ifnet *ifp)
-{
- struct ifnet *oifp;
-
- oifp = NULL;
- /* Determine zone index of destination address. */
- if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr) ||
- IN6_IS_ADDR_MC_INTFACELOCAL(&dst->sin6_addr)) {
- if (dst->sin6_scope_id == 0)
- return (EHOSTUNREACH);
- oifp = in6_getlinkifnet(dst->sin6_scope_id);
- } else if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr) &&
- mopts != NULL && mopts->im6o_multicast_ifp != NULL) {
- oifp = mopts->im6o_multicast_ifp;
- } else {
- if (cached_rtlookup(dst, ro, fibnum) == 0)
- oifp = ro->ro_rt->rt_ifp;
- }
- if (oifp == NULL)
- return (EHOSTUNREACH);
-
- if (oifp != ifp &&
- in6_getscopezone(ifp, in6_srcaddrscope(src)) !=
- in6_getscopezone(oifp, in6_srcaddrscope(&dst->sin6_addr)))
- return (EHOSTUNREACH);
-
- return (0);
-}
-
/*
- * dst - original destination address;
* pi - options configured via IPV6_PKTINFO;
- * mopts - options configured via IPV6_MULTICAST_IF;
- * ro - route to destination;
- * fibnum - FIB number
*
* These parameters are returned back to caller:
* ifpp - determined outgoing interface;
* srcp - determined source address;
- * done - if set, this means that outgoing interface and
- * source address were determined.
- *
- * NOTE: don't forget to RTFREE(ro->ro_rt) after calling this function,
- * if needed of course.
*/
static int
-handle_pktinfo(const struct sockaddr_in6 *dst,
- const struct in6_pktinfo* pi, const struct ip6_moptions *mopts,
- struct route_in6 *ro, u_int fibnum, struct ifnet **ifpp,
- struct in6_addr *srcp, int *done)
+handle_pktinfo(const struct in6_pktinfo* pi, struct ifnet **ifpp,
+ struct in6_addr *srcp)
{
- struct in6_ifaddr *ia;
struct ifnet *ifp;
ifp = NULL;
- *done = 0;
if (pi->ipi6_ifindex != 0) {
ifp = ifnet_byindex(pi->ipi6_ifindex);
if (ifp == NULL)
@@ -393,93 +343,11 @@ handle_pktinfo(const struct sockaddr_in6
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
return (ENETDOWN);
}
- if (ifp != NULL && IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
- /*
- * If an interface is explicitly specified, use it.
- */
+ if (ifp != NULL)
*ifpp = ifp;
+ if (IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
return (0);
- }
- if (ifp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
- /*
- * If both, address and ifindex are specified via
- * IPV6_PKTINFO, then check that address is available
- * on this interface.
- */
- ia = in6ifa_ifpwithaddr(ifp, &pi->ipi6_addr);
- } else {
- /*
- * If address is specified via IPV6_PKTINFO, but interface
- * isn't, we can determine interface for a global unicast
- * from the ifaddr hash.
- */
- if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr)) {
- /* ipi6_addr is global. */
- ia = in6ifa_ifwithaddr(&pi->ipi6_addr, 0);
- } else if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) {
- /* ipi6_addr is link-local, dst is multicast. */
- if (mopts != NULL &&
- mopts->im6o_multicast_ifp != NULL) {
- /*
- * Outgoing interface is specified via
- * IPV6_MULTICAST_IF socket option.
- */
- ia = in6ifa_ifpwithaddr(
- mopts->im6o_multicast_ifp, &pi->ipi6_addr);
- } else if (dst->sin6_scope_id != 0 && ( /* XXX */
- IN6_IS_ADDR_MC_LINKLOCAL(&dst->sin6_addr) ||
- IN6_IS_ADDR_MC_INTFACELOCAL(&dst->sin6_addr))) {
- /*
- * Destination multicast address is in the
- * link-local or interface-local scope.
- * Use its sin6_scope_id to determine
- * outgoing interface.
- */
- ia = in6ifa_ifwithaddr(&pi->ipi6_addr,
- dst->sin6_scope_id);
- } else {
- /*
- * XXX: Try to lookup route for this multicast
- * destination address.
- */
- if (cached_rtlookup(dst, ro, fibnum) != 0)
- return (EHOSTUNREACH);
- ia = in6ifa_ifpwithaddr(ro->ro_rt->rt_ifp,
- &pi->ipi6_addr);
- }
- } else if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr)) {
- /* both are link-local. */
- ia = in6ifa_ifwithaddr(&pi->ipi6_addr,
- dst->sin6_scope_id);
- } else {
- /* ipi6_addr is link-local, dst is global. */
- if (cached_rtlookup(dst, ro, fibnum) != 0)
- return (EHOSTUNREACH);
- /* Check that address is available on interface. */
- ia = in6ifa_ifpwithaddr(ro->ro_rt->rt_ifp,
- &pi->ipi6_addr);
- }
- }
- if (ia == NULL || (
- ia->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
- RO_RTFREE(ro);
- if (ia != NULL)
- ifa_free(&ia->ia_ifa);
- return (EADDRNOTAVAIL);
- }
- ifp = ia->ia_ifp;
- ifa_free(&ia->ia_ifa);
- /*
- * Source address can not break the destination zone.
- */
- if (check_scopezones(dst, ro, fibnum, mopts, &pi->ipi6_addr,
- ifp) != 0) {
- RO_RTFREE(ro);
- return (EHOSTUNREACH);
- }
- *ifpp = ifp;
*srcp = pi->ipi6_addr;
- *done = 1;
return (0);
}
@@ -495,7 +363,6 @@ static int
handle_nexthop(struct ip6po_nhinfo *nh, u_int fibnum, struct ifnet **ifpp)
{
struct sockaddr_in6 *sa;
- struct in6_ifaddr *ia;
struct route_in6 *ro;
struct ifnet *ifp, *oifp;
@@ -508,21 +375,11 @@ handle_nexthop(struct ip6po_nhinfo *nh,
* was determined in the PKTINFO handling code.
*/
oifp = *ifpp;
-
- /*
- * Check that the next hop address is our own.
- */
- ia = in6ifa_ifwithaddr(&sa->sin6_addr, sa->sin6_scope_id);
- if (ia != NULL) {
- /* Address is our own. */
- ifp = ia->ia_ifp;
- ifa_free(&ia->ia_ifa);
- } else {
+ if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
/*
- * Address is not our own.
+ * Next hop is LLA, thus it should be neighbor.
* Determine outgoing interface by zone index.
*/
- if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
ifp = in6_getlinkifnet(sa->sin6_scope_id);
else {
if (cached_rtlookup(sa, ro, fibnum) != 0)
@@ -535,7 +392,6 @@ handle_nexthop(struct ip6po_nhinfo *nh,
return (EHOSTUNREACH);
ifp = ro->ro_rt->rt_ifp;
}
- }
/*
* When the outgoing interface is specified by IPV6_PKTINFO
* as well, the next hop specified by this option must be
@@ -548,6 +404,34 @@ handle_nexthop(struct ip6po_nhinfo *nh,
return (0);
}
+static int
+check_addrs(const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
+ struct ifnet *ifp)
+{
+ struct in6_ifaddr *ia;
+
+ /*
+ * Check that source address is available on the interface.
+ */
+ ia = in6ifa_ifpwithaddr(ifp, &src->sin6_addr);
+ if (ia == NULL || (
+ ia->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
+ if (ia != NULL)
+ ifa_free(&ia->ia_ifa);
+ return (EADDRNOTAVAIL);
+ }
+ ifa_free(&ia->ia_ifa);
+ /*
+ * Check that source address does not break the destination
+ * zone.
+ */
+ if (dst->sin6_scope_id != 0 &&
+ dst->sin6_scope_id != in6_getscopezone(ifp,
+ in6_srcaddrscope(&dst->sin6_addr)))
+ return (EHOSTUNREACH);
+ return (0);
+}
+
int
in6_selectsrc(struct sockaddr_in6 *dst, struct ip6_pktopts *opts,
struct inpcb *inp, struct route_in6 *ro, struct ucred *cred,
@@ -556,37 +440,33 @@ in6_selectsrc(struct sockaddr_in6 *dst,
struct route_in6 ro6;
struct dstaddr_props dstprops;
struct srcaddr_choice best;
+ struct sockaddr_in6 srcsock;
struct ip6_moptions *mopts;
- struct in6_pktinfo *pi;
struct in6_ifaddr *ia;
struct ifaddr *ifa;
struct ifnet *ifp, *oifp;
u_int fibnum;
- int error, done;
+ int error;
KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
KASSERT(ifpp != NULL, ("%s: ifpp is NULL", __func__));
KASSERT(sa6_checkzone(dst) == 0, ("%s: invalid zone information",
__func__));
- ifp = oifp = NULL;
- if (ifpp) {
- /*
- * Save a possibly passed in ifp for in6_selectsrc. Only
- * neighbor discovery code should use this feature, where
- * we may know the interface but not the FIB number holding
- * the connected subnet in case someone deleted it from the
- * default FIB and we need to check the interface.
- */
- if (*ifpp != NULL)
- oifp = *ifpp;
- *ifpp = NULL;
- }
-
+ ifp = NULL;
+ /*
+ * XXX: Save a possibly passed in ifp for in6_selectsrc. Only
+ * neighbor discovery code should use this feature, where
+ * we may know the interface but not the FIB number holding
+ * the connected subnet in case someone deleted it from the
+ * default FIB and we need to check the interface.
+ */
+ oifp = *ifpp;
if (inp != NULL) {
INP_LOCK_ASSERT(inp);
mopts = inp->in6p_moptions;
fibnum = inp->inp_inc.inc_fibnum;
+ /* Use "sticky" options if opts isn't specified. */
if (opts == NULL)
opts = inp->in6p_outputopts;
} else {
@@ -597,34 +477,32 @@ in6_selectsrc(struct sockaddr_in6 *dst,
ro = &ro6;
bzero(ro, sizeof(*ro));
}
-
- /*
- * XXX: jail support MUST be added later!
- */
- if (opts != NULL && (pi = opts->ip6po_pktinfo) != NULL) {
- error = handle_pktinfo(dst, pi, mopts, ro, fibnum,
- &ifp, srcp, &done);
+ srcsock = sa6_any;
+ if (opts != NULL && opts->ip6po_pktinfo != NULL) {
+ error = handle_pktinfo(opts->ip6po_pktinfo, &ifp,
+ &srcsock.sin6_addr);
if (error != 0)
return (error);
- if (done != 0) {
+ if (ifp != NULL) {
/*
* When the outgoing interface is specified by
* IPV6_PKTINFO as well, the next hop specified by
* this option must be reachable via the specified
- * interface. Also, we ignore next hop for multicast
- * destinations.
+ * interface.
+ * We ignore next hop for multicast destinations.
*/
if (!IN6_IS_ADDR_MULTICAST(&dst->sin6_addr) &&
- opts->ip6po_nexthop != NULL)
+ opts->ip6po_nexthop != NULL) {
error = handle_nexthop(&opts->ip6po_nhinfo,
fibnum, &ifp);
- if (error != 0 || ro == &ro6)
- RO_RTFREE(ro);
- if (error == 0)
- *ifpp = ifp;
- return (error);
+ if (error != 0)
+ return (error);
+ }
}
- } else if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) {
+ }
+ if (ifp != NULL)
+ goto oif_found;
+ if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) {
/*
* If the destination address is a multicast address and
* the IPV6_MULTICAST_IF socket option is specified for the
@@ -639,10 +517,11 @@ in6_selectsrc(struct sockaddr_in6 *dst,
* or interface-local scope. Use its sin6_scope_id to
* determine outgoing interface.
*/
- ifp = in6_getlinkifnet(dst->sin6_scope_id);
+ if (dst->sin6_scope_id != 0)
+ ifp = in6_getlinkifnet(dst->sin6_scope_id);
} else {
/*
- * XXX: Try to lookup route for this multicast
+ * Try to lookup route for this multicast
* destination address.
*/
if (cached_rtlookup(dst, ro, fibnum) != 0)
@@ -659,9 +538,10 @@ in6_selectsrc(struct sockaddr_in6 *dst,
* Use sin6_scope_id for link-local addresses.
* Do a route lookup for global addresses.
*/
- if (dst->sin6_scope_id != 0)
- ifp = in6_getlinkifnet(dst->sin6_scope_id);
- else {
+ if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr)) {
+ if (dst->sin6_scope_id != 0)
+ ifp = in6_getlinkifnet(dst->sin6_scope_id);
+ } else {
if (cached_rtlookup(dst, ro, fibnum) != 0)
return (EHOSTUNREACH);
ifp = ro->ro_rt->rt_ifp;
@@ -673,6 +553,26 @@ in6_selectsrc(struct sockaddr_in6 *dst,
/* Use outgoing interface specified by caller. */
ifp = oifp;
}
+oif_found:
+ if (!IN6_IS_ADDR_UNSPECIFIED(&srcsock.sin6_addr)) {
+ if (ro == &ro6)
+ RO_RTFREE(ro);
+ if (cred != NULL) {
+ srcsock.sin6_scope_id = in6_getscopezone(ifp,
+ in6_srcaddrscope(&srcsock.sin6_addr));
+ error = prison_local_ip6(cred, &srcsock,
+ (inp != NULL &&
+ (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0));
+ if (error != 0)
+ return (error);
+ }
+ error = check_addrs(&srcsock, dst, ifp);
+ if (error != 0)
+ return (error);
+ *ifpp = ifp;
+ *srcp = srcsock.sin6_addr;
+ return (0);
+ }
/*
* Otherwise, if the socket has already bound the source, just use it.
*/
@@ -684,13 +584,19 @@ in6_selectsrc(struct sockaddr_in6 *dst,
return (0);
}
/*
- * XXX: Bypass source address selection and use the primary jail IP
+ * Bypass source address selection and use the primary jail IP
* if requested.
*/
-#if 0
- if (cred != NULL && !prison_saddrsel_ip6(cred, srcp))
+ if (cred != NULL && !prison_saddrsel_ip6(cred, &srcsock)) {
+ if (ro == &ro6)
+ RO_RTFREE(ro);
+ error = check_addrs(&srcsock, dst, ifp);
+ if (error != 0)
+ return (error);
+ *ifpp = ifp;
+ *srcp = srcsock.sin6_addr;
return (0);
-#endif
+ }
/*
* If the address is not specified, choose the best one based on
More information about the svn-src-user
mailing list