X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..ebb1b9f42b62218f29061826217bb0f71cd375a6:/bsd/netinet/ip_icmp.c diff --git a/bsd/netinet/ip_icmp.c b/bsd/netinet/ip_icmp.c index 62e978023..48ea2f0f5 100644 --- a/bsd/netinet/ip_icmp.c +++ b/bsd/netinet/ip_icmp.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2000-2010 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * @APPLE_LICENSE_OSREFERENCE_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 + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * 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. * - * 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 - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1982, 1986, 1988, 1993 @@ -61,6 +59,12 @@ * * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 */ +/* + * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ #include #include @@ -71,6 +75,8 @@ #include #include +#include + #include #include @@ -104,7 +110,12 @@ */ #ifndef M_SKIP_FIREWALL #define M_SKIP_FIREWALL 0x4000 -#endif +#endif + +#if CONFIG_MACF_NET +#include +#endif /* MAC_NET */ + /* * ICMP routines: error generation, receive packet processing, and @@ -112,24 +123,24 @@ * host table maintenance routines. */ -static struct icmpstat icmpstat; -SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD, +struct icmpstat icmpstat; +SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD | CTLFLAG_LOCKED, &icmpstat, icmpstat, ""); static int icmpmaskrepl = 0; -SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, +SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW | CTLFLAG_LOCKED, &icmpmaskrepl, 0, ""); static int icmptimestamp = 0; -SYSCTL_INT(_net_inet_icmp, ICMPCTL_TIMESTAMP, timestamp, CTLFLAG_RW, +SYSCTL_INT(_net_inet_icmp, ICMPCTL_TIMESTAMP, timestamp, CTLFLAG_RW | CTLFLAG_LOCKED, &icmptimestamp, 0, ""); static int drop_redirect = 0; -SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW, +SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW | CTLFLAG_LOCKED, &drop_redirect, 0, ""); static int log_redirect = 0; -SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW, +SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW | CTLFLAG_LOCKED, &log_redirect, 0, ""); #if ICMP_BANDLIM @@ -140,12 +151,12 @@ SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW, */ static int icmplim = 250; -SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW, +SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW | CTLFLAG_LOCKED, &icmplim, 0, ""); #else static int icmplim = -1; -SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD, +SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD | CTLFLAG_LOCKED, &icmplim, 0, ""); #endif @@ -155,7 +166,7 @@ SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD, */ static int icmpbmcastecho = 1; -SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, +SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW | CTLFLAG_LOCKED, &icmpbmcastecho, 0, ""); @@ -165,7 +176,6 @@ int icmpprintfs = 0; static void icmp_reflect(struct mbuf *); static void icmp_send(struct mbuf *, struct mbuf *); -static int ip_next_mtu(int, int); extern struct protosw inetsw[]; @@ -179,12 +189,12 @@ icmp_error( int type, int code, n_long dest, - struct ifnet *destifp) + u_int32_t nextmtu) { - register struct ip *oip = mtod(n, struct ip *), *nip; - register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; - register struct icmp *icp; - register struct mbuf *m; + struct ip *oip = mtod(n, struct ip *), *nip; + unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; + struct icmp *icp; + struct mbuf *m; unsigned icmplen; #if ICMPPRINTFS @@ -212,15 +222,18 @@ icmp_error( /* * First, formulate icmp message */ - m = m_gethdr(M_DONTWAIT, MT_HEADER); + m = m_gethdr(M_DONTWAIT, MT_HEADER); /* MAC-OK */ if (m == NULL) goto freeit; - if (n->m_flags & M_SKIP_FIREWALL) { + if (n->m_flags & M_SKIP_FIREWALL) { /* set M_SKIP_FIREWALL to skip firewall check, since we're called from firewall */ m->m_flags |= M_SKIP_FIREWALL; } +#if CONFIG_MACF_NET + mac_mbuf_label_associate_netlayer(n, m); +#endif icmplen = min(oiplen + 8, oip->ip_len); if (icmplen < sizeof(struct ip)) { printf("icmp_error: bad length\n"); @@ -246,8 +259,8 @@ icmp_error( icp->icmp_pptr = code; code = 0; } else if (type == ICMP_UNREACH && - code == ICMP_UNREACH_NEEDFRAG && destifp) { - icp->icmp_nextmtu = htons(destifp->if_mtu); + code == ICMP_UNREACH_NEEDFRAG && nextmtu != 0) { + icp->icmp_nextmtu = htons(nextmtu); } } @@ -258,9 +271,10 @@ icmp_error( /* * Convert fields to network representation. */ +#if BYTE_ORDER != BIG_ENDIAN HTONS(nip->ip_len); HTONS(nip->ip_off); - +#endif /* * Now, copy old ip header (without options) * in front of icmp message. @@ -271,7 +285,6 @@ icmp_error( m->m_len += sizeof(struct ip); m->m_pkthdr.len = m->m_len; m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; - m->m_pkthdr.aux = NULL; /* for IPsec */ nip = mtod(m, struct ip *); bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); nip->ip_len = m->m_len; @@ -284,26 +297,26 @@ freeit: m_freem(n); } -static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; -static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; -static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; +static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET, + 0 , { 0 }, { 0,0,0,0,0,0,0,0 } }; +static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET, + 0 , { 0 }, { 0,0,0,0,0,0,0,0 } }; +static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET, + 0 , { 0 }, { 0,0,0,0,0,0,0,0 } }; /* * Process a received ICMP message. */ void -icmp_input(m, hlen) - register struct mbuf *m; - int hlen; +icmp_input(struct mbuf *m, int hlen) { - register struct icmp *icp; - register struct ip *ip = mtod(m, struct ip *); + struct icmp *icp; + struct ip *ip = mtod(m, struct ip *); int icmplen = ip->ip_len; - register int i; + int i; struct in_ifaddr *ia; void (*ctlfunc)(int, struct sockaddr *, void *); int code; - char ipv4str[MAX_IPv4_STR_LEN]; /* * Locate icmp structure in mbuf, and check @@ -312,6 +325,7 @@ icmp_input(m, hlen) #if ICMPPRINTFS if (icmpprintfs) { char buf[MAX_IPv4_STR_LEN]; + char ipv4str[MAX_IPv4_STR_LEN]; printf("icmp_input from %s to %s, len %d\n", inet_ntop(AF_INET, &ip->ip_src, buf, sizeof(buf)), @@ -433,7 +447,11 @@ icmp_input(m, hlen) icmpstat.icps_badlen++; goto freeit; } + +#if BYTE_ORDER != BIG_ENDIAN NTOHS(icp->icmp_ip.ip_len); +#endif + /* Discard ICMP's in response to multicast packets */ if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) goto badcode; @@ -442,52 +460,7 @@ icmp_input(m, hlen) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); #endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; -#if 1 - /* - * MTU discovery: - * If we got a needfrag and there is a host route to the - * original destination, and the MTU is not locked, then - * set the MTU in the route to the suggested new value - * (if given) and then notify as usual. The ULPs will - * notice that the MTU has changed and adapt accordingly. - * If no new MTU was suggested, then we guess a new one - * less than the current value. If the new MTU is - * unreasonably small (defined by sysctl tcp_minmss), then - * we reset the MTU to the interface value and enable the - * lock bit, indicating that we are no longer doing MTU - * discovery. - */ - if (code == PRC_MSGSIZE) { - struct rtentry *rt; - int mtu; - - rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, - RTF_CLONING | RTF_PRCLONING); - if (rt && (rt->rt_flags & RTF_HOST) - && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { - mtu = ntohs(icp->icmp_nextmtu); - if (!mtu) - mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, - 1); -#if DEBUG_MTUDISC - printf("MTU for %s reduced to %d\n", - inet_ntop(AF_INET, &icmpsrc.sin_addr, ipv4str, - sizeof(ipv4str)), - mtu); -#endif - if (mtu < max(296, (tcp_minmss + sizeof(struct tcpiphdr)))) { - /* rt->rt_rmx.rmx_mtu = - rt->rt_ifp->if_mtu; */ - rt->rt_rmx.rmx_locks |= RTV_MTU; - } else if (rt->rt_rmx.rmx_mtu > mtu) { - rt->rt_rmx.rmx_mtu = mtu; - } - } - if (rt) - rtfree(rt); - } -#endif /* * XXX if the packet contains [IPv4 AH TCP], we can't make a * notification to TCP layer. @@ -564,9 +537,11 @@ icmp_input(m, hlen) (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); if (ia == 0) break; + IFA_LOCK(&ia->ia_ifa); if (ia->ia_ifp == 0) { - ifafree(&ia->ia_ifa); - ia = 0; + IFA_UNLOCK(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); + ia = NULL; break; } icp->icmp_type = ICMP_MASKREPLY; @@ -577,7 +552,8 @@ icmp_input(m, hlen) else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; } - ifafree(&ia->ia_ifa); + IFA_UNLOCK(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); reflect: ip->ip_len += hlen; /* since ip_input deducts this */ icmpstat.icps_reflect++; @@ -587,7 +563,7 @@ reflect: case ICMP_REDIRECT: if (log_redirect) { - u_long src, dst, gw; + u_int32_t src, dst, gw; src = ntohl(ip->ip_src.s_addr); dst = ntohl(icp->icmp_ip.ip_dst.s_addr); @@ -630,10 +606,9 @@ reflect: } #endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; - rtredirect((struct sockaddr *)&icmpsrc, - (struct sockaddr *)&icmpdst, - (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, - (struct sockaddr *)&icmpgw, (struct rtentry **)0); + rtredirect(m->m_pkthdr.rcvif, (struct sockaddr *)&icmpsrc, + (struct sockaddr *)&icmpdst, NULL, RTF_GATEWAY | RTF_HOST, + (struct sockaddr *)&icmpgw, NULL); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); #if IPSEC key_sa_routechange((struct sockaddr *)&icmpsrc); @@ -666,13 +641,12 @@ freeit: * Reflect the ip packet back to the source */ static void -icmp_reflect(m) - struct mbuf *m; +icmp_reflect(struct mbuf *m) { - register struct ip *ip = mtod(m, struct ip *); - register struct in_ifaddr *ia; + struct ip *ip = mtod(m, struct ip *); + struct in_ifaddr *ia; struct in_addr t; - struct mbuf *opts = 0; + struct mbuf *opts = NULL; int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip); if (!in_canforward(ip->ip_src) && @@ -689,16 +663,33 @@ icmp_reflect(m) * or anonymous), use the address which corresponds * to the incoming interface. */ - lck_mtx_lock(rt_mtx); + lck_rw_lock_shared(in_ifaddr_rwlock); + TAILQ_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash) { + IFA_LOCK(&ia->ia_ifa); + if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) { + IFA_ADDREF_LOCKED(&ia->ia_ifa); + IFA_UNLOCK(&ia->ia_ifa); + goto match; + } + IFA_UNLOCK(&ia->ia_ifa); + } + /* + * Slow path; check for broadcast addresses. Find a source + * IP address to use when replying to the broadcast request; + * let IP handle the source interface selection work. + */ for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { - if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) - break; + IFA_LOCK(&ia->ia_ifa); if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) && - t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) + t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) { + IFA_ADDREF_LOCKED(&ia->ia_ifa); + IFA_UNLOCK(&ia->ia_ifa); break; + } + IFA_UNLOCK(&ia->ia_ifa); } - if (ia) - ifaref(&ia->ia_ifa); +match: + lck_rw_done(in_ifaddr_rwlock); icmpdst.sin_addr = t; if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif) ia = (struct in_ifaddr *)ifaof_ifpforaddr( @@ -708,23 +699,29 @@ icmp_reflect(m) * and was received on an interface with no IP address. */ if (ia == (struct in_ifaddr *)0) { + lck_rw_lock_shared(in_ifaddr_rwlock); ia = in_ifaddrhead.tqh_first; if (ia == (struct in_ifaddr *)0) {/* no address yet, bail out */ + lck_rw_done(in_ifaddr_rwlock); m_freem(m); - lck_mtx_unlock(rt_mtx); goto done; } - ifaref(&ia->ia_ifa); + IFA_ADDREF(&ia->ia_ifa); + lck_rw_done(in_ifaddr_rwlock); } - lck_mtx_unlock(rt_mtx); +#if CONFIG_MACF_NET + mac_netinet_icmp_reply(m); +#endif + IFA_LOCK_SPIN(&ia->ia_ifa); t = IA_SIN(ia)->sin_addr; + IFA_UNLOCK(&ia->ia_ifa); ip->ip_src = t; ip->ip_ttl = ip_defttl; - ifafree(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); ia = NULL; if (optlen > 0) { - register u_char *cp; + u_char *cp; int opt, cnt; u_int len; @@ -734,7 +731,7 @@ icmp_reflect(m) */ cp = (u_char *) (ip + 1); if ((opts = ip_srcroute()) == 0 && - (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { + (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { /* MAC-OK */ opts->m_len = sizeof(struct in_addr); mtod(opts, struct in_addr *)->s_addr = 0; } @@ -807,15 +804,16 @@ done: * after supplying a checksum. */ static void -icmp_send(m, opts) - register struct mbuf *m; - struct mbuf *opts; +icmp_send(struct mbuf *m, struct mbuf *opts) { - register struct ip *ip = mtod(m, struct ip *); - register int hlen; - register struct icmp *icp; + struct ip *ip = mtod(m, struct ip *); + int hlen; + struct icmp *icp; struct route ro; - char ipv4str[MAX_IPv4_STR_LEN]; + struct ip_out_args ipoa = { IFSCOPE_NONE, 0 }; + + if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.rcvif != NULL) + ipoa.ipoa_boundif = m->m_pkthdr.rcvif->if_index; hlen = IP_VHL_HL(ip->ip_vhl) << 2; m->m_data += hlen; @@ -825,13 +823,13 @@ icmp_send(m, opts) icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); m->m_data -= hlen; m->m_len += hlen; - m->m_pkthdr.rcvif = 0; - m->m_pkthdr.aux = NULL; + m->m_pkthdr.rcvif = NULL; m->m_pkthdr.csum_data = 0; m->m_pkthdr.csum_flags = 0; #if ICMPPRINTFS if (icmpprintfs) { char buf[MAX_IPv4_STR_LEN]; + char ipv4str[MAX_IPv4_STR_LEN]; printf("icmp_send dst %s src %s\n", inet_ntop(AF_INET, &ip->ip_dst, buf, sizeof(buf)), @@ -839,16 +837,16 @@ icmp_send(m, opts) } #endif bzero(&ro, sizeof ro); - (void) ip_output(m, opts, &ro, 0, NULL); + (void) ip_output(m, opts, &ro, IP_OUTARGS, NULL, &ipoa); if (ro.ro_rt) rtfree(ro.ro_rt); } n_time -iptime() +iptime(void) { struct timeval atv; - u_long t; + u_int32_t t; microtime(&atv); t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; @@ -861,10 +859,8 @@ iptime() * given current value MTU. If DIR is less than zero, a larger plateau * is returned; otherwise, a smaller value is returned. */ -static int -ip_next_mtu(mtu, dir) - int mtu; - int dir; +int +ip_next_mtu(int mtu, int dir) { static int mtutab[] = { 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, @@ -986,8 +982,8 @@ badport_bandlim(int which) #include extern struct domain inetdomain; -extern u_long rip_sendspace; -extern u_long rip_recvspace; +extern u_int32_t rip_sendspace; +extern u_int32_t rip_recvspace; extern struct inpcbinfo ripcbinfo; int rip_abort(struct socket *); @@ -1011,10 +1007,10 @@ __private_extern__ struct pr_usrreqs icmp_dgram_usrreqs = { /* Like rip_attach but without root privilege enforcement */ __private_extern__ int -icmp_dgram_attach(struct socket *so, int proto, struct proc *p) +icmp_dgram_attach(struct socket *so, __unused int proto, struct proc *p) { struct inpcb *inp; - int error, s; + int error; inp = sotoinpcb(so); if (inp) @@ -1023,9 +1019,7 @@ icmp_dgram_attach(struct socket *so, int proto, struct proc *p) error = soreserve(so, rip_sendspace, rip_recvspace); if (error) return error; - s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); - splx(s); if (error) return error; inp = (struct inpcb *)so->so_pcb; @@ -1041,8 +1035,7 @@ icmp_dgram_attach(struct socket *so, int proto, struct proc *p) __private_extern__ int icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt) { - struct inpcb *inp = sotoinpcb(so); - int error, optval; + int error; if (sopt->sopt_level != IPPROTO_IP) return (EINVAL); @@ -1057,6 +1050,7 @@ icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt) case IP_RECVDSTADDR: case IP_RETOPTS: case IP_MULTICAST_IF: + case IP_MULTICAST_IFINDEX: case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: case IP_ADD_MEMBERSHIP: @@ -1070,9 +1064,14 @@ icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt) #endif case IP_STRIPHDR: case IP_RECVTTL: + case IP_BOUND_IF: +#if CONFIG_FORCE_OUT_IFP + case IP_FORCE_OUT_IFP: +#endif + case IP_NO_IFT_CELLULAR: error = rip_ctloutput(so, sopt); break; - + default: error = EINVAL; break; @@ -1109,7 +1108,7 @@ icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *n if (hlen < 20 || hlen > 40 || ip->ip_len != m->m_pkthdr.len) goto bad; /* Bogus fragments can tie up peer resources */ - if (ip->ip_off != 0) + if ((ip->ip_off & ~IP_DF) != 0) goto bad; /* Allow only ICMP even for user provided IP header */ if (ip->ip_p != IPPROTO_ICMP) @@ -1117,20 +1116,25 @@ icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *n /* To prevent spoofing, specified source address must be one of ours */ if (ip->ip_src.s_addr != INADDR_ANY) { socket_unlock(so, 0); - lck_mtx_lock(rt_mtx); + lck_rw_lock_shared(in_ifaddr_rwlock); if (TAILQ_EMPTY(&in_ifaddrhead)) { - lck_mtx_unlock(rt_mtx); + lck_rw_done(in_ifaddr_rwlock); socket_lock(so, 0); goto bad; } - TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { - if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_src.s_addr) { - lck_mtx_unlock(rt_mtx); + TAILQ_FOREACH(ia, INADDR_HASH(ip->ip_src.s_addr), + ia_hash) { + IFA_LOCK(&ia->ia_ifa); + if (IA_SIN(ia)->sin_addr.s_addr == + ip->ip_src.s_addr) { + IFA_UNLOCK(&ia->ia_ifa); + lck_rw_done(in_ifaddr_rwlock); socket_lock(so, 0); goto ours; } + IFA_UNLOCK(&ia->ia_ifa); } - lck_mtx_unlock(rt_mtx); + lck_rw_done(in_ifaddr_rwlock); socket_lock(so, 0); goto bad; } @@ -1172,4 +1176,3 @@ bad: } #endif /* __APPLE__ */ -