• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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