From 187eb9ae419dd9a6a79adabd655d1e39adc6e8df Mon Sep 17 00:00:00 2001 From: Fabrizio Bertocci Date: Sat, 10 Apr 2021 11:40:23 -0400 Subject: [PATCH] Initial implementation of ioctl SIOCGIFCONF. Untested for most of the platforms yet. --- libc/calls/ioctl-siocgifconf-nt.c | 61 +++++++++++++++++++++++++++++++ libc/calls/ioctl-siocgifconf.c | 51 ++++++++++++++++++++++++++ libc/calls/ioctl.h | 3 ++ libc/nt/winsock.h | 8 ++++ libc/sock/sock.h | 54 +++++++++++++++++++++++++++ 5 files changed, 177 insertions(+) create mode 100644 libc/calls/ioctl-siocgifconf-nt.c create mode 100644 libc/calls/ioctl-siocgifconf.c diff --git a/libc/calls/ioctl-siocgifconf-nt.c b/libc/calls/ioctl-siocgifconf-nt.c new file mode 100644 index 000000000..ba021c14b --- /dev/null +++ b/libc/calls/ioctl-siocgifconf-nt.c @@ -0,0 +1,61 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/sysv/consts/o.h" +#include "libc/sock/sock.h" +#include "libc/sock/internal.h" +#include "libc/sysv/errfuns.h" +#include "libc/nt/winsock.h" + +// TODO: Remove me +#include "libc/stdio/stdio.h" + +#define MAX_INTERFACES 32 + +/* Reference: + * - Description of ioctls: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls + * - Structure INTERFACE_INFO: https://docs.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-interface_info + * - WSAIoctl man page: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaioctl + * - Using SIOCGIFCONF in Win32: https://docs.microsoft.com/en-us/windows/win32/winsock/using-unix-ioctls-in-winsock + */ + +textwindows int ioctl_siocgifconf_nt(int fd, struct ifconf *ifc) { + struct NtInterfaceInfo iflist[MAX_INTERFACES]; + uint32_t dwBytes; + int ret; + int i, count; + + if (g_fds.p[fd].kind != kFdSocket) { + return ebadf(); + } + + ret = WSAIoctl(g_fds.p[fd].handle, kNtSioGetInterfaceList, NULL, 0, &iflist, sizeof(iflist), &dwBytes, NULL, NULL); + if (ret == -1) { + return __winsockerr(); + } + + count = dwBytes / sizeof(struct NtInterfaceInfo); + printf("CI> SIO_GET_INTERFACE_LIST success:\n"); + for (i = 0; i < count; ++i) { + printf("CI>\t #i: %08x\n", i, iflist[i].iiAddress.sin_addr.s_addr); + } + return ret; +} + diff --git a/libc/calls/ioctl-siocgifconf.c b/libc/calls/ioctl-siocgifconf.c new file mode 100644 index 000000000..9896185c2 --- /dev/null +++ b/libc/calls/ioctl-siocgifconf.c @@ -0,0 +1,51 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/sock/sock.h" +#include "libc/sock/internal.h" +#include "libc/sysv/consts/sio.h" + +int ioctl_siocgifconf_nt(int, struct ifconf *) hidden; + +static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) { + /* Same as the default for now... */ + return sys_ioctl(fd, SIOCGIFCONF, ifc); + /* + int rc; + + if ((rc = sys_ioctl(fd, SIOCGIFCONF, &ifc)) != -1) { + return rc; + } + return rc; + */ +} + +/** + * Returns information about network interfaces. + * + * @see ioctl(fd, SIOCGIFCONF, tio) dispatches here + */ +int ioctl_siocgifconf(int fd, struct ifconf *ifc) { + if (!IsWindows()) { + return ioctl_siocgifconf_sysv(fd, ifc); + } else { + return ioctl_siocgifconf_nt(fd, ifc); + } +} + diff --git a/libc/calls/ioctl.h b/libc/calls/ioctl.h index 4fe29ccd0..9d9980a31 100644 --- a/libc/calls/ioctl.h +++ b/libc/calls/ioctl.h @@ -2,6 +2,7 @@ #define COSMOPOLITAN_LIBC_CALLS_IOCTL_H_ #include "libc/macros.internal.h" #include "libc/sysv/consts/termios.h" +#include "libc/sysv/consts/sio.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -27,6 +28,7 @@ int ioctl(int, uint64_t, void *); if (CMP(request, TCSETS)) return ioctl_tcsets(FD, REQUEST, MEMORY); \ if (CMP(request, TCSETSW)) return ioctl_tcsets(FD, REQUEST, MEMORY); \ if (CMP(request, TCSETSF)) return ioctl_tcsets(FD, REQUEST, MEMORY); \ + if (CMP(request, SIOCGIFCONF)) return ioctl_siocgifconf(FD, REQUEST, MEMORY); \ } while (0) int ioctl_tcgets(int, void *); @@ -37,6 +39,7 @@ int ioctl_tiocgwinsz(int, void *); int ioctl_tiocgwinsz_nt(int, void *); int ioctl_tiocswinsz(int, void *); int ioctl_tiocswinsz_nt(int, void *); +int ioctl_siocgifconf(int, uint64_t, void *); int ioctl_default(int, uint64_t, void *); forceinline int ioctl_dispatch(int fd, uint64_t request, void *memory) { diff --git a/libc/nt/winsock.h b/libc/nt/winsock.h index 1b48dabba..fab0cd4a0 100644 --- a/libc/nt/winsock.h +++ b/libc/nt/winsock.h @@ -85,6 +85,7 @@ #define kNtSioTranslateHandle 0xC800000Du #define kNtSioUdpConnreset 0x9800000Cu #define kNtSioUdpNetreset 0x9800000Fu +#define kNtSioGetInterfaceList 0x4008747fu /* _IOR('t', 127, ULONG) */ #define kNtNspNotifyImmediately 0 #define kNtNspNotifyHwnd 1 @@ -311,6 +312,13 @@ struct NtFdSet { int64_t fd_array[64]; }; +struct NtInterfaceInfo { + uint64_t iiFlags; + struct sockaddr_in iiAddress; + struct sockaddr_in iiBroadcastAddress; + struct sockaddr_in iiNetmask; +}; + /** * Winsock2 prototypes. * diff --git a/libc/sock/sock.h b/libc/sock/sock.h index 2601bd3b5..5f365c0b6 100644 --- a/libc/sock/sock.h +++ b/libc/sock/sock.h @@ -75,6 +75,60 @@ struct msghdr { /* Linux+NT ABI */ uint32_t msg_flags; /* MSG_XXX */ }; + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ +struct ifconf { + int ifc_len; /* size of buffer */ + union { + char *ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; + +/* Shortcuts to the ifconf buffer or ifreq array */ +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + +#define IFHWADDRLEN 6 +#define IF_NAMESIZE 16 +#define IFNAMSIZ IF_NAMESIZE +struct ifreq { + union { + char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + short int ifru_flags; + int ifru_ivalue; + int ifru_mtu; + } ifr_ifru; +}; +# define ifr_name ifr_ifrn.ifrn_name /* interface name */ +# define ifr_addr ifr_ifru.ifru_addr /* address */ +# define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ +# define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +# define ifr_flags ifr_ifru.ifru_flags /* flags */ +# define ifr_metric ifr_ifru.ifru_ivalue /* metric */ +# define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +# define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ +# define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ +# define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */ +# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0) +# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0) +# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0) + +#define IFF_UP (1<<0) + + + const char *inet_ntop(int, const void *, char *, uint32_t); int inet_aton(const char *, struct in_addr *); int inet_pton(int, const char *, void *);