]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/raw_ip.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / netinet / raw_ip.c
index 173b506a6f3fc2cae1a52db7d0f2dd9edf4b2db0..65f2d2a41fd33b2c9a3270937d2b24ca33b26f4c 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -22,7 +22,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
 #include <pexpert/pexpert.h>
 
 #include <net/if.h>
+#include <net/net_api_stats.h>
 #include <net/route.h>
 
 #define _IP_VHL
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
+#include <netinet/in_tclass.h>
 #include <netinet/ip.h>
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
@@ -197,9 +199,7 @@ static struct       sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET , 0, {0}, {0,0,0,0,
  * mbuf chain.
  */
 void
-rip_input(m, iphlen)
-       struct mbuf *m;
-       int iphlen;
+rip_input(struct mbuf *m, int iphlen)
 {
        struct ip *ip = mtod(m, struct ip *);
        struct inpcb *inp;
@@ -230,11 +230,12 @@ rip_input(m, iphlen)
                        continue;
                if (last) {
                        struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
-               
+
                        skipit = 0;
-                       
+
 #if NECP
-                       if (n && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0, &ip->ip_dst, &ip->ip_src, ifp, NULL)) {
+                       if (n && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
+                               &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
                                m_freem(n);
                                /* do not inject data to pcb */
                                skipit = 1;
@@ -253,7 +254,8 @@ rip_input(m, iphlen)
                                int error = 0;
                                if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
                                    (last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
-                                   (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
+                                   (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
+                                       (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
                                        ret = ip_savecontrol(last, &opts, ip, n);
                                        if (ret != 0) {
                                                m_freem(n);
@@ -275,7 +277,7 @@ rip_input(m, iphlen)
                                } else {
                                        if (error) {
                                                /* should notify about lost packet */
-                                               kprintf("rip_input can't append to socket\n");
+                                               ipstat.ips_raw_sappend_fail++;
                                        }
                                }
                                opts = 0;
@@ -286,7 +288,8 @@ rip_input(m, iphlen)
 
        skipit = 0;
 #if NECP
-       if (last && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0, &ip->ip_dst, &ip->ip_src, ifp, NULL)) {
+       if (last && !necp_socket_is_allowed_to_send_recv_v4(last, 0, 0,
+               &ip->ip_dst, &ip->ip_src, ifp, NULL, NULL, NULL)) {
                m_freem(m);
                OSAddAtomic(1, &ipstat.ips_delivered);
                /* do not inject data to pcb */
@@ -305,12 +308,13 @@ rip_input(m, iphlen)
                if (last) {
                        if ((last->inp_flags & INP_CONTROLOPTS) != 0 ||
                                (last->inp_socket->so_options & SO_TIMESTAMP) != 0 ||
-                               (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
+                               (last->inp_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0 ||
+                               (last->inp_socket->so_options & SO_TIMESTAMP_CONTINUOUS) != 0) {
                                ret = ip_savecontrol(last, &opts, ip, m);
                                if (ret != 0) {
                                        m_freem(m);
                                        m_freem(opts);
-                                       goto unlock;            
+                                       goto unlock;
                                }
                        }
                        if (last->inp_flags & INP_STRIPHDR) {
@@ -323,7 +327,7 @@ rip_input(m, iphlen)
                                (struct sockaddr *)&ripsrc, m, opts, NULL) != 0) {
                                sorwakeup(last->inp_socket);
                        } else {
-                               kprintf("rip_input(2) can't append to socket\n");
+                               ipstat.ips_raw_sappend_fail++;
                        }
                } else {
                        m_freem(m);
@@ -333,7 +337,7 @@ rip_input(m, iphlen)
        }
 unlock:
        /*
-        * Keep the list locked because socket filter may force the socket lock 
+        * Keep the list locked because socket filter may force the socket lock
         * to be released when calling sbappendaddr() -- see rdar://7627704
         */
        lck_rw_done(ripcbinfo.ipi_lock);
@@ -353,18 +357,28 @@ rip_output(
        struct ip *ip;
        struct inpcb *inp = sotoinpcb(so);
        int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
-       struct ip_out_args ipoa =
-           { IFSCOPE_NONE, { 0 }, IPOAF_SELECT_SRCIF, 0 };
+       struct ip_out_args ipoa;
        struct ip_moptions *imo;
        int error = 0;
-       mbuf_svc_class_t msc = MBUF_SC_UNSPEC;
+
+       bzero(&ipoa, sizeof(ipoa));
+       ipoa.ipoa_boundif = IFSCOPE_NONE;
+       ipoa.ipoa_flags = IPOAF_SELECT_SRCIF;
+
+       int sotc = SO_TC_UNSPEC;
+       int netsvctype = _NET_SERVICE_TYPE_UNSPEC;
+
 
        if (control != NULL) {
-               msc = mbuf_service_class_from_control(control);
+               sotc = so_tc_from_control(control, &netsvctype);
 
                m_freem(control);
                control = NULL;
        }
+       if (sotc == SO_TC_UNSPEC) {
+               sotc = so->so_traffic_class;
+               netsvctype = so->so_netsvctype;
+       }
 
        if (inp == NULL
 #if NECP
@@ -389,6 +403,8 @@ rip_output(
                ipoa.ipoa_flags |=  IPOAF_NO_EXPENSIVE;
        if (INP_AWDL_UNRESTRICTED(inp))
                ipoa.ipoa_flags |=  IPOAF_AWDL_UNRESTRICTED;
+       ipoa.ipoa_sotc = sotc;
+       ipoa.ipoa_netsvctype = netsvctype;
 
        if (inp->inp_flowhash == 0)
                inp->inp_flowhash = inp_calc_flowhash(inp);
@@ -402,7 +418,7 @@ rip_output(
                        m_freem(m);
                        return(EMSGSIZE);
                }
-               M_PREPEND(m, sizeof(struct ip), M_WAIT);
+               M_PREPEND(m, sizeof(struct ip), M_WAIT, 1);
                if (m == NULL)
                        return ENOBUFS;
                ip = mtod(m, struct ip *);
@@ -428,7 +444,7 @@ rip_output(
                        m_freem(m);
                        return EINVAL;
                }
-               if (ip->ip_id == 0)
+               if (ip->ip_id == 0 && !(rfc6864 && IP_OFF_IS_ATOMIC(ntohs(ip->ip_off))))
                        ip->ip_id = ip_randomid();
                /* XXX prevent ip_output from overwriting header fields */
                flags |= IP_RAWOUTPUT;
@@ -437,19 +453,69 @@ rip_output(
 
        if (inp->inp_laddr.s_addr != INADDR_ANY)
                ipoa.ipoa_flags |= IPOAF_BOUND_SRCADDR;
-       
+
 #if NECP
        {
                necp_kernel_policy_id policy_id;
-               if (!necp_socket_is_allowed_to_send_recv_v4(inp, 0, 0, &ip->ip_src, &ip->ip_dst, NULL, &policy_id)) {
+               necp_kernel_policy_id skip_policy_id;
+               u_int32_t route_rule_id;
+
+               /*
+                * We need a route to perform NECP route rule checks
+                */
+               if (net_qos_policy_restricted != 0 &&
+                   ROUTE_UNUSABLE(&inp->inp_route)) {
+                       struct sockaddr_in to;
+                       struct sockaddr_in from;
+                       struct in_addr laddr = ip->ip_src;
+
+                       ROUTE_RELEASE(&inp->inp_route);
+
+                       bzero(&from, sizeof(struct sockaddr_in));
+                       from.sin_family = AF_INET;
+                       from.sin_len = sizeof(struct sockaddr_in);
+                       from.sin_addr = laddr;
+
+                       bzero(&to, sizeof(struct sockaddr_in));
+                       to.sin_family = AF_INET;
+                       to.sin_len = sizeof(struct sockaddr_in);
+                       to.sin_addr.s_addr = ip->ip_dst.s_addr;
+
+                       if ((error = in_pcbladdr(inp, (struct sockaddr *)&to,
+                           &laddr, ipoa.ipoa_boundif, NULL, 1)) != 0) {
+                               printf("%s in_pcbladdr(%p) error %d\n",
+                                       __func__, inp, error);
+                               m_freem(m);
+                               return (error);
+                       }
+
+                       inp_update_necp_policy(inp, (struct sockaddr *)&from,
+                           (struct sockaddr *)&to, ipoa.ipoa_boundif);
+                       inp->inp_policyresult.results.qos_marking_gencount = 0;
+               }
+
+               if (!necp_socket_is_allowed_to_send_recv_v4(inp, 0, 0,
+                       &ip->ip_src, &ip->ip_dst, NULL, &policy_id, &route_rule_id, &skip_policy_id)) {
                        m_freem(m);
                        return(EHOSTUNREACH);
                }
 
-               necp_mark_packet_from_socket(m, inp, policy_id);
+               necp_mark_packet_from_socket(m, inp, policy_id, route_rule_id, skip_policy_id);
+
+               if (net_qos_policy_restricted != 0) {
+                       struct ifnet *rt_ifp = NULL;
+
+                       if (inp->inp_route.ro_rt != NULL)
+                               rt_ifp = inp->inp_route.ro_rt->rt_ifp;
+
+                       necp_socket_update_qos_marking(inp, inp->inp_route.ro_rt,
+                           NULL, route_rule_id);
+               }
        }
 #endif /* NECP */
-       
+       if ((so->so_flags1 & SOF1_QOSMARKING_ALLOWED))
+               ipoa.ipoa_flags |= IPOAF_QOSMARKING_ALLOWED;
+
 #if IPSEC
        if (inp->inp_sp != NULL && ipsec_setsocket(m, so) != 0) {
                m_freem(m);
@@ -460,12 +526,18 @@ rip_output(
        if (ROUTE_UNUSABLE(&inp->inp_route))
                ROUTE_RELEASE(&inp->inp_route);
 
-       set_packet_service_class(m, so, msc, 0);
+       set_packet_service_class(m, so, sotc, 0);
        m->m_pkthdr.pkt_flowsrc = FLOWSRC_INPCB;
        m->m_pkthdr.pkt_flowid = inp->inp_flowhash;
        m->m_pkthdr.pkt_flags |= (PKTF_FLOW_ID | PKTF_FLOW_LOCALSRC |
            PKTF_FLOW_RAWSOCK);
        m->m_pkthdr.pkt_proto = inp->inp_ip_p;
+       m->m_pkthdr.tx_rawip_pid = so->last_pid;
+       m->m_pkthdr.tx_rawip_e_pid = so->e_pid;
+       if (so->so_flags & SOF_DELEGATED)
+               m->m_pkthdr.tx_rawip_e_pid = so->e_pid;
+       else
+               m->m_pkthdr.tx_rawip_e_pid = 0;
 
 #if CONFIG_MACF_NET
        mac_mbuf_label_associate_inpcb(inp, m);
@@ -479,6 +551,7 @@ rip_output(
         * to pass the PCB cached route pointer directly to IP and
         * the modules beneath it.
         */
+       // TODO: PASS DOWN ROUTE RULE ID
        error = ip_output(m, inp->inp_options, &inp->inp_route, flags,
            imo, &ipoa);
 
@@ -506,8 +579,10 @@ rip_output(
                 * route is unicast, update outif with that of the
                 * route interface used by IP.
                 */
-               if (rt != NULL && (outif = rt->rt_ifp) != inp->inp_last_outifp)
+               if (rt != NULL &&
+                   (outif = rt->rt_ifp) != inp->inp_last_outifp) {
                        inp->inp_last_outifp = outif;
+               }
        } else {
                ROUTE_RELEASE(&inp->inp_route);
        }
@@ -528,15 +603,15 @@ int
 load_ipfw(void)
 {
        kern_return_t   err;
-       
+
        ipfw_init();
-       
+
 #if DUMMYNET
        if (!DUMMYNET_LOADED)
                ip_dn_init();
 #endif /* DUMMYNET */
        err = 0;
-       
+
        return err == 0 && ip_fw_ctl_ptr == NULL ? -1 : err;
 }
 #endif /* IPFIREWALL */
@@ -545,9 +620,7 @@ load_ipfw(void)
  * Raw IP socket option processing.
  */
 int
-rip_ctloutput(so, sopt)
-       struct socket *so;
-       struct sockopt *sopt;
+rip_ctloutput(struct socket *so, struct sockopt *sopt)
 {
        struct  inpcb *inp = sotoinpcb(so);
        int     error, optval;
@@ -689,11 +762,12 @@ void
 rip_ctlinput(
        int cmd,
        struct sockaddr *sa,
-       __unused void *vip)
+       __unused void *vip,
+       __unused struct ifnet *ifp)
 {
-       struct in_ifaddr *ia;
-       struct ifnet *ifp;
-       int err;
+       struct in_ifaddr *ia = NULL;
+       struct ifnet *iaifp = NULL;
+       int err = 0;
        int flags, done = 0;
 
        switch (cmd) {
@@ -753,10 +827,10 @@ rip_ctlinput(
                lck_rw_done(in_ifaddr_rwlock);
 
                flags = RTF_UP;
-               ifp = ia->ia_ifa.ifa_ifp;
+               iaifp = ia->ia_ifa.ifa_ifp;
 
-               if ((ifp->if_flags & IFF_LOOPBACK)
-                   || (ifp->if_flags & IFF_POINTOPOINT))
+               if ((iaifp->if_flags & IFF_LOOPBACK)
+                   || (iaifp->if_flags & IFF_POINTOPOINT))
                        flags |= RTF_HOST;
 
                err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
@@ -877,6 +951,7 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
        }
        inp->inp_laddr = sin.sin_addr;
        inp->inp_last_outifp = outif;
+
        return (0);
 }
 
@@ -899,6 +974,12 @@ rip_connect(struct socket *so, struct sockaddr *nam, __unused  struct proc *p)
        if ((addr->sin_family != AF_INET) &&
            (addr->sin_family != AF_IMPLINK))
                return EAFNOSUPPORT;
+
+       if (!(so->so_flags1 & SOF1_CONNECT_COUNTED)) {
+               so->so_flags1 |= SOF1_CONNECT_COUNTED;
+               INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_inet_dgram_connected);
+       }
+
        inp->inp_faddr = addr->sin_addr;
        soisconnected(so);
 
@@ -960,7 +1041,7 @@ bad:
 }
 
 /* note: rip_unlock is called from different protos  instead of the generic socket_unlock,
- * it will handle the socket dealloc on last reference 
+ * it will handle the socket dealloc on last reference
  * */
 int
 rip_unlock(struct socket *so, int refcount, void *debug)
@@ -1035,7 +1116,7 @@ rip_pcblist SYSCTL_HANDLER_ARGS
         */
        gencnt = ripcbinfo.ipi_gencnt;
        n = ripcbinfo.ipi_count;
-       
+
        bzero(&xig, sizeof(xig));
        xig.xig_len = sizeof xig;
        xig.xig_count = n;
@@ -1051,7 +1132,7 @@ rip_pcblist SYSCTL_HANDLER_ARGS
      */
     if (n == 0) {
        lck_rw_done(ripcbinfo.ipi_lock);
-        return 0; 
+        return 0;
     }
 
        inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
@@ -1059,7 +1140,7 @@ rip_pcblist SYSCTL_HANDLER_ARGS
                lck_rw_done(ripcbinfo.ipi_lock);
                return ENOMEM;
        }
-       
+
        for (inp = ripcbinfo.ipi_listhead->lh_first, i = 0; inp && i < n;
             inp = inp->inp_list.le_next) {
                if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
@@ -1106,6 +1187,7 @@ SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist,
            CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
            rip_pcblist, "S,xinpcb", "List of active raw IP sockets");
 
+#if !CONFIG_EMBEDDED
 
 static int
 rip_pcblist64 SYSCTL_HANDLER_ARGS
@@ -1209,6 +1291,7 @@ SYSCTL_PROC(_net_inet_raw, OID_AUTO, pcblist64,
             CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0,
             rip_pcblist64, "S,xinpcb64", "List of active raw IP sockets");
 
+#endif /* !CONFIG_EMBEDDED */
 
 
 static int