/*
- * 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/if.h>
#include <net/route.h>
+#include <net/content_filter.h>
#define _IP_VHL
#include <netinet/in.h>
#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
/* 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 */
/*
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;
struct in_ifaddr *ia;
void (*ctlfunc)(int, struct sockaddr *, void *, struct ifnet *);
int code;
+ boolean_t should_log_redirect = false;
/* Expect 32-bit aligned data pointer on strict-align platforms */
MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
*/
if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)
|| IP_VHL_HL(icp->icmp_ip.ip_vhl) <
- (sizeof(struct ip) >> 2)) {
+ (sizeof(struct ip) >> 2) ||
+ (m = m_pullup(m, hlen + ICMP_ADVLEN(icp))) == NULL) {
icmpstat.icps_badlen++;
goto freeit;
}
+ ip = mtod(m, struct ip *);
+ icp = (struct icmp *)(void *)(mtod(m, uint8_t *) + hlen);
+
#if BYTE_ORDER != BIG_ENDIAN
NTOHS(icp->icmp_ip.ip_len);
#endif
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
return;
case ICMP_REDIRECT:
- if (log_redirect) {
- u_int32_t src, dst, gw;
-
- src = ntohl(ip->ip_src.s_addr);
- dst = ntohl(icp->icmp_ip.ip_dst.s_addr);
- gw = ntohl(icp->icmp_gwaddr.s_addr);
- printf("icmp redirect from %d.%d.%d.%d: "
- "%d.%d.%d.%d => %d.%d.%d.%d\n",
- (int)(src >> 24), (int)((src >> 16) & 0xff),
- (int)((src >> 8) & 0xff), (int)(src & 0xff),
- (int)(dst >> 24), (int)((dst >> 16) & 0xff),
- (int)((dst >> 8) & 0xff), (int)(dst & 0xff),
- (int)(gw >> 24), (int)((gw >> 16) & 0xff),
- (int)((gw >> 8) & 0xff), (int)(gw & 0xff));
- }
if (drop_redirect) {
break;
}
icmpstat.icps_badlen++;
break;
}
+
+#if (DEBUG | DEVELOPMENT)
+ should_log_redirect = log_redirect || (icmpprintfs > 0);
+#else
+ should_log_redirect = log_redirect;
+#endif
/*
* Short circuit routing redirects to force
* immediate change in the kernel's routing
*/
icmpgw.sin_addr = ip->ip_src;
icmpdst.sin_addr = icp->icmp_gwaddr;
-#if (DEBUG | DEVELOPMENT)
- if (icmpprintfs > 0) {
+
+ if (should_log_redirect) {
+ char src_str[MAX_IPv4_STR_LEN];
char dst_str[MAX_IPv4_STR_LEN];
char gw_str[MAX_IPv4_STR_LEN];
+ inet_ntop(AF_INET, &ip->ip_src, src_str, sizeof(src_str));
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);
+ printf("%s: redirect dst %s to %s from %s\n", __func__,
+ dst_str, gw_str, src_str);
}
-#endif
icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
rtredirect(m->m_pkthdr.rcvif, (struct sockaddr *)&icmpsrc,
(struct sockaddr *)&icmpdst, NULL, RTF_GATEWAY | RTF_HOST,
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;
* 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;
const char *bandlimittype[] = {
"Limiting icmp unreach 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;
}
+ time = net_uptime();
secs = time - lticks[which];
/*
*/
if (++lpackets[which] > icmplim) {
- return -1;
+ 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;
struct in_ifaddr *ia = NULL;
int icmplen;
int error = EINVAL;
+ int inp_flags = inp ? inp->inp_flags : 0;
if (inp == NULL
#if NECP
goto bad;
}
- if ((inp->inp_flags & INP_HDRINCL) != 0) {
+#if CONTENT_FILTER
+ /*
+ * If socket is subject to Content Filter, get inp_flags from saved state
+ */
+ if (so->so_cfil_db && nam == NULL) {
+ cfil_dgram_peek_socket_state(m, &inp_flags);
+ }
+#endif
+
+ if ((inp_flags & INP_HDRINCL) != 0) {
/* Expect 32-bit aligned data ptr on strict-align platforms */
MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
/*