1 //
2 //
3 // Copyright 2016 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 "src/core/lib/address_utils/sockaddr_utils.h"
20
21 #include <errno.h>
22 #include <grpc/support/port_platform.h>
23 #include <inttypes.h>
24
25 #include "absl/log/check.h"
26 #ifdef GRPC_HAVE_VSOCK
27 #include <linux/vm_sockets.h>
28 #endif
29 #include <string.h>
30
31 #include <string>
32 #include <utility>
33
34 #include "absl/log/log.h"
35 #include "absl/status/status.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/str_format.h"
38 #include "src/core/lib/iomgr/port.h"
39 #include "src/core/lib/iomgr/sockaddr.h"
40 #include "src/core/lib/iomgr/socket_utils.h"
41 #include "src/core/util/crash.h"
42 #include "src/core/util/host_port.h"
43 #include "src/core/util/uri.h"
44
45 #ifdef GRPC_HAVE_UNIX_SOCKET
46 #ifdef GPR_WINDOWS
47 // clang-format off
48 #include <ws2def.h>
49 #include <afunix.h>
50 // clang-format on
51 #else
52 #include <sys/un.h>
53 #endif // GPR_WINDOWS
54 #endif // GRPC_HAVE_UNIX_SOCKET
55
56 #ifdef GRPC_HAVE_UNIX_SOCKET
grpc_sockaddr_to_uri_unix_if_possible(const grpc_resolved_address * resolved_addr)57 static absl::StatusOr<std::string> grpc_sockaddr_to_uri_unix_if_possible(
58 const grpc_resolved_address* resolved_addr) {
59 const grpc_sockaddr* addr =
60 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
61 if (addr->sa_family != AF_UNIX) {
62 return absl::InvalidArgumentError(
63 absl::StrCat("Socket family is not AF_UNIX: ", addr->sa_family));
64 }
65 const auto* unix_addr = reinterpret_cast<const struct sockaddr_un*>(addr);
66 std::string scheme, path;
67 if (unix_addr->sun_path[0] == '\0' && unix_addr->sun_path[1] != '\0') {
68 scheme = "unix-abstract";
69 path = std::string(unix_addr->sun_path + 1,
70 resolved_addr->len - sizeof(unix_addr->sun_family) - 1);
71 } else {
72 scheme = "unix";
73 path = unix_addr->sun_path;
74 }
75 absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Create(
76 std::move(scheme), /*authority=*/"", std::move(path),
77 /*query_parameter_pairs=*/{}, /*fragment=*/"");
78 if (!uri.ok()) return uri.status();
79 return uri->ToString();
80 }
81 #else
grpc_sockaddr_to_uri_unix_if_possible(const grpc_resolved_address *)82 static absl::StatusOr<std::string> grpc_sockaddr_to_uri_unix_if_possible(
83 const grpc_resolved_address* /* addr */) {
84 return absl::InvalidArgumentError("Unix socket is not supported.");
85 }
86 #endif
87
88 #ifdef GRPC_HAVE_VSOCK
grpc_sockaddr_to_uri_vsock_if_possible(const grpc_resolved_address * resolved_addr)89 static absl::StatusOr<std::string> grpc_sockaddr_to_uri_vsock_if_possible(
90 const grpc_resolved_address* resolved_addr) {
91 const grpc_sockaddr* addr =
92 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
93 if (addr->sa_family != AF_VSOCK) {
94 return absl::InvalidArgumentError(
95 absl::StrCat("Socket family is not AF_VSOCK: ", addr->sa_family));
96 }
97 const auto* vsock_addr = reinterpret_cast<const struct sockaddr_vm*>(addr);
98 return absl::StrCat("vsock:", vsock_addr->svm_cid, ":", vsock_addr->svm_port);
99 }
100 #else
grpc_sockaddr_to_uri_vsock_if_possible(const grpc_resolved_address *)101 static absl::StatusOr<std::string> grpc_sockaddr_to_uri_vsock_if_possible(
102 const grpc_resolved_address* /* addr */) {
103 return absl::InvalidArgumentError("VSOCK is not supported.");
104 }
105 #endif
106
107 static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0xff, 0xff};
109
grpc_sockaddr_is_v4mapped(const grpc_resolved_address * resolved_addr,grpc_resolved_address * resolved_addr4_out)110 int grpc_sockaddr_is_v4mapped(const grpc_resolved_address* resolved_addr,
111 grpc_resolved_address* resolved_addr4_out) {
112 CHECK(resolved_addr != resolved_addr4_out);
113 const grpc_sockaddr* addr =
114 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
115 grpc_sockaddr_in* addr4_out =
116 resolved_addr4_out == nullptr
117 ? nullptr
118 : reinterpret_cast<grpc_sockaddr_in*>(resolved_addr4_out->addr);
119 if (addr->sa_family == GRPC_AF_INET6) {
120 const grpc_sockaddr_in6* addr6 =
121 reinterpret_cast<const grpc_sockaddr_in6*>(addr);
122 if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix,
123 sizeof(kV4MappedPrefix)) == 0) {
124 if (resolved_addr4_out != nullptr) {
125 // Normalize ::ffff:0.0.0.0/96 to IPv4.
126 memset(resolved_addr4_out, 0, sizeof(*resolved_addr4_out));
127 addr4_out->sin_family = GRPC_AF_INET;
128 // s6_addr32 would be nice, but it's non-standard.
129 memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4);
130 addr4_out->sin_port = addr6->sin6_port;
131 resolved_addr4_out->len =
132 static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
133 }
134 return 1;
135 }
136 }
137 return 0;
138 }
139
grpc_sockaddr_to_v4mapped(const grpc_resolved_address * resolved_addr,grpc_resolved_address * resolved_addr6_out)140 int grpc_sockaddr_to_v4mapped(const grpc_resolved_address* resolved_addr,
141 grpc_resolved_address* resolved_addr6_out) {
142 CHECK(resolved_addr != resolved_addr6_out);
143 const grpc_sockaddr* addr =
144 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
145 grpc_sockaddr_in6* addr6_out =
146 reinterpret_cast<grpc_sockaddr_in6*>(resolved_addr6_out->addr);
147 if (addr->sa_family == GRPC_AF_INET) {
148 const grpc_sockaddr_in* addr4 =
149 reinterpret_cast<const grpc_sockaddr_in*>(addr);
150 memset(resolved_addr6_out, 0, sizeof(*resolved_addr6_out));
151 addr6_out->sin6_family = GRPC_AF_INET6;
152 memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12);
153 memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4);
154 addr6_out->sin6_port = addr4->sin_port;
155 resolved_addr6_out->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
156 return 1;
157 }
158 return 0;
159 }
160
grpc_sockaddr_is_wildcard(const grpc_resolved_address * resolved_addr,int * port_out)161 int grpc_sockaddr_is_wildcard(const grpc_resolved_address* resolved_addr,
162 int* port_out) {
163 const grpc_sockaddr* addr;
164 grpc_resolved_address addr4_normalized;
165 if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr4_normalized)) {
166 resolved_addr = &addr4_normalized;
167 }
168 addr = reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
169 if (addr->sa_family == GRPC_AF_INET) {
170 // Check for 0.0.0.0
171 const grpc_sockaddr_in* addr4 =
172 reinterpret_cast<const grpc_sockaddr_in*>(addr);
173 if (addr4->sin_addr.s_addr != 0) {
174 return 0;
175 }
176 *port_out = grpc_ntohs(addr4->sin_port);
177 return 1;
178 } else if (addr->sa_family == GRPC_AF_INET6) {
179 // Check for ::
180 const grpc_sockaddr_in6* addr6 =
181 reinterpret_cast<const grpc_sockaddr_in6*>(addr);
182 int i;
183 for (i = 0; i < 16; i++) {
184 if (addr6->sin6_addr.s6_addr[i] != 0) {
185 return 0;
186 }
187 }
188 *port_out = grpc_ntohs(addr6->sin6_port);
189 return 1;
190 } else {
191 return 0;
192 }
193 }
194
grpc_sockaddr_make_wildcards(int port,grpc_resolved_address * wild4_out,grpc_resolved_address * wild6_out)195 void grpc_sockaddr_make_wildcards(int port, grpc_resolved_address* wild4_out,
196 grpc_resolved_address* wild6_out) {
197 grpc_sockaddr_make_wildcard4(port, wild4_out);
198 grpc_sockaddr_make_wildcard6(port, wild6_out);
199 }
200
grpc_sockaddr_make_wildcard4(int port,grpc_resolved_address * resolved_wild_out)201 void grpc_sockaddr_make_wildcard4(int port,
202 grpc_resolved_address* resolved_wild_out) {
203 grpc_sockaddr_in* wild_out =
204 reinterpret_cast<grpc_sockaddr_in*>(resolved_wild_out->addr);
205 CHECK(port >= 0);
206 CHECK(port < 65536);
207 memset(resolved_wild_out, 0, sizeof(*resolved_wild_out));
208 wild_out->sin_family = GRPC_AF_INET;
209 wild_out->sin_port = grpc_htons(static_cast<uint16_t>(port));
210 resolved_wild_out->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
211 }
212
grpc_sockaddr_make_wildcard6(int port,grpc_resolved_address * resolved_wild_out)213 void grpc_sockaddr_make_wildcard6(int port,
214 grpc_resolved_address* resolved_wild_out) {
215 grpc_sockaddr_in6* wild_out =
216 reinterpret_cast<grpc_sockaddr_in6*>(resolved_wild_out->addr);
217 CHECK(port >= 0);
218 CHECK(port < 65536);
219 memset(resolved_wild_out, 0, sizeof(*resolved_wild_out));
220 wild_out->sin6_family = GRPC_AF_INET6;
221 wild_out->sin6_port = grpc_htons(static_cast<uint16_t>(port));
222 resolved_wild_out->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
223 }
224
grpc_sockaddr_to_string(const grpc_resolved_address * resolved_addr,bool normalize)225 absl::StatusOr<std::string> grpc_sockaddr_to_string(
226 const grpc_resolved_address* resolved_addr, bool normalize) {
227 const int save_errno = errno;
228 grpc_resolved_address addr_normalized;
229 if (normalize && grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
230 resolved_addr = &addr_normalized;
231 }
232 const grpc_sockaddr* addr =
233 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
234 std::string out;
235 #ifdef GRPC_HAVE_UNIX_SOCKET
236 if (addr->sa_family == GRPC_AF_UNIX) {
237 const sockaddr_un* addr_un = reinterpret_cast<const sockaddr_un*>(addr);
238 bool abstract = addr_un->sun_path[0] == '\0';
239 if (abstract) {
240 int len = resolved_addr->len - sizeof(addr->sa_family);
241 if (len <= 0) {
242 return absl::InvalidArgumentError("empty UDS abstract path");
243 }
244 out = std::string(addr_un->sun_path, len);
245 } else {
246 size_t maxlen = sizeof(addr_un->sun_path);
247 if (strnlen(addr_un->sun_path, maxlen) == maxlen) {
248 return absl::InvalidArgumentError("UDS path is not null-terminated");
249 }
250 out = std::string(addr_un->sun_path);
251 }
252 return out;
253 }
254 #endif
255
256 #ifdef GRPC_HAVE_VSOCK
257 if (addr->sa_family == GRPC_AF_VSOCK) {
258 const sockaddr_vm* addr_vm = reinterpret_cast<const sockaddr_vm*>(addr);
259 out = absl::StrCat(addr_vm->svm_cid, ":", addr_vm->svm_port);
260 return out;
261 }
262 #endif
263
264 const void* ip = nullptr;
265 int port = 0;
266 uint32_t sin6_scope_id = 0;
267 if (addr->sa_family == GRPC_AF_INET) {
268 const grpc_sockaddr_in* addr4 =
269 reinterpret_cast<const grpc_sockaddr_in*>(addr);
270 ip = &addr4->sin_addr;
271 port = grpc_ntohs(addr4->sin_port);
272 } else if (addr->sa_family == GRPC_AF_INET6) {
273 const grpc_sockaddr_in6* addr6 =
274 reinterpret_cast<const grpc_sockaddr_in6*>(addr);
275 ip = &addr6->sin6_addr;
276 port = grpc_ntohs(addr6->sin6_port);
277 sin6_scope_id = addr6->sin6_scope_id;
278 }
279 char ntop_buf[GRPC_INET6_ADDRSTRLEN];
280 if (ip != nullptr && grpc_inet_ntop(addr->sa_family, ip, ntop_buf,
281 sizeof(ntop_buf)) != nullptr) {
282 if (sin6_scope_id != 0) {
283 // Enclose sin6_scope_id with the format defined in RFC 6874 section 2.
284 std::string host_with_scope =
285 absl::StrFormat("%s%%%" PRIu32, ntop_buf, sin6_scope_id);
286 out = grpc_core::JoinHostPort(host_with_scope, port);
287 } else {
288 out = grpc_core::JoinHostPort(ntop_buf, port);
289 }
290 } else {
291 return absl::InvalidArgumentError(
292 absl::StrCat("Unknown sockaddr family: ", addr->sa_family));
293 }
294 // This is probably redundant, but we wouldn't want to log the wrong error.
295 errno = save_errno;
296 return out;
297 }
298
grpc_sockaddr_to_uri(const grpc_resolved_address * resolved_addr)299 absl::StatusOr<std::string> grpc_sockaddr_to_uri(
300 const grpc_resolved_address* resolved_addr) {
301 if (resolved_addr->len == 0) {
302 return absl::InvalidArgumentError("Empty address");
303 }
304 grpc_resolved_address addr_normalized;
305 if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
306 resolved_addr = &addr_normalized;
307 }
308 const char* scheme = grpc_sockaddr_get_uri_scheme(resolved_addr);
309 if (scheme == nullptr) {
310 return absl::InvalidArgumentError("Unknown address type");
311 }
312 if (strcmp("unix", scheme) == 0) {
313 return grpc_sockaddr_to_uri_unix_if_possible(resolved_addr);
314 }
315 if (strcmp("vsock", scheme) == 0) {
316 return grpc_sockaddr_to_uri_vsock_if_possible(resolved_addr);
317 }
318
319 auto path = grpc_sockaddr_to_string(resolved_addr, false /* normalize */);
320 if (!path.ok()) return path;
321 absl::StatusOr<grpc_core::URI> uri =
322 grpc_core::URI::Create(scheme, /*authority=*/"", std::move(path.value()),
323 /*query_parameter_pairs=*/{}, /*fragment=*/"");
324 if (!uri.ok()) return uri.status();
325 return uri->ToString();
326 }
327
grpc_sockaddr_get_uri_scheme(const grpc_resolved_address * resolved_addr)328 const char* grpc_sockaddr_get_uri_scheme(
329 const grpc_resolved_address* resolved_addr) {
330 const grpc_sockaddr* addr =
331 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
332 switch (addr->sa_family) {
333 case GRPC_AF_INET:
334 return "ipv4";
335 case GRPC_AF_INET6:
336 return "ipv6";
337 case GRPC_AF_UNIX:
338 return "unix";
339 #ifdef GRPC_HAVE_VSOCK
340 case GRPC_AF_VSOCK:
341 return "vsock";
342 #endif
343 }
344 return nullptr;
345 }
346
grpc_sockaddr_get_family(const grpc_resolved_address * resolved_addr)347 int grpc_sockaddr_get_family(const grpc_resolved_address* resolved_addr) {
348 const grpc_sockaddr* addr =
349 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
350 return addr->sa_family;
351 }
352
grpc_sockaddr_get_port(const grpc_resolved_address * resolved_addr)353 int grpc_sockaddr_get_port(const grpc_resolved_address* resolved_addr) {
354 const grpc_sockaddr* addr =
355 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
356 switch (addr->sa_family) {
357 case GRPC_AF_INET:
358 return grpc_ntohs(
359 (reinterpret_cast<const grpc_sockaddr_in*>(addr))->sin_port);
360 case GRPC_AF_INET6:
361 return grpc_ntohs(
362 (reinterpret_cast<const grpc_sockaddr_in6*>(addr))->sin6_port);
363 #ifdef GRPC_HAVE_UNIX_SOCKET
364 case AF_UNIX:
365 return 1;
366 #endif
367 #ifdef GRPC_HAVE_VSOCK
368 case AF_VSOCK:
369 return 1;
370 #endif
371 default:
372 LOG(ERROR) << "Unknown socket family " << addr->sa_family
373 << " in grpc_sockaddr_get_port";
374 return 0;
375 }
376 }
377
grpc_sockaddr_set_port(grpc_resolved_address * resolved_addr,int port)378 int grpc_sockaddr_set_port(grpc_resolved_address* resolved_addr, int port) {
379 grpc_sockaddr* addr = reinterpret_cast<grpc_sockaddr*>(resolved_addr->addr);
380 switch (addr->sa_family) {
381 case GRPC_AF_INET:
382 CHECK(port >= 0);
383 CHECK(port < 65536);
384 (reinterpret_cast<grpc_sockaddr_in*>(addr))->sin_port =
385 grpc_htons(static_cast<uint16_t>(port));
386 return 1;
387 case GRPC_AF_INET6:
388 CHECK(port >= 0);
389 CHECK(port < 65536);
390 (reinterpret_cast<grpc_sockaddr_in6*>(addr))->sin6_port =
391 grpc_htons(static_cast<uint16_t>(port));
392 return 1;
393 default:
394 LOG(ERROR) << "Unknown socket family " << addr->sa_family
395 << " in grpc_sockaddr_set_port";
396 return 0;
397 }
398 }
399
grpc_sockaddr_get_packed_host(const grpc_resolved_address * resolved_addr)400 std::string grpc_sockaddr_get_packed_host(
401 const grpc_resolved_address* resolved_addr) {
402 const grpc_sockaddr* addr =
403 reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
404 if (addr->sa_family == GRPC_AF_INET) {
405 const grpc_sockaddr_in* addr4 =
406 reinterpret_cast<const grpc_sockaddr_in*>(addr);
407 const char* addr_bytes = reinterpret_cast<const char*>(&addr4->sin_addr);
408 return std::string(addr_bytes, 4);
409 } else if (addr->sa_family == GRPC_AF_INET6) {
410 const grpc_sockaddr_in6* addr6 =
411 reinterpret_cast<const grpc_sockaddr_in6*>(addr);
412 const char* addr_bytes = reinterpret_cast<const char*>(&addr6->sin6_addr);
413 return std::string(addr_bytes, 16);
414 } else {
415 grpc_core::Crash("unknown socket family");
416 }
417 }
418
grpc_sockaddr_mask_bits(grpc_resolved_address * address,uint32_t mask_bits)419 void grpc_sockaddr_mask_bits(grpc_resolved_address* address,
420 uint32_t mask_bits) {
421 grpc_sockaddr* addr = reinterpret_cast<grpc_sockaddr*>(address->addr);
422 if (addr->sa_family == GRPC_AF_INET) {
423 grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(addr);
424 if (mask_bits == 0) {
425 memset(&addr4->sin_addr, 0, sizeof(addr4->sin_addr));
426 return;
427 } else if (mask_bits >= 32) {
428 return;
429 }
430 uint32_t mask_ip_addr = (~(uint32_t{0})) << (32 - mask_bits);
431 addr4->sin_addr.s_addr &= grpc_htonl(mask_ip_addr);
432 } else if (addr->sa_family == GRPC_AF_INET6) {
433 grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(addr);
434 if (mask_bits == 0) {
435 memset(&addr6->sin6_addr, 0, sizeof(addr6->sin6_addr));
436 return;
437 } else if (mask_bits >= 128) {
438 return;
439 }
440 // We cannot use s6_addr32 since it is not defined on all platforms that we
441 // need it on.
442 uint32_t address_parts[4];
443 CHECK(sizeof(addr6->sin6_addr) == sizeof(address_parts));
444 memcpy(address_parts, &addr6->sin6_addr, sizeof(grpc_in6_addr));
445 if (mask_bits <= 32) {
446 uint32_t mask_ip_addr = (~(uint32_t{0})) << (32 - mask_bits);
447 address_parts[0] &= grpc_htonl(mask_ip_addr);
448 memset(&address_parts[1], 0, sizeof(uint32_t));
449 memset(&address_parts[2], 0, sizeof(uint32_t));
450 memset(&address_parts[3], 0, sizeof(uint32_t));
451 } else if (mask_bits <= 64) {
452 mask_bits -= 32;
453 uint32_t mask_ip_addr = (~(uint32_t{0})) << (32 - mask_bits);
454 address_parts[1] &= grpc_htonl(mask_ip_addr);
455 memset(&address_parts[2], 0, sizeof(uint32_t));
456 memset(&address_parts[3], 0, sizeof(uint32_t));
457 } else if (mask_bits <= 96) {
458 mask_bits -= 64;
459 uint32_t mask_ip_addr = (~(uint32_t{0})) << (32 - mask_bits);
460 address_parts[2] &= grpc_htonl(mask_ip_addr);
461 memset(&address_parts[3], 0, sizeof(uint32_t));
462 } else {
463 mask_bits -= 96;
464 uint32_t mask_ip_addr = (~(uint32_t{0})) << (32 - mask_bits);
465 address_parts[3] &= grpc_htonl(mask_ip_addr);
466 }
467 memcpy(&addr6->sin6_addr, address_parts, sizeof(grpc_in6_addr));
468 }
469 }
470
grpc_sockaddr_match_subnet(const grpc_resolved_address * address,const grpc_resolved_address * subnet_address,uint32_t mask_bits)471 bool grpc_sockaddr_match_subnet(const grpc_resolved_address* address,
472 const grpc_resolved_address* subnet_address,
473 uint32_t mask_bits) {
474 auto* addr = reinterpret_cast<const grpc_sockaddr*>(address->addr);
475 auto* subnet_addr =
476 reinterpret_cast<const grpc_sockaddr*>(subnet_address->addr);
477 if (addr->sa_family != subnet_addr->sa_family) return false;
478 grpc_resolved_address masked_address;
479 memcpy(&masked_address, address, sizeof(grpc_resolved_address));
480 addr = reinterpret_cast<grpc_sockaddr*>((&masked_address)->addr);
481 grpc_sockaddr_mask_bits(&masked_address, mask_bits);
482 if (addr->sa_family == GRPC_AF_INET) {
483 auto* addr4 = reinterpret_cast<const grpc_sockaddr_in*>(addr);
484 auto* subnet_addr4 = reinterpret_cast<const grpc_sockaddr_in*>(subnet_addr);
485 if (memcmp(&addr4->sin_addr, &subnet_addr4->sin_addr,
486 sizeof(addr4->sin_addr)) == 0) {
487 return true;
488 }
489 } else if (addr->sa_family == GRPC_AF_INET6) {
490 auto* addr6 = reinterpret_cast<const grpc_sockaddr_in6*>(addr);
491 auto* subnet_addr6 =
492 reinterpret_cast<const grpc_sockaddr_in6*>(subnet_addr);
493 if (memcmp(&addr6->sin6_addr, &subnet_addr6->sin6_addr,
494 sizeof(addr6->sin6_addr)) == 0) {
495 return true;
496 }
497 }
498 return false;
499 }
500