diff options
author | cernekee <cernekee@chromium.org> | 2016-02-09 14:16:53 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-09 22:18:45 +0000 |
commit | c03b3edd866d172c13f96fde1c3773ca631462b9 (patch) | |
tree | 745b739c79ff38eee71b641d44e4357c2e0a3a67 /native_client_sdk | |
parent | 94fb5d4a5bf05e7d230c29be6df8ea1a21628032 (diff) | |
download | chromium_src-c03b3edd866d172c13f96fde1c3773ca631462b9.zip chromium_src-c03b3edd866d172c13f96fde1c3773ca631462b9.tar.gz chromium_src-c03b3edd866d172c13f96fde1c3773ca631462b9.tar.bz2 |
nacl_io: Add bare-bones getnameinfo() implementation
This can't perform reverse DNS queries, but at least it can translate
sockaddr_in and sockaddr_in6 into numeric IP strings.
BUG=386832
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_nacl_sdk;tryserver.chromium.mac:mac_nacl_sdk;tryserver.chromium.win:win_nacl_sdk
Review URL: https://codereview.chromium.org/1683553002
Cr-Commit-Position: refs/heads/master@{#374498}
Diffstat (limited to 'native_client_sdk')
-rw-r--r-- | native_client_sdk/src/libraries/nacl_io/host_resolver.cc | 48 | ||||
-rw-r--r-- | native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc | 103 |
2 files changed, 147 insertions, 4 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/host_resolver.cc b/native_client_sdk/src/libraries/nacl_io/host_resolver.cc index 4dd50ac..150e0cf 100644 --- a/native_client_sdk/src/libraries/nacl_io/host_resolver.cc +++ b/native_client_sdk/src/libraries/nacl_io/host_resolver.cc @@ -8,8 +8,11 @@ #include "nacl_io/host_resolver.h" +#include <arpa/inet.h> #include <assert.h> +#include <netinet/in.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -221,14 +224,51 @@ void HostResolver::freeaddrinfo(struct addrinfo* res) { } } -int HostResolver::getnameinfo(const struct sockaddr *sa, +int HostResolver::getnameinfo(const struct sockaddr* sa, socklen_t salen, - char *host, + char* host, size_t hostlen, - char *serv, + char* serv, size_t servlen, int flags) { - return ENOSYS; + in_port_t port; + const void* addr; + + if (host == NULL && serv == NULL) { + LOG_TRACE("host and serv are NULL."); + return EAI_NONAME; + } + + // Currently we only handle numeric hosts and services. + if (flags & NI_NAMEREQD) + return EAI_NONAME; + + if (sa->sa_family == AF_INET) { + if (salen < sizeof(struct sockaddr_in)) + return EAI_FAMILY; + + const struct sockaddr_in* sock = + reinterpret_cast<const struct sockaddr_in*>(sa); + port = sock->sin_port; + addr = &sock->sin_addr.s_addr; + } else if (sa->sa_family == AF_INET6) { + if (salen < sizeof(struct sockaddr_in6)) + return EAI_FAMILY; + + const struct sockaddr_in6* sock = + reinterpret_cast<const struct sockaddr_in6*>(sa); + port = sock->sin6_port; + addr = sock->sin6_addr.s6_addr; + } else { + return EAI_FAMILY; + } + + if (host && inet_ntop(sa->sa_family, addr, host, hostlen) == NULL) + return EAI_OVERFLOW; + if (serv && (size_t)snprintf(serv, servlen, "%u", htons(port)) >= servlen) + return EAI_OVERFLOW; + + return 0; } int HostResolver::getaddrinfo(const char* node, diff --git a/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc b/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc index 3aaec27..a153240 100644 --- a/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc +++ b/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc @@ -135,6 +135,109 @@ TEST_F(HostResolverTest, Getaddrinfo_NumericService) { ki_freeaddrinfo(ai); } +TEST_F(HostResolverTest, Getnameinfo_Numeric) { + char host[64]; + char serv[64]; + + // IPv4 host + service to strings. + struct sockaddr_in in; + + memset(&in, 0, sizeof(in)); + memset(host, 0, sizeof(host)); + memset(serv, 0, sizeof(serv)); + in.sin_family = AF_INET; + in.sin_port = ntohs(443); + in.sin_addr.s_addr = ntohl(0x01020304); + + ASSERT_EQ(0, ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), + sizeof(in), host, sizeof(host), serv, + sizeof(serv), NI_NUMERICSERV)); + ASSERT_STREQ(host, "1.2.3.4"); + ASSERT_STREQ(serv, "443"); + + // IPv4 host only. + memset(host, 0, sizeof(host)); + ASSERT_EQ(0, + ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), sizeof(in), + host, sizeof(host), NULL, 0, NI_NUMERICSERV)); + ASSERT_STREQ(host, "1.2.3.4"); + + // IPv6 host + service. + struct sockaddr_in6 in6; + + memset(&in6, 0, sizeof(in6)); + memset(host, 0, sizeof(host)); + memset(serv, 0, sizeof(serv)); + in6.sin6_family = AF_INET6; + in6.sin6_port = ntohs(80); + in6.sin6_addr.s6_addr[0] = 0xfe; + in6.sin6_addr.s6_addr[1] = 0x80; + in6.sin6_addr.s6_addr[12] = 0x05; + in6.sin6_addr.s6_addr[13] = 0x06; + in6.sin6_addr.s6_addr[14] = 0x07; + in6.sin6_addr.s6_addr[15] = 0x08; + + ASSERT_EQ(0, ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in6), + sizeof(in6), host, sizeof(host), serv, + sizeof(serv), NI_NUMERICSERV)); + ASSERT_STREQ(host, "fe80::506:708"); + ASSERT_STREQ(serv, "80"); + + // IPv6 service only. + memset(serv, 0, sizeof(serv)); + ASSERT_EQ( + 0, ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in6), sizeof(in6), + NULL, 0, serv, sizeof(serv), NI_NUMERICSERV)); + ASSERT_STREQ(serv, "80"); +} + +TEST_F(HostResolverTest, Getnameinfo_ErrorHandling) { + struct sockaddr_in in; + char host[64]; + char serv[64]; + + memset(&in, 0, sizeof(in)); + memset(host, 0, sizeof(host)); + memset(serv, 0, sizeof(serv)); + in.sin_family = AF_INET; + in.sin_port = ntohs(443); + in.sin_addr.s_addr = ntohl(0x01020304); + + // Bogus salen, hostlen, or servlen. + ASSERT_EQ(EAI_FAMILY, ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), + sizeof(in) - 4, host, sizeof(host), serv, + sizeof(serv), NI_NUMERICSERV)); + ASSERT_EQ(EAI_OVERFLOW, + ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), sizeof(in), + host, 7, serv, sizeof(serv), NI_NUMERICSERV)); + ASSERT_EQ(EAI_OVERFLOW, + ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), sizeof(in), + host, sizeof(host), serv, 3, NI_NUMERICSERV)); + + // User insists on names, but we can only provide numbers. + ASSERT_EQ(EAI_NONAME, + ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), sizeof(in), + host, sizeof(host), serv, 3, NI_NAMEREQD)); + + // User forgot to pass a host or serv buffer. + ASSERT_EQ(EAI_NONAME, + ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&in), sizeof(in), + NULL, 0, NULL, 0, NI_NUMERICSERV)); + + // Wrong socket type. + struct sockaddr unix_sock; + memset(&unix_sock, 0, sizeof(unix_sock)); + memset(host, 0, sizeof(host)); + memset(serv, 0, sizeof(serv)); + unix_sock.sa_family = AF_UNIX; + ASSERT_EQ(EAI_FAMILY, + ki_getnameinfo(reinterpret_cast<struct sockaddr*>(&unix_sock), + sizeof(unix_sock), host, sizeof(host), serv, + sizeof(serv), NI_NUMERICSERV)); + ASSERT_STREQ(host, ""); + ASSERT_STREQ(serv, ""); +} + TEST_F(HostResolverTest, Getaddrinfo_MissingPPAPI) { // Verify that full lookups fail due to lack of PPAPI interfaces struct addrinfo* ai = NULL; |