X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/netinet/raw_ip.c diff --git a/bsd/netinet/raw_ip.c b/bsd/netinet/raw_ip.c index 173b506a6..65f2d2a41 100644 --- a/bsd/netinet/raw_ip.c +++ b/bsd/netinet/raw_ip.c @@ -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 @@ -11,10 +11,10 @@ * 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@ */ /* @@ -84,11 +84,13 @@ #include #include +#include #include #define _IP_VHL #include #include +#include #include #include #include @@ -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