aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2021-11-11 23:48:06 +0000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2021-11-11 23:48:06 +0000
commit8b6ebdfd536d7bfdc4832e1bd686274b23e9ccee (patch)
treea012dc819ef67266dbdef82bf92bc317e8920ec6
parent99bc3fc61e58fa29eac5577aa4dcaf1ede732d4a (diff)
parent242de58ec73f77b6b7dada205d31b0828140b589 (diff)
downloadslirp-8b6ebdfd536d7bfdc4832e1bd686274b23e9ccee.zip
slirp-8b6ebdfd536d7bfdc4832e1bd686274b23e9ccee.tar.gz
slirp-8b6ebdfd536d7bfdc4832e1bd686274b23e9ccee.tar.bz2
Merge branch 'icmp_raw' into 'master'
icmp: Support falling back on trying a SOCK_RAW socket See merge request slirp/libslirp!92
-rw-r--r--src/ip_icmp.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/src/ip_icmp.c b/src/ip_icmp.c
index 9fba653..4607721 100644
--- a/src/ip_icmp.c
+++ b/src/ip_icmp.c
@@ -91,8 +91,32 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
struct ip *ip = mtod(m, struct ip *);
struct sockaddr_in addr;
+ /*
+ * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
+ * between host OSes. On Linux, only the ICMP header and payload is
+ * included. On macOS/Darwin, the socket acts like a raw socket and
+ * includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
+ * sockets aren't supported at all, so we treat them like raw sockets. It
+ * isn't possible to detect this difference at runtime, so we must use an
+ * #ifdef to determine if we need to remove the IP header.
+ */
+#ifdef CONFIG_BSD
+ so->so_type = IPPROTO_IP;
+#else
+ so->so_type = IPPROTO_ICMP;
+#endif
+
so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (so->s == -1) {
+ if (errno == EAFNOSUPPORT
+ || errno == EPROTONOSUPPORT
+ || errno == EACCES) {
+ /* Kernel doesn't support or allow ping sockets. */
+ so->so_type = IPPROTO_IP;
+ so->s = slirp_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ }
+ }
+ if (so->s == -1) {
return -1;
}
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
@@ -108,7 +132,6 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
so->so_faddr = ip->ip_dst;
so->so_laddr = ip->ip_src;
so->so_iptos = ip->ip_tos;
- so->so_type = IPPROTO_ICMP;
so->so_state = SS_ISFCONNECTED;
so->so_expire = curtime + SO_EXPIRE;
@@ -478,31 +501,24 @@ void icmp_receive(struct socket *so)
id = icp->icmp_id;
len = recv(so->s, icp, M_ROOM(m), 0);
- /*
- * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
- * between host OSes. On Linux, only the ICMP header and payload is
- * included. On macOS/Darwin, the socket acts like a raw socket and
- * includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP
- * sockets aren't supported at all, so we treat them like raw sockets. It
- * isn't possible to detect this difference at runtime, so we must use an
- * #ifdef to determine if we need to remove the IP header.
- */
-#ifdef CONFIG_BSD
- if (len >= sizeof(struct ip)) {
- struct ip *inner_ip = mtod(m, struct ip *);
- int inner_hlen = inner_ip->ip_hl << 2;
- if (inner_hlen > len) {
+
+ if (so->so_type == IPPROTO_IP) {
+ if (len >= sizeof(struct ip)) {
+ struct ip *inner_ip = mtod(m, struct ip *);
+ int inner_hlen = inner_ip->ip_hl << 2;
+ if (inner_hlen > len) {
+ len = -1;
+ errno = -EINVAL;
+ } else {
+ len -= inner_hlen;
+ memmove(icp, (unsigned char *)icp + inner_hlen, len);
+ }
+ } else {
len = -1;
errno = -EINVAL;
- } else {
- len -= inner_hlen;
- memmove(icp, (unsigned char *)icp + inner_hlen, len);
}
- } else {
- len = -1;
- errno = -EINVAL;
}
-#endif
+
icp->icmp_id = id;
m->m_data -= hlen;