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