This commit is contained in:
Hugues Morisset 2025-08-13 13:10:35 +00:00 committed by GitHub
commit 2b491390b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 134 additions and 64 deletions

View file

@ -43,6 +43,7 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/serialize.h" #include "libc/serialize.h"
#include "libc/sock/in.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/struct/ifconf.h" #include "libc/sock/struct/ifconf.h"
#include "libc/sock/struct/ifreq.h" #include "libc/sock/struct/ifreq.h"
@ -533,15 +534,34 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e; for (p = b, e = p + MIN(bufMax, READ32LE(ifcBsd)); p + 16 + 16 <= e;
p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) { p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) {
fam = p[IsBsd() ? 17 : 16] & 255; fam = p[IsBsd() ? 17 : 16] & 255;
if (fam != AF_INET) if (fam == AF_INET) {
continue; ip = READ32BE(p + 20);
ip = READ32BE(p + 20); bzero(req, sizeof(*req));
bzero(req, sizeof(*req)); memcpy(req->ifr_name, p, 16);
memcpy(req->ifr_name, p, 16); memcpy(&req->ifr_addr, p + 16, 16);
memcpy(&req->ifr_addr, p + 16, 16); req->ifr_addr.sa_family = fam;
req->ifr_addr.sa_family = fam; ((struct sockaddr_in *)&req->ifr_addr)->sin_addr.s_addr = htonl(ip);
((struct sockaddr_in *)&req->ifr_addr)->sin_addr.s_addr = htonl(ip); ++req;
++req; } else if (fam == AF_INET6) {
// Only BSD systems returns AF_INET6 addresses with SIOCGIFCONF
// BSD don't return flags or prefix length, need to get them later
bzero(req, sizeof(*req));
memcpy(req->ifr_name, p, 16);
void *addr6 = p + 24;
if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
// link-local bsd special https://stackoverflow.com/q/5888359/2838914
req->ifr6_ifindex = ntohs(*((uint16_t *)(p + 26)));
*((uint16_t *)(p + 26)) = 0x0;
req->ifr6_scope = 0x20; // link
} else if (IN6_IS_ADDR_SITELOCAL(addr6)) {
req->ifr6_scope = 0x40; // site
} else if (IN6_IS_ADDR_LOOPBACK(addr6)) {
req->ifr6_scope = 0x10; // host
}
memcpy(&req->ifr6_addr, addr6, 16);
req->ifr_addr.sa_family = fam;
++req;
}
} }
ifc->ifc_len = (char *)req - ifc->ifc_buf; /* Adjust len */ ifc->ifc_len = (char *)req - ifc->ifc_buf; /* Adjust len */
} }

View file

@ -45,3 +45,8 @@ uint64_t(bswap_64)(uint64_t x) {
(0x00ff000000000000ull & x) >> 050 | (0x00ff000000000000ull & x) >> 050 |
(0xff00000000000000ull & x) >> 070; (0xff00000000000000ull & x) >> 070;
} }
uint128_t(bswap_128)(uint128_t x) {
return ((uint128_t)bswap_64((uint64_t)x) << 64) |
(uint128_t)bswap_64((uint64_t)(x >> 64));
}

View file

@ -5,11 +5,13 @@ COSMOPOLITAN_C_START_
libcesque uint16_t bswap_16(uint16_t) pureconst; libcesque uint16_t bswap_16(uint16_t) pureconst;
libcesque uint32_t bswap_32(uint32_t) pureconst; libcesque uint32_t bswap_32(uint32_t) pureconst;
libcesque uint64_t bswap_64(uint64_t) pureconst; libcesque uint64_t bswap_64(uint64_t) pureconst;
libcesque uint128_t bswap_128(uint128_t) pureconst;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define bswap_16(x) __builtin_bswap16(x) #define bswap_16(x) __builtin_bswap16(x)
#define bswap_32(x) __builtin_bswap32(x) #define bswap_32(x) __builtin_bswap32(x)
#define bswap_64(x) __builtin_bswap64(x) #define bswap_64(x) __builtin_bswap64(x)
#define bswap_128(x) __builtin_bswap128(x)
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ #endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -8,43 +8,55 @@
#define PDP_ENDIAN __ORDER_PDP_ENDIAN__ #define PDP_ENDIAN __ORDER_PDP_ENDIAN__
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define htobe16(x) bswap_16(x) #define htobe16(x) bswap_16(x)
#define be16toh(x) bswap_16(x) #define be16toh(x) bswap_16(x)
#define betoh16(x) bswap_16(x) #define betoh16(x) bswap_16(x)
#define htobe32(x) bswap_32(x) #define htobe32(x) bswap_32(x)
#define be32toh(x) bswap_32(x) #define be32toh(x) bswap_32(x)
#define betoh32(x) bswap_32(x) #define betoh32(x) bswap_32(x)
#define htobe64(x) bswap_64(x) #define htobe64(x) bswap_64(x)
#define be64toh(x) bswap_64(x) #define be64toh(x) bswap_64(x)
#define betoh64(x) bswap_64(x) #define betoh64(x) bswap_64(x)
#define htole16(x) (uint16_t)(x) #define htobe128(x) bswap_128(x)
#define le16toh(x) (uint16_t)(x) #define be128toh(x) bswap_128(x)
#define letoh16(x) (uint16_t)(x) #define betoh128(x) bswap_128(x)
#define htole32(x) (uint32_t)(x) #define htole16(x) (uint16_t)(x)
#define le32toh(x) (uint32_t)(x) #define le16toh(x) (uint16_t)(x)
#define letoh32(x) (uint32_t)(x) #define letoh16(x) (uint16_t)(x)
#define htole64(x) (uint64_t)(x) #define htole32(x) (uint32_t)(x)
#define le64toh(x) (uint64_t)(x) #define le32toh(x) (uint32_t)(x)
#define letoh64(x) (uint64_t)(x) #define letoh32(x) (uint32_t)(x)
#define htole64(x) (uint64_t)(x)
#define le64toh(x) (uint64_t)(x)
#define letoh64(x) (uint64_t)(x)
#define htole128(x) (uint128_t)(x)
#define le128toh(x) (uint128_t)(x)
#define letoh128(x) (uint128_t)(x)
#else #else
#define htobe16(x) (uint16_t)(x) #define htobe16(x) (uint16_t)(x)
#define be16toh(x) (uint16_t)(x) #define be16toh(x) (uint16_t)(x)
#define betoh16(x) (uint16_t)(x) #define betoh16(x) (uint16_t)(x)
#define htobe32(x) (uint32_t)(x) #define htobe32(x) (uint32_t)(x)
#define be32toh(x) (uint32_t)(x) #define be32toh(x) (uint32_t)(x)
#define betoh32(x) (uint32_t)(x) #define betoh32(x) (uint32_t)(x)
#define htobe64(x) (uint64_t)(x) #define htobe64(x) (uint64_t)(x)
#define be64toh(x) (uint64_t)(x) #define be64toh(x) (uint64_t)(x)
#define betoh64(x) (uint64_t)(x) #define betoh64(x) (uint64_t)(x)
#define htole16(x) bswap_16(x) #define htobe128(x) (uint128_t)(x)
#define le16toh(x) bswap_16(x) #define be128toh(x) (uint128_t)(x)
#define letoh16(x) bswap_16(x) #define betoh128(x) (uint128_t)(x)
#define htole32(x) bswap_32(x) #define htole16(x) bswap_16(x)
#define le32toh(x) bswap_32(x) #define le16toh(x) bswap_16(x)
#define letoh32(x) bswap_32(x) #define letoh16(x) bswap_16(x)
#define htole64(x) bswap_64(x) #define htole32(x) bswap_32(x)
#define le64toh(x) bswap_64(x) #define le32toh(x) bswap_32(x)
#define letoh64(x) bswap_64(x) #define letoh32(x) bswap_32(x)
#define htole64(x) bswap_64(x)
#define le64toh(x) bswap_64(x)
#define letoh64(x) bswap_64(x)
#define htole128(x) bswap_128(x)
#define le128toh(x) bswap_128(x)
#define letoh128(x) bswap_128(x)
#endif #endif
#endif /* COSMOPOLITAN_LIBC_BITS_NEWBIE_H_ */ #endif /* COSMOPOLITAN_LIBC_BITS_NEWBIE_H_ */

View file

@ -20,6 +20,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/newbie.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
@ -34,6 +35,9 @@
#include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h" #include "libc/sysv/consts/sock.h"
#define SIOCGIFAFLAG_IN6 3240126793 // bsd
#define SIOCGIFNETMASK_IN6 3240126757 // bsd
struct IfAddr { struct IfAddr {
struct ifaddrs ifaddrs; struct ifaddrs ifaddrs;
char name[IFNAMSIZ]; char name[IFNAMSIZ];
@ -142,27 +146,27 @@ static int getifaddrs_linux_ip6(struct ifconf *conf) {
* @see tool/viz/getifaddrs.c for example code * @see tool/viz/getifaddrs.c for example code
*/ */
int getifaddrs(struct ifaddrs **out_ifpp) { int getifaddrs(struct ifaddrs **out_ifpp) {
// printf("%d\n", sizeof(struct ifreq)); int rc = 0;
int rc = -1; int fd, fd6 = -1;
int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) != -1) { if ((fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) != -1) {
char *data; char *data;
size_t size; size_t size;
if ((data = malloc((size = 16384)))) { if ((data = malloc((size = 16384)))) {
struct ifconf conf; struct ifconf conf, confl6;
conf.ifc_buf = data; conf.ifc_buf = data;
conf.ifc_len = size; conf.ifc_len = size;
if (!ioctl(fd, SIOCGIFCONF, &conf)) { if (!ioctl(fd, SIOCGIFCONF, &conf)) {
confl6.ifc_buf = data + conf.ifc_len;
confl6.ifc_len = size - conf.ifc_len;
if (IsLinux()) { if (IsLinux()) {
struct ifconf confl6; rc = getifaddrs_linux_ip6(&confl6);
confl6.ifc_buf = data + conf.ifc_len;
confl6.ifc_len = size - conf.ifc_len;
if ((rc = getifaddrs_linux_ip6(&confl6)))
return rc;
conf.ifc_len += confl6.ifc_len;
} }
if (rc)
return rc;
conf.ifc_len += confl6.ifc_len;
struct ifaddrs *res = 0; struct ifaddrs *res = 0;
rc = -1;
for (struct ifreq *ifr = (struct ifreq *)data; for (struct ifreq *ifr = (struct ifreq *)data;
(char *)ifr < data + conf.ifc_len; ++ifr) { (char *)ifr < data + conf.ifc_len; ++ifr) {
uint16_t family = ifr->ifr_addr.sa_family; uint16_t family = ifr->ifr_addr.sa_family;
@ -207,9 +211,10 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
addr6->ifaddrs.ifa_broadaddr = (struct sockaddr *)&addr6->bstaddr; addr6->ifaddrs.ifa_broadaddr = (struct sockaddr *)&addr6->bstaddr;
addr6->ifaddrs.ifa_data = (void *)&addr6->info; addr6->ifaddrs.ifa_data = (void *)&addr6->info;
memcpy(&addr6->name, &ifr->ifr_name, IFNAMSIZ);
addr6->info.addr_flags = ifr->ifr6_flags;
addr6->info.addr_scope = ifr->ifr6_scope; addr6->info.addr_scope = ifr->ifr6_scope;
addr6->info.addr_flags = ifr->ifr6_flags;
memcpy(&addr6->name, &ifr->ifr_name, IFNAMSIZ);
addr6->addr.sin6_family = AF_INET6; addr6->addr.sin6_family = AF_INET6;
addr6->addr.sin6_port = 0; addr6->addr.sin6_port = 0;
@ -222,10 +227,33 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
addr6->netmask.sin6_port = 0; addr6->netmask.sin6_port = 0;
addr6->netmask.sin6_flowinfo = 0; addr6->netmask.sin6_flowinfo = 0;
addr6->addr.sin6_scope_id = ifr->ifr6_ifindex; addr6->addr.sin6_scope_id = ifr->ifr6_ifindex;
memcpy(&addr6->netmask.sin6_addr, &ifr->ifr6_addr,
sizeof(struct in6_addr)); if (IsBsd()) { // on bsd we miss prefixlen and addr flags
*((uint128_t *)&(addr6->netmask.sin6_addr)) &= if (fd6 == -1) {
(UINT128_MAX >> ifr->ifr6_prefixlen); fd6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
}
uint8_t in6req[288]; // BSD struct in6_ifreq
bzero(&in6req, sizeof(in6req));
memcpy(&in6req, &ifr->ifr_name, IFNAMSIZ);
in6req[16] = 28; // sin6_len sizeof(struct sockaddr_in6_bsd)
in6req[17] = AF_INET6; // sin6_family
memcpy(&in6req[24], &addr6->addr.sin6_addr,
sizeof(struct in6_addr)); // sin6_addr
if (!ioctl(fd6, SIOCGIFAFLAG_IN6, &in6req)) {
addr6->info.addr_flags =
*(int *)(&in6req[16]); // ifru_flags6
}
in6req[16] = 28; // sin6_len
in6req[17] = AF_INET6; // sin6_family
if (!ioctl(fd6, SIOCGIFNETMASK_IN6, &in6req)) {
memcpy(&(addr6->netmask.sin6_addr), &in6req[24],
sizeof(struct in6_addr));
}
} else {
int prefixlen = ifr->ifr6_prefixlen;
*((uint128_t *)&(addr6->netmask.sin6_addr)) = htobe128(
prefixlen == 0 ? 0 : (UINT128_MAX << (128 - prefixlen)));
}
if (!ioctl(fd, SIOCGIFFLAGS, ifr)) { if (!ioctl(fd, SIOCGIFFLAGS, ifr)) {
addr6->ifaddrs.ifa_flags = ifr->ifr_flags; addr6->ifaddrs.ifa_flags = ifr->ifr_flags;
@ -243,6 +271,9 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
free(data); free(data);
} }
close(fd); close(fd);
if (fd6 != -1) {
close(fd6);
}
} }
return rc; return rc;
} }