summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWeilun Du <wdu@google.com>2023-07-17 11:56:03 -0400
committerWeilun Du <wdu@google.com>2023-07-17 11:56:03 -0400
commit527c0ad35c887a5c514932eb265d92458e1a5433 (patch)
tree964cdee5044db593be784960ed848f624a2b12ce
parenta13b9aad9362207a4a3e030603e51baaad5c52da (diff)
downloadqemu-libslirp-aosp-emu-34-dev.tar.gz
Adapted from CL https://android-review.git.corp.google.com/c/platform/external/qemu/+/408506 BUG: 288280272 Change-Id: I6fc1f2a772ae3cd9aaf43a7dd43a8a58a40bd4c8 Signed-off-by: Weilun Du <wdu@google.com>
-rw-r--r--src/ip_icmp.c28
-rw-r--r--src/ip_icmp.h6
-rw-r--r--src/ip_icmp_ping.c118
-rw-r--r--src/socket.h6
4 files changed, 156 insertions, 2 deletions
diff --git a/src/ip_icmp.c b/src/ip_icmp.c
index 6ae523c..8f3404f 100644
--- a/src/ip_icmp.c
+++ b/src/ip_icmp.c
@@ -117,7 +117,13 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
}
}
if (so->s == -1) {
+#ifndef WIN32
+ int res = ping_binary_send(so, m, hlen);
+ if (res != 0)
+ return -1;
+#else
return -1;
+#endif
}
so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
@@ -140,6 +146,11 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
slirp_insque(so, &so->slirp->icmp);
+#ifndef _WIN32
+ if (so->ping_pipe != NULL)
+ return 0;
+#endif
+
if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s", errno,
@@ -154,7 +165,14 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
void icmp_detach(struct socket *so)
{
so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+#ifndef WIN32
+ if (so->ping_pipe != NULL)
+ ping_binary_close(so);
+ else
+ closesocket(so->s);
+#else
closesocket(so->s);
+#endif
sofree(so);
}
@@ -494,14 +512,22 @@ void icmp_receive(struct socket *so)
int hlen = ip->ip_hl << 2;
uint8_t error_code;
struct icmp *icp;
- int id, len;
+ int id, len = -1;
m->m_data += hlen;
m->m_len -= hlen;
icp = mtod(m, struct icmp *);
id = icp->icmp_id;
+
+#ifndef WIN32
+ if (so->ping_pipe != NULL)
+ len = ping_binary_recv(so, ip, icp);
+ else
+ len = recv(so->s, icp, M_ROOM(m), 0);
+#else
len = recv(so->s, icp, M_ROOM(m), 0);
+#endif
if (so->so_type == IPPROTO_IP) {
if (len >= sizeof(struct ip)) {
diff --git a/src/ip_icmp.h b/src/ip_icmp.h
index 569a083..cb3d97c 100644
--- a/src/ip_icmp.h
+++ b/src/ip_icmp.h
@@ -165,4 +165,10 @@ void icmp_reflect(struct mbuf *);
void icmp_receive(struct socket *so);
void icmp_detach(struct socket *so);
+#ifndef WIN32
+int ping_binary_send(struct socket *so, struct mbuf *m, int hlen);
+int ping_binary_recv(struct socket *so, struct ip *ip, struct icmp *icp);
+void ping_binary_close(struct socket *so);
+#endif
+
#endif
diff --git a/src/ip_icmp_ping.c b/src/ip_icmp_ping.c
new file mode 100644
index 0000000..a666248
--- /dev/null
+++ b/src/ip_icmp_ping.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017
+ * Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Support ping using the system ping binary on Linux and Mac
+ * On Linux/Mac, icmp protocol requires the process to have system permission.
+ * Our emulator, by default, does not have system permission, so we have to
+ * resort to the built-in ping binary to handle icmp messages.
+ */
+
+#include "slirp.h"
+#include "ip_icmp.h"
+
+#include <fcntl.h>
+
+int ping_binary_send(struct socket* so, struct mbuf* m, int hlen) {
+ struct ip* ip = mtod(m, struct ip*);
+ const char* dest_ip_addr = inet_ntoa(ip->ip_dst);
+ char ping_cmd[1024];
+ sprintf(ping_cmd, "ping -c 1 -t %d %s 2>&1", ip->ip_ttl, dest_ip_addr);
+ FILE* p = popen(ping_cmd, "r");
+ if (!p) {
+ DEBUG_ERROR("popen failed for ping binary");
+ return -1;
+ }
+
+ so->ping_pipe = p;
+
+ // this is rather critical, otherwise emulator blocks when pinging
+ // an unreachable host
+ so->s = fileno(p);
+ fcntl(so->s, F_SETFL, O_NONBLOCK);
+
+ return 0;
+}
+
+/*
+ping -c 1 www.google.com
+PING www.google.com (172.217.6.36) 56(84) bytes of data.
+64 bytes from sfo03s08-in-f36.1e100.net (172.217.6.36): icmp_seq=1 ttl=57
+time=1.31 ms
+
+--- www.google.com ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+rtt min/avg/max/mdev = 1.316/1.316/1.316/0.000 ms
+*/
+int ping_binary_recv(struct socket* so, struct ip* ip, struct icmp* icp) {
+ if (so == NULL || so->ping_pipe == NULL) {
+ return -1;
+ }
+
+ int seq = -1, ttl = -1;
+ char line[4096] = "";
+ char skip[4096] = "";
+ char skip2[4096] = "";
+ while (fgets(line, sizeof(line), so->ping_pipe)) {
+ char* p = strstr(line, "icmp_seq=");
+ if (p != NULL) {
+ p += strlen("icmp_seq=");
+ seq = atoi(p);
+ }
+ p = strstr(line, "ttl=");
+ if (p != NULL) {
+ p += strlen("ttl=");
+ ttl = atoi(p);
+ }
+
+ if (seq != -1 && ttl != -1) {
+ break;
+ }
+ }
+
+ if (seq != -1 && ttl != -1) {
+ ip->ip_ttl = ttl;
+ ip->ip_p = IPPROTO_ICMP;
+ icp->icmp_type = ICMP_ECHOREPLY;
+ icp->icmp_code = 0;
+ icp->icmp_cksum = 0;
+ // icp->icmp_seq = seq;
+ return sizeof(*icp);
+ }
+
+ return -1;
+}
+
+void ping_binary_close(struct socket* so) {
+ if (so != NULL && so->ping_pipe) {
+ pclose(so->ping_pipe);
+ so->ping_pipe = NULL;
+ }
+}
diff --git a/src/socket.h b/src/socket.h
index ca8c103..07ced57 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -39,7 +39,11 @@ union slirp_sockaddr {
struct socket {
struct socket *so_next, *so_prev; /* For a linked list of sockets */
- int s; /* The actual socket */
+ int s; /* The actual socket or file descriptor of ping_pipe below */
+
+#ifndef WIN32
+ FILE *ping_pipe; /* the popen() stream for ping binary */
+#endif
int s_aux; /* An auxiliary socket for miscellaneous use. Currently used to
* reserve OS ports in UNIX-to-inet translation. */
struct gfwd_list *guestfwd;