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