*
* @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@
*/
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netinet/icmp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcpip.h>
#if IPSEC
#include <netinet6/ipsec.h>
#if defined(NFAITH) && NFAITH > 0
#include "faith.h"
#include <net/if_types.h>
+#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
/*
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, "");
* 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
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[];
* 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;
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");
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
*/
#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) {
* 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.
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;
goto reflect;
case ICMP_TSTAMP:
+
+ if (icmptimestamp == 0)
+ break;
+
if (!icmpbmcastecho
&& (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
icmpstat.icps_bmcasttstamp++;
(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) {
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++;
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;
* 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;
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(
* 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;
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;
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);
if (icmplim <= 0 || which > BANDLIM_MAX || which < 0)
return(0);
- getmicrotime(&time);
+ getmicrouptime(&time);
secs = time.tv_sec - lticks[which].tv_sec ;
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 */
case IP_FAITH:
#endif
case IP_STRIPHDR:
+ case IP_RECVTTL:
error = rip_ctloutput(so, sopt);
break;
/* 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)
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: