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