Skip to content

Commit

Permalink
Recognize localhost before handing off to system
Browse files Browse the repository at this point in the history
  • Loading branch information
jellefoks committed Feb 5, 2025
1 parent 7e88efa commit d4e78c3
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 7 deletions.
35 changes: 28 additions & 7 deletions starboard/nplb/posix_compliance/posix_socket_resolve_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <utility>

#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace starboard {
namespace nplb {
Expand Down Expand Up @@ -225,22 +226,42 @@ TEST_P(PosixSocketResolveTest, Localhost) {

int address_count = 0;
struct sockaddr_in* ai_addr = nullptr;
struct sockaddr_in6* ai_addr6 = nullptr;
for (const struct addrinfo* i = ai; i != nullptr; i = i->ai_next) {
++address_count;
if (ai_addr == nullptr && i->ai_addr != nullptr) {
ai_addr = reinterpret_cast<sockaddr_in*>(i->ai_addr);
break;
ai_addr6 = reinterpret_cast<sockaddr_in6*>(i->ai_addr);

EXPECT_TRUE(ai_addr->sin_family == AF_INET ||
ai_addr->sin_family == AF_INET6);
if (GetAddressFamily() != AF_UNSPEC) {
EXPECT_EQ(ai_addr->sin_family, GetAddressFamily());
if (GetAddressFamily() == AF_INET) {
struct in_addr loopback_addr;
loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
EXPECT_EQ(ai_addr->sin_addr.s_addr, loopback_addr.s_addr);

struct in_addr expected_addr;
expected_addr.s_addr = htonl((127 << 24) | 1);
EXPECT_EQ(ai_addr->sin_addr.s_addr, expected_addr.s_addr);
}
if (GetAddressFamily() == AF_INET6) {
struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT;
EXPECT_EQ(memcmp(&ai_addr6->sin6_addr, &loopback, sizeof(loopback)),
0);

const unsigned char kExpectedAddress[16] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1};
EXPECT_THAT(ai_addr6->sin6_addr.s6_addr,
testing::ElementsAreArray(kExpectedAddress));
}
}
}
}
EXPECT_LT(0, address_count);
EXPECT_NE(nullptr, ai_addr);

EXPECT_TRUE(ai_addr->sin_family == AF_INET ||
ai_addr->sin_family == AF_INET6);
if (GetAddressFamily() != AF_UNSPEC) {
EXPECT_EQ(ai_addr->sin_family, GetAddressFamily());
}

freeaddrinfo(ai);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,50 @@ SB_EXPORT int __abi_wrap_getaddrinfo(const char* node,
return -1;
}

// Recognize "localhost" as special and resolve to the loopback address.
// https://datatracker.ietf.org/doc/html/rfc6761#section-6.3
// Note: This returns the IPv4 localhost first, and falls back to system
// resolution when a service is supplied.
if (!service && node && strcmp("localhost", node) == 0) {
struct musl_addrinfo* last_ai = nullptr;
*res = nullptr;
const int ai_family[2] = {MUSL_AF_INET, MUSL_AF_INET6};
for (int family_idx = 0; family_idx < 2; ++family_idx) {
int family = ai_family[family_idx];
if (!hints || hints->ai_family == AF_UNSPEC ||
hints->ai_family == family) {
struct musl_addrinfo* musl_ai =
(struct musl_addrinfo*)calloc(1, sizeof(struct musl_addrinfo));
musl_ai->ai_addrlen = family == MUSL_AF_INET
? sizeof(struct sockaddr_in)
: sizeof(struct sockaddr_in6);
musl_ai->ai_addr = reinterpret_cast<struct musl_sockaddr*>(
calloc(1, sizeof(struct musl_sockaddr)));
musl_ai->ai_addr->sa_family = family;

if (family == MUSL_AF_INET) {
struct sockaddr_in* address =
reinterpret_cast<struct sockaddr_in*>(musl_ai->ai_addr);
address->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
// address->sin_addr.s_addr = -1;
} else if (family == MUSL_AF_INET6) {
struct sockaddr_in6* address =
reinterpret_cast<struct sockaddr_in6*>(musl_ai->ai_addr);
address->sin6_addr = IN6ADDR_LOOPBACK_INIT;
// address->sin6_addr.__in6_u.__u6_addr8[0] = 5;
}
if (*res == nullptr) {
*res = musl_ai;
last_ai = musl_ai;
} else {
last_ai->ai_next = musl_ai;
last_ai = musl_ai;
}
}
}
return 0;
}

// musl addrinfo definition might differ from platform definition.
// So we need to do a manual conversion to avoid header mismatches.
struct addrinfo new_hints = {0};
Expand Down
43 changes: 43 additions & 0 deletions starboard/shared/posix/socket_resolve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>

#include "starboard/common/log.h"
Expand All @@ -27,6 +28,48 @@ SbSocketResolution* SbSocketResolve(const char* hostname, int filters) {
struct addrinfo* ai = NULL;
struct addrinfo hints = {0};

// Recognize "localhost" as special and resolve to the loopback address.
// https://datatracker.ietf.org/doc/html/rfc6761#section-6.3
// Note: This returns the IPv4 localhost first.
if (hostname && strcmp("localhost", hostname) == 0) {
SbSocketResolution* result = new SbSocketResolution();
int address = 0;
result->address_count = 0;
if (filters == kSbSocketResolveFilterNone) {
result->address_count = 2;
} else {
if (filters & kSbSocketResolveFilterIpv4) {
result->address_count++;
}
#if SB_HAS(IPV6)
if (filters & kSbSocketResolveFilterIpv6) {
result->address_count++;
}
#endif
}
result->addresses =
new SbSocketAddress[result->address_count](); // ensure zero
// initialization

if ((filters == kSbSocketResolveFilterNone) ||
(filters & kSbSocketResolveFilterIpv4)) {
result->addresses[address].port = 0;
result->addresses[address].type = kSbSocketAddressTypeIpv4;
result->addresses[address].address[0] = 127;
result->addresses[address].address[3] = 1;
address++;
}
#if SB_HAS(IPV6)
if ((filters == kSbSocketResolveFilterNone) ||
(filters & kSbSocketResolveFilterIpv6)) {
result->addresses[address].port = 0;
result->addresses[address].type = kSbSocketAddressTypeIpv6;
result->addresses[address].address[15] = 1;
}
#endif
return result;
}

if (filters & kSbSocketResolveFilterIpv4) {
if (filters & kSbSocketResolveFilterIpv6) {
hints.ai_family = AF_UNSPEC;
Expand Down

0 comments on commit d4e78c3

Please sign in to comment.