]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/ip_output.c
xnu-1504.9.37.tar.gz
[apple/xnu.git] / bsd / netinet / ip_output.c
index a989e64e33da6224275720ec668870ec9deeac80..07d74f97fbda3a7eaa03630f62400b5c7da0ccb7 100644 (file)
@@ -2305,10 +2305,15 @@ ip_ctloutput(so, sopt)
                        if (error) 
                                break;
 
-                       if (background) 
-                               so->so_traffic_mgt_flags |= TRAFFIC_MGT_SO_BACKGROUND;
-                       else 
-                               so->so_traffic_mgt_flags &= ~TRAFFIC_MGT_SO_BACKGROUND;
+                       if (background) {
+                               socket_set_traffic_mgt_flags(so,
+                                   TRAFFIC_MGT_SO_BACKGROUND |
+                                   TRAFFIC_MGT_SO_BG_REGULATE);
+                       } else {
+                               socket_clear_traffic_mgt_flags(so,
+                                   TRAFFIC_MGT_SO_BACKGROUND |
+                                   TRAFFIC_MGT_SO_BG_REGULATE);
+                       }
 
                        break;
                }
@@ -3177,7 +3182,7 @@ in_selectsrcif(struct ip *ip, struct route *ro, unsigned int ifscope)
        struct in_addr src = ip->ip_src;
        struct in_addr dst = ip->ip_dst;
        struct ifnet *rt_ifp;
-       char s_src[16], s_dst[16];
+       char s_src[MAX_IPv4_STR_LEN], s_dst[MAX_IPv4_STR_LEN];
 
        if (ip_select_srcif_debug) {
                (void) inet_ntop(AF_INET, &src.s_addr, s_src, sizeof (s_src));
@@ -3217,6 +3222,22 @@ in_selectsrcif(struct ip *ip, struct route *ro, unsigned int ifscope)
 
                ifa = (struct ifaddr *)ifa_foraddr_scoped(src.s_addr, scope);
 
+               if (ifa == NULL && ip->ip_p != IPPROTO_UDP &&
+                   ip->ip_p != IPPROTO_TCP && ipforwarding) {
+                       /*
+                        * If forwarding is enabled, and if the packet isn't
+                        * TCP or UDP, check if the source address belongs
+                        * to one of our own interfaces; if so, demote the
+                        * interface scope and do a route lookup right below.
+                        */
+                       ifa = (struct ifaddr *)ifa_foraddr(src.s_addr);
+                       if (ifa != NULL) {
+                               ifafree(ifa);
+                               ifa = NULL;
+                               ifscope = IFSCOPE_NONE;
+                       }
+               }
+
                if (ip_select_srcif_debug && ifa != NULL) {
                        if (ro->ro_rt != NULL) {
                                printf("%s->%s ifscope %d->%d ifa_if %s%d "
@@ -3246,6 +3267,103 @@ in_selectsrcif(struct ip *ip, struct route *ro, unsigned int ifscope)
        if (ifa == NULL && ifscope == IFSCOPE_NONE) {
                ifa = (struct ifaddr *)ifa_foraddr(src.s_addr);
 
+               /*
+                * If we have the IP address, but not the route, we don't
+                * really know whether or not it belongs to the correct
+                * interface (it could be shared across multiple interfaces.)
+                * The only way to find out is to do a route lookup.
+                */
+               if (ifa != NULL && ro->ro_rt == NULL) {
+                       struct rtentry *rt;
+                       struct sockaddr_in sin;
+                       struct ifaddr *oifa = NULL;
+
+                       bzero(&sin, sizeof (sin));
+                       sin.sin_family = AF_INET;
+                       sin.sin_len = sizeof (sin);
+                       sin.sin_addr = dst;
+
+                       lck_mtx_lock(rnh_lock);
+                       if ((rt = rt_lookup(TRUE, (struct sockaddr *)&sin, NULL,
+                           rt_tables[AF_INET], IFSCOPE_NONE)) != NULL) {
+                               RT_LOCK(rt);
+                               /*
+                                * If the route uses a different interface,
+                                * use that one instead.  The IP address of
+                                * the ifaddr that we pick up here is not
+                                * relevant.
+                                */
+                               if (ifa->ifa_ifp != rt->rt_ifp) {
+                                       oifa = ifa;
+                                       ifa = rt->rt_ifa;
+                                       ifaref(ifa);
+                                       RT_UNLOCK(rt);
+                               } else {
+                                       RT_UNLOCK(rt);
+                               }
+                               rtfree_locked(rt);
+                       }
+                       lck_mtx_unlock(rnh_lock);
+
+                       if (oifa != NULL) {
+                               struct ifaddr *iifa;
+
+                               /*
+                                * See if the interface pointed to by the
+                                * route is configured with the source IP
+                                * address of the packet.
+                                */
+                               iifa = (struct ifaddr *)ifa_foraddr_scoped(
+                                   src.s_addr, ifa->ifa_ifp->if_index);
+
+                               if (iifa != NULL) {
+                                       /*
+                                        * Found it; drop the original one
+                                        * as well as the route interface
+                                        * address, and use this instead.
+                                        */
+                                       ifafree(oifa);
+                                       ifafree(ifa);
+                                       ifa = iifa;
+                               } else if (!ipforwarding ||
+                                   (rt->rt_flags & RTF_GATEWAY)) {
+                                       /*
+                                        * This interface doesn't have that
+                                        * source IP address; drop the route
+                                        * interface address and just use the
+                                        * original one, and let the caller
+                                        * do a scoped route lookup.
+                                        */
+                                       ifafree(ifa);
+                                       ifa = oifa;
+                               } else {
+                                       /*
+                                        * Forwarding is enabled and the source
+                                        * address belongs to one of our own
+                                        * interfaces which isn't the outgoing
+                                        * interface, and we have a route, and
+                                        * the destination is on a network that
+                                        * is directly attached (onlink); drop
+                                        * the original one and use the route
+                                        * interface address instead.
+                                        */
+                                       ifafree(oifa);
+                               }
+                       }
+               } else if (ifa != NULL && ro->ro_rt != NULL &&
+                   !(ro->ro_rt->rt_flags & RTF_GATEWAY) &&
+                   ifa->ifa_ifp != ro->ro_rt->rt_ifp && ipforwarding) {
+                       /*
+                        * Forwarding is enabled and the source address belongs
+                        * to one of our own interfaces which isn't the same
+                        * as the interface used by the known route; drop the
+                        * original one and use the route interface address.
+                        */
+                       ifafree(ifa);
+                       ifa = ro->ro_rt->rt_ifa;
+                       ifaref(ifa);
+               }
+
                if (ip_select_srcif_debug && ifa != NULL) {
                        printf("%s->%s ifscope %d ifa_if %s%d\n",
                            s_src, s_dst, ifscope, ifa->ifa_ifp->if_name,