diff options
author | Weilun Du <wdu@google.com> | 2023-07-17 11:56:03 -0400 |
---|---|---|
committer | Weilun Du <wdu@google.com> | 2023-07-17 11:56:03 -0400 |
commit | 527c0ad35c887a5c514932eb265d92458e1a5433 (patch) | |
tree | 964cdee5044db593be784960ed848f624a2b12ce | |
parent | a13b9aad9362207a4a3e030603e51baaad5c52da (diff) | |
download | qemu-libslirp-aosp-emu-34-dev.tar.gz |
[libslirp] Back-port icmp ping supportnetsim-devemu-prebuiltsemu-devemu-34-devemu-34-3-releaseemu-33-devaosp-emu-34-dev
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.c | 28 | ||||
-rw-r--r-- | src/ip_icmp.h | 6 | ||||
-rw-r--r-- | src/ip_icmp_ping.c | 118 | ||||
-rw-r--r-- | src/socket.h | 6 |
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; |