/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2021 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/syscall-sysv.internal.h" #include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/nt/errors.h" #include "libc/nt/iphlpapi.h" #include "libc/serialize.h" #include "libc/sock/sock.h" #include "libc/str/str.h" #include "libc/sysv/consts/af.h" #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/sock.h" static uint32_t *GetUnixIps(void) { int fd, n; uint64_t z; uint32_t *a; char *b, *p, *e, c[16]; if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) return 0; a = 0; n = 0; z = 15000; b = malloc(z); memcpy(c, &z, 8); memcpy(c + (IsXnu() ? 4 : 8), &b, 8); if (sys_ioctl(fd, SIOCGIFCONF, &c) != -1) { for (p = b, e = p + MIN(z, READ32LE(c)); p + 16 + 16 <= e; p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) { if ((p[IsBsd() ? 17 : 16] & 255) != AF_INET) continue; a = realloc(a, ++n * sizeof(*a)); a[n - 1] = READ32BE(p + 20); } a = realloc(a, ++n * sizeof(*a)); a[n - 1] = 0; } close(fd); free(b); return a; } static textwindows uint32_t *GetWindowsIps(void) { uint32_t i, z, n, rc, *a; struct NtIpAdapterUnicastAddress *u; struct NtIpAdapterAddresses *p, *ifaces; i = 0; z = 15000; do { if (!(ifaces = malloc(z))) return 0; rc = GetAdaptersAddresses(AF_INET, kNtGaaFlagSkipAnycast | kNtGaaFlagSkipMulticast | kNtGaaFlagSkipDnsServer | kNtGaaFlagSkipFriendlyName, 0, ifaces, &z); if (rc != kNtErrorBufferOverflow) break; free(ifaces); ifaces = 0; } while (++i < 3); if (rc == kNtErrorNoData) { a = calloc(1, sizeof(*a)); } else if (rc == kNtNoError) { for (a = 0, n = 0, p = ifaces; p; p = p->Next) { if (p->OperStatus != kNtIfOperStatusUp) continue; for (u = p->FirstUnicastAddress; u; u = u->Next) { if (u->Address.lpSockaddr->sa_family != AF_INET) continue; a = realloc(a, ++n * sizeof(*a)); a[n - 1] = ntohl( ((struct sockaddr_in *)u->Address.lpSockaddr)->sin_addr.s_addr); } } a = realloc(a, ++n * sizeof(*a)); a[n - 1] = 0; } else { __winerr(); a = 0; } free(ifaces); return a; } /** * Returns IP addresses of system. * * Normally return values will look like `{0x7f000001, 0x0a0a0a7c, 0}` * which means the same thing as `{"127.0.0.1", "10.10.10.124", 0}`. * Returned IPs will IPv4 anycast addresses bound to network interfaces * which come in a NULL-terminated array with no particular ordering. * * uint32_t *ip, *ips = GetIps(); * for (ip = ips; *ip; ++ip) { * printf("%hhu.%hhu.%hhu.%hhu\n", *ip >> 24, *ip >> 16, *ip >> 8, *ip); * } * * This function supports Windows, Linux, XNU, FreeBSD, NetBSD, OpenBSD. * * @return null-terminated ip array on success, or null w/ errno */ uint32_t *GetHostIps(void) { if (!IsWindows()) { return GetUnixIps(); } else { return GetWindowsIps(); } }