X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..ebb1b9f42b62218f29061826217bb0f71cd375a6:/bsd/netinet/ip_icmp.c diff --git a/bsd/netinet/ip_icmp.c b/bsd/netinet/ip_icmp.c index 82ba9a44f..48ea2f0f5 100644 --- a/bsd/netinet/ip_icmp.c +++ b/bsd/netinet/ip_icmp.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2010 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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 Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1982, 1986, 1988, 1993 @@ -53,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 @@ -63,6 +75,8 @@ #include #include +#include + #include #include @@ -91,30 +105,42 @@ #include #endif + /* XXX This one should go in sys/mbuf.h. It is used to avoid that + * a firewall-generated packet loops forever through the firewall. + */ +#ifndef M_SKIP_FIREWALL +#define M_SKIP_FIREWALL 0x4000 +#endif + +#if CONFIG_MACF_NET +#include +#endif /* MAC_NET */ + + /* * ICMP routines: error generation, receive packet processing, and * routines to turnaround packets back to the originator, and * 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 @@ -125,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 @@ -140,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, ""); @@ -148,9 +174,8 @@ SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, int icmpprintfs = 0; #endif -static void icmp_reflect __P((struct mbuf *)); -static void icmp_send __P((struct mbuf *, struct mbuf *)); -static int ip_next_mtu __P((int, int)); +static void icmp_reflect(struct mbuf *); +static void icmp_send(struct mbuf *, struct mbuf *); extern struct protosw inetsw[]; @@ -159,16 +184,17 @@ extern struct protosw inetsw[]; * in response to bad packet ip. */ void -icmp_error(n, type, code, dest, destifp) - struct mbuf *n; - int type, code; - n_long dest; - struct ifnet *destifp; +icmp_error( + struct mbuf *n, + int type, + int code, + n_long dest, + 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 @@ -196,9 +222,18 @@ icmp_error(n, type, code, dest, destifp) /* * 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) { + /* 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"); @@ -224,8 +259,8 @@ icmp_error(n, type, code, dest, destifp) 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); } } @@ -236,9 +271,10 @@ icmp_error(n, type, code, dest, destifp) /* * 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. @@ -249,7 +285,6 @@ icmp_error(n, type, code, dest, destifp) 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; @@ -262,24 +297,25 @@ 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) __P((int, struct sockaddr *, void *)); + void (*ctlfunc)(int, struct sockaddr *, void *); int code; /* @@ -288,10 +324,13 @@ icmp_input(m, hlen) */ #if ICMPPRINTFS if (icmpprintfs) { - char buf[4 * sizeof "123"]; - strcpy(buf, inet_ntoa(ip->ip_src)); + char buf[MAX_IPv4_STR_LEN]; + char ipv4str[MAX_IPv4_STR_LEN]; + printf("icmp_input from %s to %s, len %d\n", - buf, inet_ntoa(ip->ip_dst), icmplen); + inet_ntop(AF_INET, &ip->ip_src, buf, sizeof(buf)), + inet_ntop(AF_INET, &ip->ip_dst, ipv4str, sizeof(ipv4str)), + icmplen); } #endif if (icmplen < ICMP_MINLEN) { @@ -408,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; @@ -417,50 +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_ntoa(icmpsrc.sin_addr), 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. @@ -537,8 +537,13 @@ icmp_input(m, hlen) (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); if (ia == 0) break; - if (ia->ia_ifp == 0) + IFA_LOCK(&ia->ia_ifa); + if (ia->ia_ifp == 0) { + IFA_UNLOCK(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); + ia = NULL; break; + } icp->icmp_type = ICMP_MASKREPLY; icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; if (ip->ip_src.s_addr == 0) { @@ -547,6 +552,8 @@ icmp_input(m, hlen) else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; } + IFA_UNLOCK(&ia->ia_ifa); + IFA_REMREF(&ia->ia_ifa); reflect: ip->ip_len += hlen; /* since ip_input deducts this */ icmpstat.icps_reflect++; @@ -556,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); @@ -590,18 +597,18 @@ reflect: icmpdst.sin_addr = icp->icmp_gwaddr; #if ICMPPRINTFS if (icmpprintfs) { - char buf[4 * sizeof "123"]; - strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst)); + char buf[MAX_IPv4_STR_LEN]; printf("redirect dst %s to %s\n", - buf, inet_ntoa(icp->icmp_gwaddr)); + inet_ntop(AF_INET, &icp->icmp_ip.ip_dst, buf, sizeof(buf)), + inet_ntop(AF_INET, &icp->icmp_gwaddr, ipv4str, + sizeof(ipv4str))); } #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); @@ -634,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) && @@ -657,13 +663,33 @@ icmp_reflect(m) * or anonymous), use the address which corresponds * to the incoming interface. */ + 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); } +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( @@ -672,14 +698,30 @@ icmp_reflect(m) * The following happens if the packet was not addressed to us, * and was received on an interface with no IP address. */ - if (ia == (struct in_ifaddr *)0) + 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); + goto done; + } + IFA_ADDREF(&ia->ia_ifa); + lck_rw_done(in_ifaddr_rwlock); + } +#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; + IFA_REMREF(&ia->ia_ifa); + ia = NULL; if (optlen > 0) { - register u_char *cp; + u_char *cp; int opt, cnt; u_int len; @@ -689,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; } @@ -762,14 +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; + 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; @@ -779,29 +823,30 @@ 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 = (struct ifnet *)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[4 * sizeof "123"]; - strcpy(buf, inet_ntoa(ip->ip_dst)); + char buf[MAX_IPv4_STR_LEN]; + char ipv4str[MAX_IPv4_STR_LEN]; + printf("icmp_send dst %s src %s\n", - buf, inet_ntoa(ip->ip_src)); + inet_ntop(AF_INET, &ip->ip_dst, buf, sizeof(buf)), + inet_ntop(AF_INET, &ip->ip_src, ipv4str, sizeof(ipv4str))); } #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; @@ -814,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, @@ -893,7 +936,7 @@ badport_bandlim(int which) if (icmplim <= 0 || which > BANDLIM_MAX || which < 0) return(0); - getmicrotime(&time); + getmicrouptime(&time); secs = time.tv_sec - lticks[which].tv_sec ; @@ -939,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 *); @@ -959,15 +1002,15 @@ __private_extern__ struct pr_usrreqs icmp_dgram_usrreqs = { pru_connect2_notsupp, in_control, rip_detach, rip_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, icmp_dgram_send, pru_sense_null, rip_shutdown, - in_setsockaddr, sosend, soreceive, sopoll + in_setsockaddr, sosend, soreceive, pru_sopoll_notsupp }; /* 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) @@ -976,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; @@ -994,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); @@ -1010,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: @@ -1023,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; @@ -1059,23 +1105,37 @@ icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *n /* Only IPv4 */ if (IP_VHL_V(ip->ip_vhl) != 4) goto bad; - if (hlen < 20 || hlen > 40 || ip->ip_len != m->m_pkthdr.len || - ip->ip_len > 65535) + 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) goto bad; /* To prevent spoofing, specified source address must be one of ours */ if (ip->ip_src.s_addr != INADDR_ANY) { - if (TAILQ_EMPTY(&in_ifaddrhead)) + socket_unlock(so, 0); + lck_rw_lock_shared(in_ifaddr_rwlock); + if (TAILQ_EMPTY(&in_ifaddrhead)) { + 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) + } + 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_rw_done(in_ifaddr_rwlock); + socket_lock(so, 0); goto bad; } ours: @@ -1116,4 +1176,3 @@ bad: } #endif /* __APPLE__ */ -