Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/misc.c
2 views
/* SPDX-License-Identifier: BSD-3-Clause */1/*2* Copyright (c) 1995 Danny Gasparovski.3*/45#include "slirp.h"6#ifdef G_OS_UNIX7#include <sys/un.h>8#endif910void slirp_insque(void *a, void *b)11{12register struct slirp_quehead *element = (struct slirp_quehead *)a;13register struct slirp_quehead *head = (struct slirp_quehead *)b;14element->qh_link = head->qh_link;15head->qh_link = (struct slirp_quehead *)element;16element->qh_rlink = (struct slirp_quehead *)head;17((struct slirp_quehead *)(element->qh_link))->qh_rlink =18(struct slirp_quehead *)element;19}2021void slirp_remque(void *a)22{23register struct slirp_quehead *element = (struct slirp_quehead *)a;24((struct slirp_quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;25((struct slirp_quehead *)(element->qh_rlink))->qh_link = element->qh_link;26element->qh_rlink = NULL;27}2829/* TODO: IPv6 */30struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,31void *opaque, struct in_addr addr, int port)32{33struct gfwd_list *f = g_new0(struct gfwd_list, 1);3435f->write_cb = write_cb;36f->opaque = opaque;37f->ex_fport = port;38f->ex_addr = addr;39f->ex_next = *ex_ptr;40*ex_ptr = f;4142return f;43}4445struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,46struct in_addr addr, int port)47{48struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);4950f->ex_exec = g_strdup(cmdline);5152return f;53}5455struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,56struct in_addr addr, int port)57{58struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);5960f->ex_unix = g_strdup(unixsock);6162return f;63}6465int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port)66{67for (; *ex_ptr != NULL; ex_ptr = &((*ex_ptr)->ex_next)) {68struct gfwd_list *f = *ex_ptr;69if (f->ex_addr.s_addr == addr.s_addr && f->ex_fport == port) {70*ex_ptr = f->ex_next;71g_free(f->ex_exec);72g_free(f);73return 0;74}75}76return -1;77}7879static int slirp_socketpair_with_oob(int sv[2])80{81struct sockaddr_in addr = {82.sin_family = AF_INET,83.sin_port = 0,84.sin_addr.s_addr = htonl(INADDR_LOOPBACK),85};86socklen_t addrlen = sizeof(addr);87int ret, s;8889sv[1] = -1;90s = slirp_socket(AF_INET, SOCK_STREAM, 0);91if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||92listen(s, 1) < 0 ||93getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {94goto err;95}9697sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);98if (sv[1] < 0) {99goto err;100}101/*102* This connect won't block because we've already listen()ed on103* the server end (even though we won't accept() the connection104* until later on).105*/106do {107ret = connect(sv[1], (struct sockaddr *)&addr, addrlen);108} while (ret < 0 && errno == EINTR);109if (ret < 0) {110goto err;111}112113do {114sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen);115} while (sv[0] < 0 && errno == EINTR);116if (sv[0] < 0) {117goto err;118}119120closesocket(s);121return 0;122123err:124g_critical("slirp_socketpair(): %s", strerror(errno));125if (s >= 0) {126closesocket(s);127}128if (sv[1] >= 0) {129closesocket(sv[1]);130}131return -1;132}133134static void fork_exec_child_setup(gpointer data)135{136#ifndef _WIN32137setsid();138139/* Unblock all signals and leave our exec()-ee to block what it wants */140sigset_t ss;141sigemptyset(&ss);142sigprocmask(SIG_SETMASK, &ss, NULL);143144/* POSIX is obnoxious about SIGCHLD specifically across exec() */145signal(SIGCHLD, SIG_DFL);146#endif147}148149#ifdef __GNUC__150#pragma GCC diagnostic push151#pragma GCC diagnostic ignored "-Wdeprecated-declarations"152#endif153154#if !GLIB_CHECK_VERSION(2, 58, 0)155typedef struct SlirpGSpawnFds {156GSpawnChildSetupFunc child_setup;157gpointer user_data;158gint stdin_fd;159gint stdout_fd;160gint stderr_fd;161} SlirpGSpawnFds;162163static inline void slirp_gspawn_fds_setup(gpointer user_data)164{165SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;166167dup2(q->stdin_fd, 0);168dup2(q->stdout_fd, 1);169dup2(q->stderr_fd, 2);170q->child_setup(q->user_data);171}172#endif173174static inline gboolean175g_spawn_async_with_fds_slirp(const gchar *working_directory, gchar **argv,176gchar **envp, GSpawnFlags flags,177GSpawnChildSetupFunc child_setup,178gpointer user_data, GPid *child_pid, gint stdin_fd,179gint stdout_fd, gint stderr_fd, GError **error)180{181#if GLIB_CHECK_VERSION(2, 58, 0)182return g_spawn_async_with_fds(working_directory, argv, envp, flags,183child_setup, user_data, child_pid, stdin_fd,184stdout_fd, stderr_fd, error);185#else186SlirpGSpawnFds setup = {187.child_setup = child_setup,188.user_data = user_data,189.stdin_fd = stdin_fd,190.stdout_fd = stdout_fd,191.stderr_fd = stderr_fd,192};193194return g_spawn_async(working_directory, argv, envp, flags,195slirp_gspawn_fds_setup, &setup, child_pid, error);196#endif197}198199#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \200g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)201202#ifdef __GNUC__203#pragma GCC diagnostic pop204#endif205206int fork_exec(struct socket *so, const char *ex)207{208GError *err = NULL;209gint argc = 0;210gchar **argv = NULL;211int opt, sp[2];212213DEBUG_CALL("fork_exec");214DEBUG_ARG("so = %p", so);215DEBUG_ARG("ex = %p", ex);216217if (slirp_socketpair_with_oob(sp) < 0) {218return 0;219}220221if (!g_shell_parse_argv(ex, &argc, &argv, &err)) {222g_critical("fork_exec invalid command: %s\nerror: %s", ex, err->message);223g_error_free(err);224return 0;225}226227g_spawn_async_with_fds(NULL /* cwd */, argv, NULL /* env */,228G_SPAWN_SEARCH_PATH, fork_exec_child_setup,229NULL /* data */, NULL /* child_pid */, sp[1], sp[1],230sp[1], &err);231g_strfreev(argv);232233if (err) {234g_critical("fork_exec: %s", err->message);235g_error_free(err);236closesocket(sp[0]);237closesocket(sp[1]);238return 0;239}240241so->s = sp[0];242closesocket(sp[1]);243slirp_socket_set_fast_reuse(so->s);244opt = 1;245setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));246slirp_set_nonblock(so->s);247so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);248return 1;249}250251int open_unix(struct socket *so, const char *unixpath)252{253#ifdef G_OS_UNIX254struct sockaddr_un sa;255int s;256257DEBUG_CALL("open_unix");258DEBUG_ARG("so = %p", so);259DEBUG_ARG("unixpath = %s", unixpath);260261memset(&sa, 0, sizeof(sa));262sa.sun_family = AF_UNIX;263if (g_strlcpy(sa.sun_path, unixpath, sizeof(sa.sun_path)) >= sizeof(sa.sun_path)) {264g_critical("Bad unix path: %s", unixpath);265return 0;266}267268s = slirp_socket(PF_UNIX, SOCK_STREAM, 0);269if (s < 0) {270g_critical("open_unix(): %s", strerror(errno));271return 0;272}273274if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {275g_critical("open_unix(): %s", strerror(errno));276closesocket(s);277return 0;278}279280so->s = s;281slirp_set_nonblock(so->s);282so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);283284return 1;285#else286g_assert_not_reached();287#endif288}289290char *slirp_connection_info(Slirp *slirp)291{292GString *str = g_string_new(NULL);293const char *const tcpstates[] = {294[TCPS_CLOSED] = "CLOSED", [TCPS_LISTEN] = "LISTEN",295[TCPS_SYN_SENT] = "SYN_SENT", [TCPS_SYN_RECEIVED] = "SYN_RCVD",296[TCPS_ESTABLISHED] = "ESTABLISHED", [TCPS_CLOSE_WAIT] = "CLOSE_WAIT",297[TCPS_FIN_WAIT_1] = "FIN_WAIT_1", [TCPS_CLOSING] = "CLOSING",298[TCPS_LAST_ACK] = "LAST_ACK", [TCPS_FIN_WAIT_2] = "FIN_WAIT_2",299[TCPS_TIME_WAIT] = "TIME_WAIT",300};301struct in_addr dst_addr;302struct sockaddr_in src;303socklen_t src_len;304uint16_t dst_port;305struct socket *so;306const char *state;307char addr[INET_ADDRSTRLEN];308char buf[20];309310g_string_append_printf(str,311" Protocol[State] FD Source Address Port "312"Dest. Address Port RecvQ SendQ\n");313314/* TODO: IPv6 */315316for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {317if (so->so_state & SS_HOSTFWD) {318state = "HOST_FORWARD";319} else if (so->so_tcpcb) {320state = tcpstates[so->so_tcpcb->t_state];321} else {322state = "NONE";323}324if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {325src_len = sizeof(src);326getsockname(so->s, (struct sockaddr *)&src, &src_len);327dst_addr = so->so_laddr;328dst_port = so->so_lport;329} else {330src.sin_addr = so->so_laddr;331src.sin_port = so->so_lport;332dst_addr = so->so_faddr;333dst_port = so->so_fport;334}335slirp_fmt0(buf, sizeof(buf), " TCP[%s]", state);336g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,337src.sin_addr.s_addr ?338inet_ntop(AF_INET, &src.sin_addr, addr, sizeof(addr)) : "*",339ntohs(src.sin_port));340g_string_append_printf(str, "%15s %5d %5d %5d\n",341inet_ntop(AF_INET, &dst_addr, addr, sizeof(addr)),342ntohs(dst_port), so->so_rcv.sb_cc,343so->so_snd.sb_cc);344}345346for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {347if (so->so_state & SS_HOSTFWD) {348slirp_fmt0(buf, sizeof(buf), " UDP[HOST_FORWARD]");349src_len = sizeof(src);350getsockname(so->s, (struct sockaddr *)&src, &src_len);351dst_addr = so->so_laddr;352dst_port = so->so_lport;353} else {354slirp_fmt0(buf, sizeof(buf), " UDP[%d sec]",355(so->so_expire - curtime) / 1000);356src.sin_addr = so->so_laddr;357src.sin_port = so->so_lport;358dst_addr = so->so_faddr;359dst_port = so->so_fport;360}361g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,362src.sin_addr.s_addr ?363inet_ntop(AF_INET, &src.sin_addr, addr, sizeof(addr)) : "*",364ntohs(src.sin_port));365g_string_append_printf(str, "%15s %5d %5d %5d\n",366inet_ntop(AF_INET, &dst_addr, addr, sizeof(addr)),367ntohs(dst_port), so->so_rcv.sb_cc,368so->so_snd.sb_cc);369}370371for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {372slirp_fmt0(buf, sizeof(buf), " ICMP[%d sec]",373(so->so_expire - curtime) / 1000);374src.sin_addr = so->so_laddr;375dst_addr = so->so_faddr;376g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s,377src.sin_addr.s_addr ?378inet_ntop(AF_INET, &src.sin_addr, addr, sizeof(addr)) : "*");379g_string_append_printf(str, "%15s - %5d %5d\n",380inet_ntop(AF_INET, &dst_addr, addr, sizeof(addr)),381so->so_rcv.sb_cc, so->so_snd.sb_cc);382}383384return g_string_free(str, FALSE);385}386387char *slirp_neighbor_info(Slirp *slirp)388{389GString *str = g_string_new(NULL);390ArpTable *arp_table = &slirp->arp_table;391NdpTable *ndp_table = &slirp->ndp_table;392char ip_addr[INET6_ADDRSTRLEN];393char eth_addr[ETH_ADDRSTRLEN];394const char *ip;395396g_string_append_printf(str, " %5s %-17s %s\n",397"Table", "MacAddr", "IP Address");398399for (int i = 0; i < ARP_TABLE_SIZE; ++i) {400struct in_addr addr;401addr.s_addr = arp_table->table[i].ar_sip;402if (!addr.s_addr) {403continue;404}405ip = inet_ntop(AF_INET, &addr, ip_addr, sizeof(ip_addr));406g_assert(ip != NULL);407g_string_append_printf(str, " %5s %-17s %s\n", "ARP",408slirp_ether_ntoa(arp_table->table[i].ar_sha,409eth_addr, sizeof(eth_addr)),410ip);411}412413for (int i = 0; i < NDP_TABLE_SIZE; ++i) {414if (in6_zero(&ndp_table->table[i].ip_addr)) {415continue;416}417ip = inet_ntop(AF_INET6, &ndp_table->table[i].ip_addr, ip_addr,418sizeof(ip_addr));419g_assert(ip != NULL);420g_string_append_printf(str, " %5s %-17s %s\n", "NDP",421slirp_ether_ntoa(ndp_table->table[i].eth_addr,422eth_addr, sizeof(eth_addr)),423ip);424}425426return g_string_free(str, FALSE);427}428429int slirp_bind_outbound(struct socket *so, unsigned short af)430{431int ret = 0;432struct sockaddr *addr = NULL;433int addr_size = 0;434435if (af == AF_INET && so->slirp->outbound_addr != NULL) {436addr = (struct sockaddr *)so->slirp->outbound_addr;437addr_size = sizeof(struct sockaddr_in);438} else if (af == AF_INET6 && so->slirp->outbound_addr6 != NULL) {439addr = (struct sockaddr *)so->slirp->outbound_addr6;440addr_size = sizeof(struct sockaddr_in6);441}442443if (addr != NULL) {444ret = bind(so->s, addr, addr_size);445}446return ret;447}448449450