X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d7e50217d7adf6e52786a38bcaa4cd698cb9a79e..c0fea4742e91338fffdcf79f86a7c1d5e2b97eb1:/bsd/netinet/ip_icmp.c diff --git a/bsd/netinet/ip_icmp.c b/bsd/netinet/ip_icmp.c index fb9424877..030ef0680 100644 --- a/bsd/netinet/ip_icmp.c +++ b/bsd/netinet/ip_icmp.c @@ -3,22 +3,19 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * 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. 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 + * This 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. + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. * * @APPLE_LICENSE_HEADER_END@ */ @@ -77,6 +74,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #if IPSEC #include @@ -86,6 +89,13 @@ #if defined(NFAITH) && NFAITH > 0 #include "faith.h" #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 /* @@ -102,6 +112,10 @@ static int icmpmaskrepl = 0; SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, &icmpmaskrepl, 0, ""); +static int icmptimestamp = 0; +SYSCTL_INT(_net_inet_icmp, ICMPCTL_TIMESTAMP, timestamp, CTLFLAG_RW, + &icmptimestamp, 0, ""); + static int drop_redirect = 0; SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW, &drop_redirect, 0, ""); @@ -117,7 +131,7 @@ SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW, * variable content is -1 and read-only. */ -static int icmplim = 100; +static int icmplim = 250; SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW, &icmplim, 0, ""); #else @@ -141,9 +155,9 @@ 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 *); +static int ip_next_mtu(int, int); extern struct protosw inetsw[]; @@ -152,11 +166,12 @@ 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, + struct ifnet *destifp) { register struct ip *oip = mtod(n, struct ip *), *nip; register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; @@ -192,6 +207,12 @@ icmp_error(n, type, code, dest, destifp) m = m_gethdr(M_DONTWAIT, MT_HEADER); 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; + } + icmplen = min(oiplen + 8, oip->ip_len); if (icmplen < sizeof(struct ip)) { printf("icmp_error: bad length\n"); @@ -272,8 +293,9 @@ icmp_input(m, hlen) int icmplen = ip->ip_len; register int i; struct in_ifaddr *ia; - void (*ctlfunc) __P((int, struct sockaddr *, void *)); + void (*ctlfunc)(int, struct sockaddr *, void *); int code; + char ipv4str[MAX_IPv4_STR_LEN]; /* * Locate icmp structure in mbuf, and check @@ -281,10 +303,12 @@ 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]; + 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) { @@ -420,7 +444,7 @@ icmp_input(m, hlen) * 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 (arbitrarily set at 296), then + * 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. @@ -439,9 +463,11 @@ icmp_input(m, hlen) 1); #if DEBUG_MTUDISC printf("MTU for %s reduced to %d\n", - inet_ntoa(icmpsrc.sin_addr), mtu); + inet_ntop(AF_INET, &icmpsrc.sin_addr, ipv4str, + sizeof(ipv4str)), + mtu); #endif - if (mtu < 296) { + 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; @@ -483,6 +509,10 @@ icmp_input(m, hlen) goto reflect; case ICMP_TSTAMP: + + if (icmptimestamp == 0) + break; + if (!icmpbmcastecho && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { icmpstat.icps_bmcasttstamp++; @@ -526,8 +556,11 @@ icmp_input(m, hlen) (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); if (ia == 0) break; - if (ia->ia_ifp == 0) + if (ia->ia_ifp == 0) { + ifafree(&ia->ia_ifa); + ia = 0; break; + } icp->icmp_type = ICMP_MASKREPLY; icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; if (ip->ip_src.s_addr == 0) { @@ -536,6 +569,7 @@ 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); reflect: ip->ip_len += hlen; /* since ip_input deducts this */ icmpstat.icps_reflect++; @@ -579,11 +613,12 @@ 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; @@ -646,6 +681,7 @@ icmp_reflect(m) * or anonymous), use the address which corresponds * to the incoming interface. */ + lck_mtx_lock(rt_mtx); 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; @@ -653,6 +689,8 @@ icmp_reflect(m) t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) break; } + if (ia) + ifaref(&ia->ia_ifa); icmpdst.sin_addr = t; if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif) ia = (struct in_ifaddr *)ifaof_ifpforaddr( @@ -661,11 +699,21 @@ 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) { ia = in_ifaddrhead.tqh_first; + if (ia == (struct in_ifaddr *)0) {/* no address yet, bail out */ + m_freem(m); + lck_mtx_unlock(rt_mtx); + goto done; + } + ifaref(&ia->ia_ifa); + } + lck_mtx_unlock(rt_mtx); t = IA_SIN(ia)->sin_addr; ip->ip_src = t; ip->ip_ttl = ip_defttl; + ifafree(&ia->ia_ifa); + ia = NULL; if (optlen > 0) { register u_char *cp; @@ -759,6 +807,7 @@ icmp_send(m, opts) register int hlen; register struct icmp *icp; struct route ro; + char ipv4str[MAX_IPv4_STR_LEN]; hlen = IP_VHL_HL(ip->ip_vhl) << 2; m->m_data += hlen; @@ -768,16 +817,17 @@ 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.rcvif = 0; m->m_pkthdr.aux = 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]; + 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); @@ -882,7 +932,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 ; @@ -948,7 +998,7 @@ __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 */ @@ -1011,6 +1061,7 @@ icmp_dgram_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FAITH: #endif case IP_STRIPHDR: + case IP_RECVTTL: error = rip_ctloutput(so, sopt); break; @@ -1047,8 +1098,7 @@ 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) @@ -1058,12 +1108,22 @@ icmp_dgram_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *n 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_mtx_lock(rt_mtx); + if (TAILQ_EMPTY(&in_ifaddrhead)) { + lck_mtx_unlock(rt_mtx); + 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) + if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_src.s_addr) { + lck_mtx_unlock(rt_mtx); + socket_lock(so, 0); goto ours; + } } + lck_mtx_unlock(rt_mtx); + socket_lock(so, 0); goto bad; } ours: