Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions libc/calls/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/serialize.h"
#include "libc/sock/in.h"
#include "libc/sock/internal.h"
#include "libc/sock/struct/ifconf.h"
#include "libc/sock/struct/ifreq.h"
Expand Down Expand Up @@ -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;
p += IsBsd() ? 16 + MAX(16, p[16] & 255) : 40) {
fam = p[IsBsd() ? 17 : 16] & 255;
if (fam != AF_INET)
continue;
ip = READ32BE(p + 20);
bzero(req, sizeof(*req));
memcpy(req->ifr_name, p, 16);
memcpy(&req->ifr_addr, p + 16, 16);
req->ifr_addr.sa_family = fam;
((struct sockaddr_in *)&req->ifr_addr)->sin_addr.s_addr = htonl(ip);
++req;
if (fam == AF_INET) {
ip = READ32BE(p + 20);
bzero(req, sizeof(*req));
memcpy(req->ifr_name, p, 16);
memcpy(&req->ifr_addr, p + 16, 16);
req->ifr_addr.sa_family = fam;
((struct sockaddr_in *)&req->ifr_addr)->sin_addr.s_addr = htonl(ip);
++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 */
}
Expand Down
5 changes: 5 additions & 0 deletions libc/intrin/bswap.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ uint64_t(bswap_64)(uint64_t x) {
(0x00ff000000000000ull & x) >> 050 |
(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));
}
8 changes: 5 additions & 3 deletions libc/intrin/bswap.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ COSMOPOLITAN_C_START_
libcesque uint16_t bswap_16(uint16_t) pureconst;
libcesque uint32_t bswap_32(uint32_t) pureconst;
libcesque uint64_t bswap_64(uint64_t) pureconst;
libcesque uint128_t bswap_128(uint128_t) pureconst;

#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define bswap_16(x) __builtin_bswap16(x)
#define bswap_32(x) __builtin_bswap32(x)
#define bswap_64(x) __builtin_bswap64(x)
#define bswap_16(x) __builtin_bswap16(x)
#define bswap_32(x) __builtin_bswap32(x)
#define bswap_64(x) __builtin_bswap64(x)
#define bswap_128(x) __builtin_bswap128(x)
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */

COSMOPOLITAN_C_END_
Expand Down
84 changes: 48 additions & 36 deletions libc/intrin/newbie.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,55 @@
#define PDP_ENDIAN __ORDER_PDP_ENDIAN__

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define htobe16(x) bswap_16(x)
#define be16toh(x) bswap_16(x)
#define betoh16(x) bswap_16(x)
#define htobe32(x) bswap_32(x)
#define be32toh(x) bswap_32(x)
#define betoh32(x) bswap_32(x)
#define htobe64(x) bswap_64(x)
#define be64toh(x) bswap_64(x)
#define betoh64(x) bswap_64(x)
#define htole16(x) (uint16_t)(x)
#define le16toh(x) (uint16_t)(x)
#define letoh16(x) (uint16_t)(x)
#define htole32(x) (uint32_t)(x)
#define le32toh(x) (uint32_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 htobe16(x) bswap_16(x)
#define be16toh(x) bswap_16(x)
#define betoh16(x) bswap_16(x)
#define htobe32(x) bswap_32(x)
#define be32toh(x) bswap_32(x)
#define betoh32(x) bswap_32(x)
#define htobe64(x) bswap_64(x)
#define be64toh(x) bswap_64(x)
#define betoh64(x) bswap_64(x)
#define htobe128(x) bswap_128(x)
#define be128toh(x) bswap_128(x)
#define betoh128(x) bswap_128(x)
#define htole16(x) (uint16_t)(x)
#define le16toh(x) (uint16_t)(x)
#define letoh16(x) (uint16_t)(x)
#define htole32(x) (uint32_t)(x)
#define le32toh(x) (uint32_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
#define htobe16(x) (uint16_t)(x)
#define be16toh(x) (uint16_t)(x)
#define betoh16(x) (uint16_t)(x)
#define htobe32(x) (uint32_t)(x)
#define be32toh(x) (uint32_t)(x)
#define betoh32(x) (uint32_t)(x)
#define htobe64(x) (uint64_t)(x)
#define be64toh(x) (uint64_t)(x)
#define betoh64(x) (uint64_t)(x)
#define htole16(x) bswap_16(x)
#define le16toh(x) bswap_16(x)
#define letoh16(x) bswap_16(x)
#define htole32(x) bswap_32(x)
#define le32toh(x) bswap_32(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 htobe16(x) (uint16_t)(x)
#define be16toh(x) (uint16_t)(x)
#define betoh16(x) (uint16_t)(x)
#define htobe32(x) (uint32_t)(x)
#define be32toh(x) (uint32_t)(x)
#define betoh32(x) (uint32_t)(x)
#define htobe64(x) (uint64_t)(x)
#define be64toh(x) (uint64_t)(x)
#define betoh64(x) (uint64_t)(x)
#define htobe128(x) (uint128_t)(x)
#define be128toh(x) (uint128_t)(x)
#define betoh128(x) (uint128_t)(x)
#define htole16(x) bswap_16(x)
#define le16toh(x) bswap_16(x)
#define letoh16(x) bswap_16(x)
#define htole32(x) bswap_32(x)
#define le32toh(x) bswap_32(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 /* COSMOPOLITAN_LIBC_BITS_NEWBIE_H_ */
63 changes: 47 additions & 16 deletions libc/sock/ifaddrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/newbie.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/sock/sock.h"
Expand All @@ -34,6 +35,9 @@
#include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h"

#define SIOCGIFAFLAG_IN6 3240126793 // bsd
#define SIOCGIFNETMASK_IN6 3240126757 // bsd

struct IfAddr {
struct ifaddrs ifaddrs;
char name[IFNAMSIZ];
Expand Down Expand Up @@ -142,27 +146,27 @@ static int getifaddrs_linux_ip6(struct ifconf *conf) {
* @see tool/viz/getifaddrs.c for example code
*/
int getifaddrs(struct ifaddrs **out_ifpp) {
// printf("%d\n", sizeof(struct ifreq));
int rc = -1;
int fd;
int rc = 0;
int fd, fd6 = -1;
if ((fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) != -1) {
char *data;
size_t size;
if ((data = malloc((size = 16384)))) {
struct ifconf conf;
struct ifconf conf, confl6;
conf.ifc_buf = data;
conf.ifc_len = size;
if (!ioctl(fd, SIOCGIFCONF, &conf)) {
confl6.ifc_buf = data + conf.ifc_len;
confl6.ifc_len = size - conf.ifc_len;
if (IsLinux()) {
struct ifconf 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;
rc = getifaddrs_linux_ip6(&confl6);
}
if (rc)
return rc;
conf.ifc_len += confl6.ifc_len;

struct ifaddrs *res = 0;
rc = -1;
for (struct ifreq *ifr = (struct ifreq *)data;
(char *)ifr < data + conf.ifc_len; ++ifr) {
uint16_t family = ifr->ifr_addr.sa_family;
Expand Down Expand Up @@ -207,9 +211,10 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
addr6->ifaddrs.ifa_broadaddr = (struct sockaddr *)&addr6->bstaddr;
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_flags = ifr->ifr6_flags;

memcpy(&addr6->name, &ifr->ifr_name, IFNAMSIZ);

addr6->addr.sin6_family = AF_INET6;
addr6->addr.sin6_port = 0;
Expand All @@ -222,10 +227,33 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
addr6->netmask.sin6_port = 0;
addr6->netmask.sin6_flowinfo = 0;
addr6->addr.sin6_scope_id = ifr->ifr6_ifindex;
memcpy(&addr6->netmask.sin6_addr, &ifr->ifr6_addr,
sizeof(struct in6_addr));
*((uint128_t *)&(addr6->netmask.sin6_addr)) &=
(UINT128_MAX >> ifr->ifr6_prefixlen);

if (IsBsd()) { // on bsd we miss prefixlen and addr flags
if (fd6 == -1) {
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)) {
addr6->ifaddrs.ifa_flags = ifr->ifr_flags;
Expand All @@ -243,6 +271,9 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
free(data);
}
close(fd);
if (fd6 != -1) {
close(fd6);
}
}
return rc;
}