1 //
2 //
3 // Copyright 2017 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <inttypes.h>
20 #include <net/if.h>
21 #include <netdb.h>
22 #include <string.h>
23
24 #include <grpc/support/alloc.h>
25 #ifdef GRPC_HAVE_UNIX_SOCKET
26 #include <sys/un.h>
27 #endif
28
29 #include <string>
30
31 #include "absl/status/status.h"
32 #include "absl/status/statusor.h"
33 #include "absl/strings/str_format.h"
34 #include "gtest/gtest.h"
35
36 #include <grpc/grpc.h>
37 #include <grpc/support/log.h>
38
39 #include "src/core/lib/address_utils/parse_address.h"
40 #include "src/core/lib/gprpp/crash.h"
41 #include "src/core/lib/gprpp/host_port.h"
42 #include "src/core/lib/iomgr/exec_ctx.h"
43 #include "src/core/lib/iomgr/resolved_address.h"
44 #include "src/core/lib/iomgr/sockaddr.h"
45 #include "src/core/lib/uri/uri_parser.h"
46 #include "test/core/util/test_config.h"
47
test_grpc_parse_ipv6_parity_with_getaddrinfo(const char * target,const struct sockaddr_in6 result_from_getaddrinfo)48 static void test_grpc_parse_ipv6_parity_with_getaddrinfo(
49 const char* target, const struct sockaddr_in6 result_from_getaddrinfo) {
50 // Get the sockaddr that gRPC's ipv6 resolver resolves this too.
51 grpc_core::ExecCtx exec_ctx;
52 absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(target);
53 if (!uri.ok()) {
54 gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
55 ASSERT_TRUE(uri.ok());
56 }
57 grpc_resolved_address addr;
58 ASSERT_TRUE(grpc_parse_ipv6(*uri, &addr));
59 grpc_sockaddr_in6* result_from_grpc_parser =
60 reinterpret_cast<grpc_sockaddr_in6*>(addr.addr);
61 // Compare the sockaddr returned from gRPC's ipv6 resolver with that returned
62 // from getaddrinfo.
63 ASSERT_EQ(result_from_grpc_parser->sin6_family, AF_INET6);
64 ASSERT_EQ(result_from_getaddrinfo.sin6_family, AF_INET6);
65 ASSERT_EQ(memcmp(&result_from_grpc_parser->sin6_addr,
66 &result_from_getaddrinfo.sin6_addr, sizeof(in6_addr)),
67 0);
68 ASSERT_EQ(result_from_grpc_parser->sin6_scope_id,
69 result_from_getaddrinfo.sin6_scope_id);
70 ASSERT_NE(result_from_grpc_parser->sin6_scope_id, 0);
71 // TODO(unknown): compare sin6_flow_info fields? parse_ipv6 zero's this field
72 // as is. Cleanup
73 }
74
resolve_with_gettaddrinfo(const char * uri_text)75 struct sockaddr_in6 resolve_with_gettaddrinfo(const char* uri_text) {
76 absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(uri_text);
77 if (!uri.ok()) {
78 gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
79 EXPECT_TRUE(uri.ok());
80 }
81 std::string host;
82 std::string port;
83 grpc_core::SplitHostPort(uri->path(), &host, &port);
84 struct addrinfo hints;
85 memset(&hints, 0, sizeof(hints));
86 hints.ai_family = AF_INET6;
87 hints.ai_socktype = SOCK_STREAM;
88 hints.ai_flags = AI_NUMERICHOST;
89 struct addrinfo* result;
90 int res = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
91 if (res != 0) {
92 grpc_core::Crash(absl::StrFormat(
93 "getaddrinfo failed to resolve host:%s port:%s. Error: %d.",
94 host.c_str(), port.c_str(), res));
95 }
96 size_t num_addrs_from_getaddrinfo = 0;
97 for (struct addrinfo* resp = result; resp != nullptr; resp = resp->ai_next) {
98 num_addrs_from_getaddrinfo++;
99 }
100 EXPECT_EQ(num_addrs_from_getaddrinfo, 1);
101 EXPECT_EQ(result->ai_family, AF_INET6);
102 struct sockaddr_in6 out =
103 *reinterpret_cast<struct sockaddr_in6*>(result->ai_addr);
104 // Cleanup
105 freeaddrinfo(result);
106 return out;
107 }
108
TEST(ParseAddressWithNamedScopeIdTest,MainTest)109 TEST(ParseAddressWithNamedScopeIdTest, MainTest) {
110 grpc_init();
111 char* arbitrary_interface_name = static_cast<char*>(gpr_zalloc(IF_NAMESIZE));
112 // Per RFC 3493, an interface index is a "small positive integer starts at 1".
113 // Probe candidate interface index numbers until we find one that the
114 // system recognizes, and then use that for the test.
115 for (size_t i = 1; i < 65536; i++) {
116 if (if_indextoname(i, arbitrary_interface_name) != nullptr) {
117 gpr_log(GPR_DEBUG,
118 "Found interface at index %" PRIuPTR
119 " named %s. Will use this for the test",
120 i, arbitrary_interface_name);
121 break;
122 }
123 }
124 ASSERT_GT(strlen(arbitrary_interface_name), 0);
125 std::string target =
126 absl::StrFormat("ipv6:[fe80::1234%%%s]:12345", arbitrary_interface_name);
127 struct sockaddr_in6 result_from_getaddrinfo =
128 resolve_with_gettaddrinfo(target.c_str());
129 // Run the test
130 gpr_log(GPR_DEBUG,
131 "Run test_grpc_parse_ipv6_parity_with_getaddrinfo with target: %s",
132 target.c_str());
133 test_grpc_parse_ipv6_parity_with_getaddrinfo(target.c_str(),
134 result_from_getaddrinfo);
135 // Cleanup
136 gpr_free(arbitrary_interface_name);
137 grpc_shutdown();
138 }
139
main(int argc,char ** argv)140 int main(int argc, char** argv) {
141 grpc::testing::TestEnvironment env(&argc, argv);
142 ::testing::InitGoogleTest(&argc, argv);
143 return RUN_ALL_TESTS();
144 }
145