xref: /aosp_15_r20/external/grpc-grpc/test/core/event_engine/tcp_socket_utils_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "src/core/lib/event_engine/tcp_socket_utils.h"
15 
16 #include <errno.h>
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include "src/core/lib/iomgr/port.h"  // IWYU pragma: keep
21 
22 #ifdef GRPC_HAVE_VSOCK
23 #include <linux/vm_sockets.h>
24 #endif
25 
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/string_view.h"
32 
33 // IWYU pragma: no_include <arpa/inet.h>
34 
35 #include <string>
36 
37 #ifdef GRPC_HAVE_UNIX_SOCKET
38 #ifdef GPR_WINDOWS
39 // clang-format off
40 #include <ws2def.h>
41 #include <afunix.h>
42 // clang-format on
43 #else
44 #include <sys/un.h>
45 #endif  // GPR_WINDOWS
46 #endif  // GRPC_HAVE_UNIX_SOCKET
47 
48 #include "absl/status/status.h"
49 #include "absl/status/statusor.h"
50 #include "gtest/gtest.h"
51 
52 #include <grpc/event_engine/event_engine.h>
53 #include <grpc/support/log.h>
54 
55 #include "src/core/lib/iomgr/sockaddr.h"
56 
57 namespace grpc_event_engine {
58 namespace experimental {
59 
60 namespace {
61 const uint8_t kMapped[] = {0, 0, 0,    0,    0,   0, 0, 0,
62                            0, 0, 0xff, 0xff, 192, 0, 2, 1};
63 const uint8_t kNotQuiteMapped[] = {0, 0, 0,    0,    0,   0, 0, 0,
64                                    0, 0, 0xff, 0xfe, 192, 0, 2, 99};
65 const uint8_t kIPv4[] = {192, 0, 2, 1};
66 const uint8_t kIPv6[] = {0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
67                          0,    0,    0,    0,    0, 0, 0, 1};
68 
MakeAddr4(const uint8_t * data,size_t data_len)69 EventEngine::ResolvedAddress MakeAddr4(const uint8_t* data, size_t data_len) {
70   EventEngine::ResolvedAddress resolved_addr4;
71   sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(
72       const_cast<sockaddr*>(resolved_addr4.address()));
73   memset(&resolved_addr4, 0, sizeof(resolved_addr4));
74   addr4->sin_family = AF_INET;
75   GPR_ASSERT(data_len == sizeof(addr4->sin_addr.s_addr));
76   memcpy(&addr4->sin_addr.s_addr, data, data_len);
77   addr4->sin_port = htons(12345);
78   return EventEngine::ResolvedAddress(
79       reinterpret_cast<sockaddr*>(addr4),
80       static_cast<socklen_t>(sizeof(sockaddr_in)));
81 }
82 
MakeAddr6(const uint8_t * data,size_t data_len)83 EventEngine::ResolvedAddress MakeAddr6(const uint8_t* data, size_t data_len) {
84   EventEngine::ResolvedAddress resolved_addr6;
85   sockaddr_in6* addr6 = reinterpret_cast<sockaddr_in6*>(
86       const_cast<sockaddr*>(resolved_addr6.address()));
87   memset(&resolved_addr6, 0, sizeof(resolved_addr6));
88   addr6->sin6_family = AF_INET6;
89   GPR_ASSERT(data_len == sizeof(addr6->sin6_addr.s6_addr));
90   memcpy(&addr6->sin6_addr.s6_addr, data, data_len);
91   addr6->sin6_port = htons(12345);
92   return EventEngine::ResolvedAddress(
93       reinterpret_cast<sockaddr*>(addr6),
94       static_cast<socklen_t>(sizeof(sockaddr_in6)));
95 }
96 
SetIPv6ScopeId(EventEngine::ResolvedAddress & addr,uint32_t scope_id)97 void SetIPv6ScopeId(EventEngine::ResolvedAddress& addr, uint32_t scope_id) {
98   sockaddr_in6* addr6 =
99       reinterpret_cast<sockaddr_in6*>(const_cast<sockaddr*>(addr.address()));
100   ASSERT_EQ(addr6->sin6_family, AF_INET6);
101   addr6->sin6_scope_id = scope_id;
102 }
103 
104 #ifdef GRPC_HAVE_UNIX_SOCKET
UnixSockaddrPopulate(absl::string_view path)105 absl::StatusOr<EventEngine::ResolvedAddress> UnixSockaddrPopulate(
106     absl::string_view path) {
107   EventEngine::ResolvedAddress resolved_addr;
108   memset(const_cast<sockaddr*>(resolved_addr.address()), 0,
109          resolved_addr.size());
110   struct sockaddr_un* un = reinterpret_cast<struct sockaddr_un*>(
111       const_cast<sockaddr*>(resolved_addr.address()));
112   const size_t maxlen = sizeof(un->sun_path) - 1;
113   if (path.size() > maxlen) {
114     return absl::InternalError(absl::StrCat(
115         "Path name should not have more than ", maxlen, " characters"));
116   }
117   un->sun_family = AF_UNIX;
118   path.copy(un->sun_path, path.size());
119   un->sun_path[path.size()] = '\0';
120   return EventEngine::ResolvedAddress(reinterpret_cast<sockaddr*>(un),
121                                       static_cast<socklen_t>(sizeof(*un)));
122 }
123 
UnixAbstractSockaddrPopulate(absl::string_view path)124 absl::StatusOr<EventEngine::ResolvedAddress> UnixAbstractSockaddrPopulate(
125     absl::string_view path) {
126   EventEngine::ResolvedAddress resolved_addr;
127   memset(const_cast<sockaddr*>(resolved_addr.address()), 0,
128          resolved_addr.size());
129   struct sockaddr* addr = const_cast<sockaddr*>(resolved_addr.address());
130   struct sockaddr_un* un = reinterpret_cast<struct sockaddr_un*>(addr);
131   const size_t maxlen = sizeof(un->sun_path) - 1;
132   if (path.size() > maxlen) {
133     return absl::InternalError(absl::StrCat(
134         "Path name should not have more than ", maxlen, " characters"));
135   }
136   un->sun_family = AF_UNIX;
137   un->sun_path[0] = '\0';
138   path.copy(un->sun_path + 1, path.size());
139 #ifdef GPR_APPLE
140   return EventEngine::ResolvedAddress(
141       addr, static_cast<socklen_t>(sizeof(un->sun_len) +
142                                    sizeof(un->sun_family) + path.size() + 1));
143 #else
144   return EventEngine::ResolvedAddress(
145       addr, static_cast<socklen_t>(sizeof(un->sun_family) + path.size() + 1));
146 #endif
147 }
148 #endif  //  GRPC_HAVE_UNIX_SOCKET
149 
150 #ifdef GRPC_HAVE_VSOCK
VSockaddrPopulate(absl::string_view path)151 absl::StatusOr<EventEngine::ResolvedAddress> VSockaddrPopulate(
152     absl::string_view path) {
153   EventEngine::ResolvedAddress resolved_addr;
154   memset(const_cast<sockaddr*>(resolved_addr.address()), 0,
155          resolved_addr.size());
156   struct sockaddr_vm* vm = reinterpret_cast<struct sockaddr_vm*>(
157       const_cast<sockaddr*>(resolved_addr.address()));
158   vm->svm_family = AF_VSOCK;
159   std::string s = std::string(path);
160   if (sscanf(s.c_str(), "%u:%u", &vm->svm_cid, &vm->svm_port) != 2) {
161     return absl::InternalError(
162         absl::StrCat("Failed to parse vsock cid/port: ", s));
163   }
164   return EventEngine::ResolvedAddress(reinterpret_cast<sockaddr*>(vm),
165                                       static_cast<socklen_t>(sizeof(*vm)));
166 }
167 #endif  //  GRPC_HAVE_VSOCK
168 
169 }  // namespace
170 
TEST(TcpSocketUtilsTest,ResolvedAddressIsV4MappedTest)171 TEST(TcpSocketUtilsTest, ResolvedAddressIsV4MappedTest) {
172   // v4mapped input should succeed.
173   EventEngine::ResolvedAddress input6 = MakeAddr6(kMapped, sizeof(kMapped));
174   ASSERT_TRUE(ResolvedAddressIsV4Mapped(input6, nullptr));
175   EventEngine::ResolvedAddress output4;
176   ASSERT_TRUE(ResolvedAddressIsV4Mapped(input6, &output4));
177   EventEngine::ResolvedAddress expect4 = MakeAddr4(kIPv4, sizeof(kIPv4));
178   ASSERT_EQ(memcmp(expect4.address(), output4.address(), expect4.size()), 0);
179 
180   // Non-v4mapped input should fail.
181   input6 = MakeAddr6(kNotQuiteMapped, sizeof(kNotQuiteMapped));
182   ASSERT_FALSE(ResolvedAddressIsV4Mapped(input6, nullptr));
183   ASSERT_FALSE(ResolvedAddressIsV4Mapped(input6, &output4));
184   // Output is unchanged.
185   ASSERT_EQ(memcmp(expect4.address(), output4.address(), expect4.size()), 0);
186 
187   // Plain IPv4 input should also fail.
188   EventEngine::ResolvedAddress input4 = MakeAddr4(kIPv4, sizeof(kIPv4));
189   ASSERT_FALSE(ResolvedAddressIsV4Mapped(input4, nullptr));
190 }
191 
TEST(TcpSocketUtilsTest,ResolvedAddressToV4MappedTest)192 TEST(TcpSocketUtilsTest, ResolvedAddressToV4MappedTest) {
193   // IPv4 input should succeed.
194   EventEngine::ResolvedAddress input4 = MakeAddr4(kIPv4, sizeof(kIPv4));
195   EventEngine::ResolvedAddress output6;
196   ASSERT_TRUE(ResolvedAddressToV4Mapped(input4, &output6));
197   EventEngine::ResolvedAddress expect6 = MakeAddr6(kMapped, sizeof(kMapped));
198   ASSERT_EQ(memcmp(expect6.address(), output6.address(), output6.size()), 0);
199 
200   // IPv6 input should fail.
201   EventEngine::ResolvedAddress input6 = MakeAddr6(kIPv6, sizeof(kIPv6));
202   ASSERT_TRUE(!ResolvedAddressToV4Mapped(input6, &output6));
203   // Output is unchanged.
204   ASSERT_EQ(memcmp(expect6.address(), output6.address(), output6.size()), 0);
205 
206   // Already-v4mapped input should also fail.
207   input6 = MakeAddr6(kMapped, sizeof(kMapped));
208   ASSERT_TRUE(!ResolvedAddressToV4Mapped(input6, &output6));
209 }
210 
TEST(TcpSocketUtilsTest,ResolvedAddressToStringTest)211 TEST(TcpSocketUtilsTest, ResolvedAddressToStringTest) {
212   errno = 0x7EADBEEF;
213 
214   EventEngine::ResolvedAddress input4 = MakeAddr4(kIPv4, sizeof(kIPv4));
215   EXPECT_EQ(ResolvedAddressToString(input4).value(), "192.0.2.1:12345");
216   EventEngine::ResolvedAddress input6 = MakeAddr6(kIPv6, sizeof(kIPv6));
217   EXPECT_EQ(ResolvedAddressToString(input6).value(), "[2001:db8::1]:12345");
218   SetIPv6ScopeId(input6, 2);
219   EXPECT_EQ(ResolvedAddressToString(input6).value(), "[2001:db8::1%2]:12345");
220   SetIPv6ScopeId(input6, 101);
221   EXPECT_EQ(ResolvedAddressToString(input6).value(), "[2001:db8::1%101]:12345");
222   EventEngine::ResolvedAddress input6x = MakeAddr6(kMapped, sizeof(kMapped));
223   EXPECT_EQ(ResolvedAddressToString(input6x).value(),
224             "[::ffff:192.0.2.1]:12345");
225   EventEngine::ResolvedAddress input6y =
226       MakeAddr6(kNotQuiteMapped, sizeof(kNotQuiteMapped));
227   EXPECT_EQ(ResolvedAddressToString(input6y).value(),
228             "[::fffe:c000:263]:12345");
229   EventEngine::ResolvedAddress phony;
230   memset(const_cast<sockaddr*>(phony.address()), 0, phony.size());
231   sockaddr* phony_addr = const_cast<sockaddr*>(phony.address());
232   phony_addr->sa_family = 123;
233   EXPECT_EQ(ResolvedAddressToString(phony).status(),
234             absl::InvalidArgumentError("Unknown sockaddr family: 123"));
235 }
236 
TEST(TcpSocketUtilsTest,ResolvedAddressToNormalizedStringTest)237 TEST(TcpSocketUtilsTest, ResolvedAddressToNormalizedStringTest) {
238   errno = 0x7EADBEEF;
239 
240   EventEngine::ResolvedAddress input4 = MakeAddr4(kIPv4, sizeof(kIPv4));
241   EXPECT_EQ(ResolvedAddressToNormalizedString(input4).value(),
242             "192.0.2.1:12345");
243   EventEngine::ResolvedAddress input6 = MakeAddr6(kIPv6, sizeof(kIPv6));
244   EXPECT_EQ(ResolvedAddressToNormalizedString(input6).value(),
245             "[2001:db8::1]:12345");
246   SetIPv6ScopeId(input6, 2);
247   EXPECT_EQ(ResolvedAddressToNormalizedString(input6).value(),
248             "[2001:db8::1%2]:12345");
249   SetIPv6ScopeId(input6, 101);
250   EXPECT_EQ(ResolvedAddressToNormalizedString(input6).value(),
251             "[2001:db8::1%101]:12345");
252   EventEngine::ResolvedAddress input6x = MakeAddr6(kMapped, sizeof(kMapped));
253   EXPECT_EQ(ResolvedAddressToNormalizedString(input6x).value(),
254             "192.0.2.1:12345");
255   EventEngine::ResolvedAddress input6y =
256       MakeAddr6(kNotQuiteMapped, sizeof(kNotQuiteMapped));
257   EXPECT_EQ(ResolvedAddressToNormalizedString(input6y).value(),
258             "[::fffe:c000:263]:12345");
259   EventEngine::ResolvedAddress phony;
260   memset(const_cast<sockaddr*>(phony.address()), 0, phony.size());
261   sockaddr* phony_addr = const_cast<sockaddr*>(phony.address());
262   phony_addr->sa_family = 123;
263   EXPECT_EQ(ResolvedAddressToNormalizedString(phony).status(),
264             absl::InvalidArgumentError("Unknown sockaddr family: 123"));
265 
266 #ifdef GRPC_HAVE_UNIX_SOCKET
267   EventEngine::ResolvedAddress inputun =
268       *UnixSockaddrPopulate("/some/unix/path");
269   struct sockaddr_un* sock_un = reinterpret_cast<struct sockaddr_un*>(
270       const_cast<sockaddr*>(inputun.address()));
271   EXPECT_EQ(ResolvedAddressToNormalizedString(inputun).value(),
272             "/some/unix/path");
273   std::string max_filepath(sizeof(sock_un->sun_path) - 1, 'x');
274   inputun = *UnixSockaddrPopulate(max_filepath);
275   EXPECT_EQ(ResolvedAddressToNormalizedString(inputun).value(), max_filepath);
276   inputun = *UnixSockaddrPopulate(max_filepath);
277   sock_un->sun_path[sizeof(sockaddr_un::sun_path) - 1] = 'x';
278   EXPECT_EQ(ResolvedAddressToNormalizedString(inputun).status(),
279             absl::InvalidArgumentError("UDS path is not null-terminated"));
280   EventEngine::ResolvedAddress inputun2 =
281       *UnixAbstractSockaddrPopulate("some_unix_path");
282   EXPECT_EQ(ResolvedAddressToNormalizedString(inputun2).value(),
283             absl::StrCat(std::string(1, '\0'), "some_unix_path"));
284   std::string max_abspath(sizeof(sock_un->sun_path) - 1, '\0');
285   EventEngine::ResolvedAddress inputun3 =
286       *UnixAbstractSockaddrPopulate(max_abspath);
287   EXPECT_EQ(ResolvedAddressToNormalizedString(inputun3).value(),
288             absl::StrCat(std::string(1, '\0'), max_abspath));
289 #endif
290 
291 #ifdef GRPC_HAVE_VSOCK
292   EventEngine::ResolvedAddress inputvm = *VSockaddrPopulate("-1:12345");
293   EXPECT_EQ(ResolvedAddressToNormalizedString(inputvm).value(),
294             absl::StrCat((uint32_t)-1, ":12345"));
295 #endif
296 }
297 
TEST(TcpSocketUtilsTest,SockAddrPortTest)298 TEST(TcpSocketUtilsTest, SockAddrPortTest) {
299   EventEngine::ResolvedAddress wild6 = ResolvedAddressMakeWild6(20);
300   EventEngine::ResolvedAddress wild4 = ResolvedAddressMakeWild4(20);
301   // Verify the string description matches the expected wildcard address with
302   // correct port number.
303   EXPECT_EQ(ResolvedAddressToNormalizedString(wild6).value(), "[::]:20");
304   EXPECT_EQ(ResolvedAddressToNormalizedString(wild4).value(), "0.0.0.0:20");
305   // Update the port values.
306   ResolvedAddressSetPort(wild4, 21);
307   ResolvedAddressSetPort(wild6, 22);
308   // Read back the port values.
309   EXPECT_EQ(ResolvedAddressGetPort(wild4), 21);
310   EXPECT_EQ(ResolvedAddressGetPort(wild6), 22);
311   // Ensure the string description reflects the updated port values.
312   EXPECT_EQ(ResolvedAddressToNormalizedString(wild4).value(), "0.0.0.0:21");
313   EXPECT_EQ(ResolvedAddressToNormalizedString(wild6).value(), "[::]:22");
314 }
315 
TEST(TcpSocketUtilsTest,MaybeGetWildcardPortFromAddress)316 TEST(TcpSocketUtilsTest, MaybeGetWildcardPortFromAddress) {
317   EventEngine::ResolvedAddress wild4 = ResolvedAddressMakeWild4(20);
318   EventEngine::ResolvedAddress wild6 = ResolvedAddressMakeWild6(20);
319   auto v4_port = MaybeGetWildcardPortFromAddress(wild4);
320   ASSERT_TRUE(v4_port.has_value());
321   auto v6_port = MaybeGetWildcardPortFromAddress(wild6);
322   ASSERT_TRUE(v6_port.has_value());
323   wild4 = MakeAddr4(kIPv4, sizeof(kIPv4));
324   v4_port = MaybeGetWildcardPortFromAddress(wild4);
325   ASSERT_FALSE(v4_port.has_value());
326   wild6 = MakeAddr6(kMapped, sizeof(kMapped));
327   v6_port = MaybeGetWildcardPortFromAddress(wild6);
328   ASSERT_FALSE(v6_port.has_value());
329 }
330 
331 }  // namespace experimental
332 }  // namespace grpc_event_engine
333 
main(int argc,char ** argv)334 int main(int argc, char** argv) {
335   ::testing::InitGoogleTest(&argc, argv);
336   return RUN_ALL_TESTS();
337 }
338