/*
- * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <net/necp.h>
#endif /* NECP */
-/* 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 <security/mac_framework.h>
-#endif /* MAC_NET */
-
/*
* ICMP routines: error generation, receive packet processing, and
const static int icmp_datalen = 8;
#if ICMP_BANDLIM
-
/* Default values in case CONFIG_ICMP_BANDLIM is not defined in the MASTER file */
#ifndef CONFIG_ICMP_BANDLIM
-#if !CONFIG_EMBEDDED
+#if XNU_TARGET_OS_OSX
#define CONFIG_ICMP_BANDLIM 250
-#else /* CONFIG_EMBEDDED */
+#else /* !XNU_TARGET_OS_OSX */
#define CONFIG_ICMP_BANDLIM 50
-#endif /* CONFIG_EMBEDDED */
+#endif /* !XNU_TARGET_OS_OSX */
#endif /* CONFIG_ICMP_BANDLIM */
/*
static int icmplim = CONFIG_ICMP_BANDLIM;
SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW | CTLFLAG_LOCKED,
&icmplim, 0, "");
-
#else /* ICMP_BANDLIM */
-
static int icmplim = -1;
SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD | CTLFLAG_LOCKED,
&icmplim, 0, "");
-
#endif /* ICMP_BANDLIM */
+static int icmplim_random_incr = CONFIG_ICMP_BANDLIM;
+SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM_INCR, icmplim_random_incr, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &icmplim_random_incr, 0, "");
+
/*
* ICMP broadcast echo sysctl
*/
u_int32_t nlen = 0;
VERIFY((u_int)type <= ICMP_MAXTYPE);
+ VERIFY(code <= UINT8_MAX);
+
/* Expect 32-bit aligned data pointer on strict-align platforms */
MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(n);
th = (struct tcphdr *)(void *)((caddr_t)oip + oiphlen);
if (th != ((struct tcphdr *)P2ROUNDDOWN(th,
- sizeof(u_int32_t)))) {
+ sizeof(u_int32_t))) ||
+ ((th->th_off << 2) > UINT16_MAX)) {
goto freeit;
}
- tcphlen = th->th_off << 2;
+ tcphlen = (uint16_t)(th->th_off << 2);
/* Sanity checks */
if (tcphlen < sizeof(struct tcphdr)) {
goto freeit;
}
-#if CONFIG_MACF_NET
- mac_mbuf_label_associate_netlayer(n, m);
-#endif
/*
* Further refine the payload length to the space
* remaining in mbuf after including the IP header and ICMP
* header.
*/
- icmplen = min(icmplen, M_TRAILINGSPACE(m) -
- sizeof(struct ip) - ICMP_MINLEN);
+ icmplen = min(icmplen, (u_int)M_TRAILINGSPACE(m) -
+ (u_int)(sizeof(struct ip) - ICMP_MINLEN));
m_align(m, ICMP_MINLEN + icmplen);
m->m_len = ICMP_MINLEN + icmplen; /* for ICMP header and data */
icp = mtod(m, struct icmp *);
icmpstat.icps_outhist[type]++;
- icp->icmp_type = type;
+ icp->icmp_type = (u_char)type;
if (type == ICMP_REDIRECT) {
icp->icmp_gwaddr.s_addr = dest;
} else {
* zeroed icmp_void field.
*/
if (type == ICMP_PARAMPROB) {
- icp->icmp_pptr = code;
+ icp->icmp_pptr = (u_char)code;
code = 0;
} else if (type == ICMP_UNREACH &&
code == ICMP_UNREACH_NEEDFRAG && nextmtu != 0) {
- icp->icmp_nextmtu = htons(nextmtu);
+ icp->icmp_nextmtu = htons((uint16_t)nextmtu);
}
}
- icp->icmp_code = code;
+ icp->icmp_code = (u_char)code;
/*
* Copy icmplen worth of content from original
/*
* Set up ICMP message mbuf and copy old IP header (without options
* in front of ICMP message.
- * If the original mbuf was meant to bypass the firewall, the error
- * reply should bypass as well.
*/
- m->m_flags |= n->m_flags & M_SKIP_FIREWALL;
m->m_data -= sizeof(struct ip);
m->m_len += sizeof(struct ip);
m->m_pkthdr.len = m->m_len;
m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
nip = mtod(m, struct ip *);
bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
- nip->ip_len = m->m_len;
+ nip->ip_len = (uint16_t)m->m_len;
nip->ip_vhl = IP_VHL_BORING;
nip->ip_p = IPPROTO_ICMP;
nip->ip_tos = 0;
icp->icmp_type = ICMP_ECHOREPLY;
#if ICMP_BANDLIM
- if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0) {
+ if (badport_bandlim(BANDLIM_ICMP_ECHO)) {
goto freeit;
} else
#endif
icp->icmp_rtime = iptime();
icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
#if ICMP_BANDLIM
- if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0) {
+ if (badport_bandlim(BANDLIM_ICMP_TSTAMP)) {
goto freeit;
} else
#endif
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;
+ ip->ip_ttl = (u_char)ip_defttl;
IFA_REMREF(&ia->ia_ifa);
ia = NULL;
/*
* badport_bandlim() - check for ICMP bandwidth limit
- *
- * Return 0 if it is ok to send an ICMP error response, -1 if we have
- * hit our bandwidth limit and it is not ok.
- *
- * If icmplim is <= 0, the feature is disabled and 0 is returned.
+ * Returns false when it is ok to send ICMP error and true to limit sending
+ * of ICMP error.
*
* For now we separate the TCP and UDP subsystems w/ different 'which'
* values. We may eventually remove this separation (and simplify the
* delay with more complex code.
*/
-int
+boolean_t
badport_bandlim(int which)
{
static uint64_t lticks[BANDLIM_MAX + 1];
static int lpackets[BANDLIM_MAX + 1];
- uint64_t time = net_uptime();
- int secs;
-
+ uint64_t time;
+ uint64_t secs;
+ static boolean_t is_initialized = FALSE;
+ static int icmplim_random;
const char *bandlimittype[] = {
"Limiting icmp unreach response",
"Limiting icmp ping response",
"Limiting open port RST response"
};
- /*
- * Return ok status if feature disabled or argument out of
- * ranage.
- */
+ /* Return ok status if feature disabled or argument out of range. */
if (icmplim <= 0 || which > BANDLIM_MAX || which < 0) {
- return 0;
+ return false;
}
+ if (is_initialized == FALSE) {
+ if (icmplim_random_incr > 0 &&
+ icmplim <= INT32_MAX - (icmplim_random_incr + 1)) {
+ icmplim_random = icmplim + (random() % icmplim_random_incr) + 1;
+ }
+ is_initialized = TRUE;
+ }
+
+ time = net_uptime();
secs = time - lticks[which];
/*
*/
if (secs > 1) {
- if (lpackets[which] > icmplim) {
+ if (lpackets[which] > icmplim_random) {
printf("%s from %d to %d packets per second\n",
bandlimittype[which],
lpackets[which],
- icmplim
+ icmplim_random
);
}
lticks[which] = time;
/*
* bump packet count
*/
-
- if (++lpackets[which] > icmplim) {
- return -1;
+ if (++lpackets[which] > icmplim_random) {
+ /*
+ * After hitting the randomized limit, we further randomize the
+ * behavior of how we apply rate limitation.
+ * We rate limit based on probability that increases with the
+ * increase in lpackets[which] count.
+ */
+ if ((random() % (lpackets[which] - icmplim_random)) != 0) {
+ return true;
+ }
}
- return 0;
+ return false;
}
#endif
inp = (struct inpcb *)so->so_pcb;
inp->inp_vflag |= INP_IPV4;
inp->inp_ip_p = IPPROTO_ICMP;
- inp->inp_ip_ttl = ip_defttl;
+ inp->inp_ip_ttl = (u_char)ip_defttl;
return 0;
}
case IP_STRIPHDR:
case IP_RECVTTL:
case IP_BOUND_IF:
+ case IP_DONTFRAG:
case IP_NO_IFT_CELLULAR:
error = rip_ctloutput(so, sopt);
break;