/*
- * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*/
struct icmpstat icmpstat;
-SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD | CTLFLAG_LOCKED,
- &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 | CTLFLAG_LOCKED,
- &icmpmaskrepl, 0, "");
+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 | CTLFLAG_LOCKED,
- &icmptimestamp, 0, "");
+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 | CTLFLAG_LOCKED,
- &drop_redirect, 0, "");
+static int drop_redirect = 1;
+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 | CTLFLAG_LOCKED,
- &log_redirect, 0, "");
+SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect,
+ CTLFLAG_RW | CTLFLAG_LOCKED,
+ &log_redirect, 0, "");
+
+const static int icmp_datalen = 8;
#if ICMP_BANDLIM
SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW | CTLFLAG_LOCKED,
&icmpbmcastecho, 0, "");
-
-#if ICMPPRINTFS
-int icmpprintfs = 0;
+#if (DEBUG | DEVELOPMENT)
+static int icmpprintfs = 0;
+SYSCTL_INT(_net_inet_icmp, OID_AUTO, verbose, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &icmpprintfs, 0, "");
#endif
static void icmp_reflect(struct mbuf *);
struct mbuf *n,
int type,
int code,
- n_long dest,
+ u_int32_t dest,
u_int32_t nextmtu)
{
- struct ip *oip = mtod(n, struct ip *), *nip;
- unsigned oiplen;
+ struct ip *oip, *nip;
struct icmp *icp;
struct mbuf *m;
- unsigned icmplen;
+ u_int32_t oiphlen, icmplen, icmpelen, nlen;
/* Expect 32-bit aligned data pointer on strict-align platforms */
MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(n);
- oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
+ oip = mtod(n, struct ip *);
+ oiphlen = IP_VHL_HL(oip->ip_vhl) << 2;
-#if ICMPPRINTFS
- if (icmpprintfs)
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 1)
printf("icmp_error(0x%llx, %x, %d)\n",
(uint64_t)VM_KERNEL_ADDRPERM(oip), type, code);
#endif
* Don't error if the old packet protocol was ICMP
* error message, only known informational types.
*/
- if (oip->ip_off &~ (IP_MF|IP_DF))
+ if (oip->ip_off & ~(IP_MF|IP_DF))
goto freeit;
+
if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
- n->m_len >= oiplen + ICMP_MINLEN &&
- !ICMP_INFOTYPE(((struct icmp *)(void *)((caddr_t)oip + oiplen))->
+ n->m_len >= oiphlen + ICMP_MINLEN &&
+ !ICMP_INFOTYPE(((struct icmp *)(void *)((caddr_t)oip + oiphlen))->
icmp_type)) {
icmpstat.icps_oldicmp++;
goto freeit;
}
- /* Don't send error in response to a multicast or broadcast packet */
+ /*
+ * Don't send error in response to a multicast or
+ * broadcast packet
+ */
if (n->m_flags & (M_BCAST|M_MCAST))
goto freeit;
+
+ /*
+ * Calculate the length to quote from original packet and prevent
+ * the ICMP mbuf from overflowing.
+ */
+ nlen = m_length(n);
+ if (oip->ip_p == IPPROTO_TCP) {
+ struct tcphdr *th;
+ u_int16_t tcphlen;
+
+ if (oiphlen + sizeof(struct tcphdr) > n->m_len &&
+ n->m_next == NULL)
+ goto stdreply;
+ if (n->m_len < (oiphlen + sizeof(struct tcphdr)) &&
+ (n = m_pullup(n, (oiphlen + sizeof(struct tcphdr)))) == NULL)
+ goto freeit;
+
+ th = (struct tcphdr *)(void *)((caddr_t)oip + oiphlen);
+ if (th != ((struct tcphdr *)P2ROUNDDOWN(th,
+ sizeof(u_int32_t))))
+ goto freeit;
+ tcphlen = th->th_off << 2;
+ if (tcphlen < sizeof(struct tcphdr))
+ goto freeit;
+ if (oip->ip_len < (oiphlen + tcphlen))
+ goto freeit;
+ if ((oiphlen + tcphlen) > n->m_len && n->m_next == NULL)
+ goto stdreply;
+ if (n->m_len < (oiphlen + tcphlen) &&
+ (n = m_pullup(n, (oiphlen + tcphlen))) == NULL)
+ goto freeit;
+
+ icmpelen = max(tcphlen, min(icmp_datalen,
+ (oip->ip_len - oiphlen)));
+ } else
+stdreply: icmpelen = max(ICMP_MINLEN, min(icmp_datalen,
+ (oip->ip_len - oiphlen)));
+
+ icmplen = min(oiphlen + icmpelen, min(nlen, oip->ip_len));
+ if (icmplen < sizeof(struct ip))
+ goto freeit;
/*
* First, formulate icmp message
*/
- m = m_gethdr(M_DONTWAIT, MT_HEADER); /* MAC-OK */
+ if (MHLEN > (sizeof(struct ip) + ICMP_MINLEN + icmplen))
+ m = m_gethdr(M_DONTWAIT, MT_HEADER); /* MAC-OK */
+ else
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+
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 */
+ 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");
- m_free(m);
- goto freeit;
- }
- m->m_len = icmplen + ICMP_MINLEN;
+ m->m_len = icmplen + ICMP_MINLEN; /* for ICMP header and data */
MH_ALIGN(m, m->m_len);
icp = mtod(m, struct icmp *);
- if ((u_int)type > ICMP_MAXTYPE)
- panic("icmp_error");
+ if ((u_int)type > ICMP_MAXTYPE) {
+ m_freem(m);
+ goto freeit;
+ }
icmpstat.icps_outhist[type]++;
icp->icmp_type = type;
if (type == ICMP_REDIRECT)
* Now, copy old ip header (without options)
* in front of icmp message.
*/
- if (m->m_data - sizeof(struct ip) < m->m_pktdat)
- panic("icmp len");
+ if (m->m_data - sizeof(struct ip) < m->m_pktdat) {
+ m_freem(m);
+ goto freeit;
+ }
m->m_data -= sizeof(struct ip);
m->m_len += sizeof(struct ip);
m->m_pkthdr.len = m->m_len;
nip->ip_vhl = IP_VHL_BORING;
nip->ip_p = IPPROTO_ICMP;
nip->ip_tos = 0;
+ nip->ip_off = 0;
icmp_reflect(m);
freeit:
* Locate icmp structure in mbuf, and check
* that not corrupted and of at least minimum length.
*/
-#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)),
- inet_ntop(AF_INET, &ip->ip_dst, ipv4str, sizeof(ipv4str)),
- icmplen);
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 2) {
+ char src_str[MAX_IPv4_STR_LEN];
+ char dst_str[MAX_IPv4_STR_LEN];
+
+ inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str));
+ inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str));
+ printf("%s: from %s to %s, len %d\n",
+ __func__, src_str, dst_str, icmplen);
}
#endif
if (icmplen < ICMP_MINLEN) {
m->m_len += hlen;
m->m_data -= hlen;
-#if ICMPPRINTFS
- if (icmpprintfs)
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 2)
printf("icmp_input, type %d code %d\n", icp->icmp_type,
icp->icmp_code);
#endif
/*
* Problem with datagram; advise higher level routines.
*/
- if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
- IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
+ if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)
+ || IP_VHL_HL(icp->icmp_ip.ip_vhl) <
+ (sizeof(struct ip) >> 2)) {
icmpstat.icps_badlen++;
goto freeit;
}
/* Discard ICMP's in response to multicast packets */
if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
goto badcode;
-#if ICMPPRINTFS
- if (icmpprintfs)
- printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 2)
+ printf("deliver to protocol %d\n",
+ icp->icmp_ip.ip_p);
#endif
icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
/*
- * XXX if the packet contains [IPv4 AH TCP], we can't make a
+ * if the packet contains [IPv4 AH TCP], we can't make a
* notification to TCP layer.
*/
ctlfunc = ip_protox[icp->icmp_ip.ip_p]->pr_ctlinput;
break;
case ICMP_ECHO:
- if (!icmpbmcastecho
- && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
+ if ((m->m_flags & (M_MCAST | M_BCAST))) {
+ if (icmpbmcastecho == 0) {
+ icmpstat.icps_bmcastecho++;
+ break;
+ }
+ }
+
+ /*
+ * rdar://18644769
+ * Do not reply when the destination is link local multicast or broadcast
+ * and the source is not from a directly connected subnet
+ */
+ if ((IN_LOCAL_GROUP(ntohl(ip->ip_dst.s_addr)) ||
+ in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) &&
+ in_localaddr(ip->ip_src) == 0) {
icmpstat.icps_bmcastecho++;
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 0) {
+ char src_str[MAX_IPv4_STR_LEN];
+ char dst_str[MAX_IPv4_STR_LEN];
+
+ inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str));
+ inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str));
+ printf("%s: non local (B|M)CAST %s to %s, len %d\n",
+ __func__, src_str, dst_str, icmplen);
+ }
+#endif
break;
}
+
icp->icmp_type = ICMP_ECHOREPLY;
#if ICMP_BANDLIM
if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0)
goto reflect;
case ICMP_TSTAMP:
-
if (icmptimestamp == 0)
break;
*/
icmpgw.sin_addr = ip->ip_src;
icmpdst.sin_addr = icp->icmp_gwaddr;
-#if ICMPPRINTFS
- if (icmpprintfs) {
- char buf[MAX_IPv4_STR_LEN];
-
- printf("redirect dst %s to %s\n",
- inet_ntop(AF_INET, &icp->icmp_ip.ip_dst, buf, sizeof(buf)),
- inet_ntop(AF_INET, &icp->icmp_gwaddr, ipv4str,
- sizeof(ipv4str)));
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 0) {
+ char dst_str[MAX_IPv4_STR_LEN];
+ char gw_str[MAX_IPv4_STR_LEN];
+
+ inet_ntop(AF_INET, &icp->icmp_ip.ip_dst, dst_str, sizeof(dst_str));
+ inet_ntop(AF_INET, &icp->icmp_gwaddr, gw_str, sizeof(gw_str));
+ printf("%s: redirect dst %s to %s\n", __func__, dst_str, gw_str);
}
#endif
icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
mtod(opts, struct in_addr *)->s_addr = 0;
}
if (opts) {
-#if ICMPPRINTFS
- if (icmpprintfs)
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 1)
printf("icmp_reflect optlen %d rt %d => ",
optlen, opts->m_len);
#endif
opts->m_len++;
}
}
-#if ICMPPRINTFS
- if (icmpprintfs)
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 1)
printf("%d\n", opts->m_len);
#endif
}
struct icmp *icp;
struct route ro;
struct ip_out_args ipoa = { IFSCOPE_NONE, { 0 },
- IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR, 0 };
+ IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR, 0,
+ SO_TC_UNSPEC, _NET_SERVICE_TYPE_UNSPEC };
if (!(m->m_pkthdr.pkt_flags & PKTF_LOOP) && m->m_pkthdr.rcvif != NULL) {
ipoa.ipoa_boundif = m->m_pkthdr.rcvif->if_index;
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)),
- inet_ntop(AF_INET, &ip->ip_src, ipv4str, sizeof(ipv4str)));
+#if (DEBUG | DEVELOPMENT)
+ if (icmpprintfs > 2) {
+ char src_str[MAX_IPv4_STR_LEN];
+ char dst_str[MAX_IPv4_STR_LEN];
+
+ inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str));
+ inet_ntop(AF_INET, &ip->ip_dst, dst_str, sizeof(dst_str));
+ printf("%s: dst %s src %s\n", __func__, dst_str, src_str);
}
#endif
bzero(&ro, sizeof ro);
ROUTE_RELEASE(&ro);
}
-n_time
+u_int32_t
iptime(void)
{
struct timeval atv;
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;