1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #define _WINSOCK_DEPRECATED_NO_WARNINGS // we need to use inet_addr instead of inet_pton
8
9 #include "td/utils/port/IPAddress.h"
10
11 #include "td/utils/format.h"
12 #include "td/utils/logging.h"
13 #include "td/utils/misc.h"
14 #include "td/utils/port/SocketFd.h"
15 #include "td/utils/port/thread_local.h"
16 #include "td/utils/ScopeGuard.h"
17 #include "td/utils/Slice.h"
18 #include "td/utils/SliceBuilder.h"
19 #include "td/utils/utf8.h"
20
21 #if TD_WINDOWS
22 #include "td/utils/port/wstring_convert.h"
23 #else
24 #include <netdb.h>
25 #include <netinet/tcp.h>
26 #include <sys/types.h>
27 #endif
28
29 #include <cstring>
30 #include <limits>
31
32 namespace td {
33
is_ascii_host_char(char c)34 static bool is_ascii_host_char(char c) {
35 return static_cast<unsigned char>(c) <= 127;
36 }
37
is_ascii_host(Slice host)38 static bool is_ascii_host(Slice host) {
39 for (auto c : host) {
40 if (!is_ascii_host_char(c)) {
41 return false;
42 }
43 }
44 return true;
45 }
46
47 #if !TD_WINDOWS
punycode(string & result,Slice part)48 static void punycode(string &result, Slice part) {
49 vector<uint32> codes;
50 codes.reserve(utf8_length(part));
51 uint32 processed = 0;
52 auto begin = part.ubegin();
53 auto end = part.uend();
54 while (begin != end) {
55 uint32 code;
56 begin = next_utf8_unsafe(begin, &code, "punycode");
57 if (code <= 127u) {
58 result += to_lower(static_cast<char>(code));
59 processed++;
60 }
61 codes.push_back(code);
62 }
63
64 if (processed > 0) {
65 result += '-';
66 }
67
68 uint32 n = 127;
69 uint32 delta = 0;
70 int bias = -72;
71 bool is_first = true;
72 while (processed < codes.size()) {
73 // choose lowest not processed code
74 uint32 next_n = 0x110000;
75 for (auto code : codes) {
76 if (code > n && code < next_n) {
77 next_n = code;
78 }
79 }
80 delta += (next_n - n - 1) * (processed + 1);
81
82 for (auto code : codes) {
83 if (code < next_n) {
84 delta++;
85 }
86
87 if (code == next_n) {
88 // found next symbol, encode delta
89 auto left = static_cast<int>(delta);
90 while (true) {
91 bias += 36;
92 auto t = clamp(bias, 1, 26);
93 if (left < t) {
94 result += static_cast<char>(left + 'a');
95 break;
96 }
97
98 left -= t;
99 auto digit = t + left % (36 - t);
100 result += static_cast<char>(digit < 26 ? digit + 'a' : digit - 26 + '0');
101 left /= 36 - t;
102 }
103 processed++;
104
105 // update bias
106 if (is_first) {
107 delta /= 700;
108 is_first = false;
109 } else {
110 delta /= 2;
111 }
112 delta += delta / processed;
113
114 bias = 0;
115 while (delta > 35 * 13) {
116 delta /= 35;
117 bias -= 36;
118 }
119 bias -= static_cast<int>(36 * delta / (delta + 38));
120 delta = 0;
121 }
122 }
123
124 delta++;
125 n = next_n;
126 }
127 }
128 #endif
129
idn_to_ascii(CSlice host)130 Result<string> idn_to_ascii(CSlice host) {
131 if (is_ascii_host(host)) {
132 return to_lower(host);
133 }
134 if (!check_utf8(host)) {
135 return Status::Error("Host name must be encoded in UTF-8");
136 }
137
138 const int MAX_DNS_NAME_LENGTH = 255;
139 if (host.size() >= MAX_DNS_NAME_LENGTH * 4) { // upper bound, 4 characters per symbol
140 return Status::Error("Host name is too long");
141 }
142
143 #if TD_WINDOWS
144 TRY_RESULT(whost, to_wstring(host));
145 wchar_t punycode[MAX_DNS_NAME_LENGTH + 1];
146 int result_length =
147 IdnToAscii(IDN_ALLOW_UNASSIGNED, whost.c_str(), narrow_cast<int>(whost.size()), punycode, MAX_DNS_NAME_LENGTH);
148 if (result_length == 0) {
149 return Status::Error("Host can't be converted to ASCII");
150 }
151
152 TRY_RESULT(idn_host, from_wstring(punycode, result_length));
153 return idn_host;
154 #else
155 auto parts = full_split(Slice(host), '.');
156 bool is_first = true;
157 string result;
158 result.reserve(host.size());
159 for (auto part : parts) {
160 if (!is_first) {
161 result += '.';
162 }
163 if (is_ascii_host(part)) {
164 result.append(part.data(), part.size());
165 } else {
166 // TODO nameprep should be applied first, but punycode is better than nothing.
167 // It is better to use libidn/ICU here if available
168 result += "xn--";
169 punycode(result, part);
170 }
171 is_first = false;
172 }
173 return result;
174 #endif
175 }
176
get_ip_str(int family,const void * addr)177 static CSlice get_ip_str(int family, const void *addr) {
178 const int buf_size = INET6_ADDRSTRLEN;
179 static TD_THREAD_LOCAL char *buf;
180 init_thread_local<char[]>(buf, buf_size);
181
182 const char *res = inet_ntop(family,
183 #if TD_WINDOWS
184 const_cast<PVOID>(addr),
185 #else
186 addr,
187 #endif
188 buf, buf_size);
189 if (res == nullptr) {
190 return CSlice();
191 } else {
192 return CSlice(res);
193 }
194 }
195
IPAddress()196 IPAddress::IPAddress() : is_valid_(false) {
197 }
198
is_valid() const199 bool IPAddress::is_valid() const {
200 return is_valid_;
201 }
202
is_reserved() const203 bool IPAddress::is_reserved() const {
204 CHECK(is_valid());
205
206 if (is_ipv6()) {
207 // TODO proper check for reserved IPv6 addresses
208 return true;
209 }
210
211 uint32 ip = get_ipv4();
212 struct IpBlock {
213 CSlice ip;
214 int mask;
215 IpBlock(CSlice ip, int mask) : ip(ip), mask(mask) {
216 }
217 };
218 static const IpBlock blocks[] = {{"0.0.0.0", 8}, {"10.0.0.0", 8}, {"100.64.0.0", 10}, {"127.0.0.0", 8},
219 {"169.254.0.0", 16}, {"172.16.0.0", 12}, {"192.0.0.0", 24}, {"192.0.2.0", 24},
220 {"192.88.99.0", 24}, {"192.168.0.0", 16}, {"198.18.0.0", 15}, {"198.51.100.0", 24},
221 {"203.0.113.0", 24}, {"224.0.0.0", 3}};
222 for (auto &block : blocks) {
223 IPAddress block_ip_address;
224 block_ip_address.init_ipv4_port(block.ip, 80).ensure();
225 uint32 range = block_ip_address.get_ipv4();
226 CHECK(block.mask != 0);
227 uint32 mask = std::numeric_limits<uint32>::max() >> (32 - block.mask) << (32 - block.mask);
228 if ((ip & mask) == (range & mask)) {
229 return true;
230 }
231 }
232 return false;
233 }
234
get_sockaddr() const235 const sockaddr *IPAddress::get_sockaddr() const {
236 CHECK(is_valid());
237 return &sockaddr_;
238 }
239
get_sockaddr_len() const240 size_t IPAddress::get_sockaddr_len() const {
241 CHECK(is_valid());
242 switch (sockaddr_.sa_family) {
243 case AF_INET6:
244 return sizeof(ipv6_addr_);
245 case AF_INET:
246 return sizeof(ipv4_addr_);
247 default:
248 UNREACHABLE();
249 return 0;
250 }
251 }
252
get_address_family() const253 int IPAddress::get_address_family() const {
254 return get_sockaddr()->sa_family;
255 }
256
is_ipv4() const257 bool IPAddress::is_ipv4() const {
258 return is_valid() && get_address_family() == AF_INET;
259 }
260
is_ipv6() const261 bool IPAddress::is_ipv6() const {
262 return is_valid() && get_address_family() == AF_INET6;
263 }
264
get_ipv4() const265 uint32 IPAddress::get_ipv4() const {
266 CHECK(is_valid());
267 CHECK(is_ipv4());
268 return htonl(ipv4_addr_.sin_addr.s_addr);
269 }
270
get_ipv6() const271 string IPAddress::get_ipv6() const {
272 static_assert(sizeof(ipv6_addr_.sin6_addr) == 16, "ipv6 size == 16");
273 CHECK(is_valid());
274 CHECK(!is_ipv4());
275 return Slice(ipv6_addr_.sin6_addr.s6_addr, 16).str();
276 }
277
get_any_addr() const278 IPAddress IPAddress::get_any_addr() const {
279 IPAddress res;
280 switch (get_address_family()) {
281 case AF_INET6:
282 res.init_ipv6_any();
283 break;
284 case AF_INET:
285 res.init_ipv4_any();
286 break;
287 default:
288 UNREACHABLE();
289 break;
290 }
291 return res;
292 }
293
init_ipv4_any()294 void IPAddress::init_ipv4_any() {
295 is_valid_ = true;
296 std::memset(&ipv4_addr_, 0, sizeof(ipv4_addr_));
297 ipv4_addr_.sin_family = AF_INET;
298 ipv4_addr_.sin_addr.s_addr = INADDR_ANY;
299 ipv4_addr_.sin_port = 0;
300 }
301
init_ipv6_any()302 void IPAddress::init_ipv6_any() {
303 is_valid_ = true;
304 std::memset(&ipv6_addr_, 0, sizeof(ipv6_addr_));
305 ipv6_addr_.sin6_family = AF_INET6;
306 ipv6_addr_.sin6_addr = in6addr_any;
307 ipv6_addr_.sin6_port = 0;
308 }
309
init_ipv6_port(CSlice ipv6,int port)310 Status IPAddress::init_ipv6_port(CSlice ipv6, int port) {
311 is_valid_ = false;
312 if (port <= 0 || port >= (1 << 16)) {
313 return Status::Error(PSLICE() << "Invalid [IPv6 address port=" << port << "]");
314 }
315 string ipv6_plain;
316 if (ipv6.size() > 2 && ipv6[0] == '[' && ipv6.back() == ']') {
317 ipv6_plain.assign(ipv6.begin() + 1, ipv6.size() - 2);
318 ipv6 = ipv6_plain;
319 }
320 std::memset(&ipv6_addr_, 0, sizeof(ipv6_addr_));
321 ipv6_addr_.sin6_family = AF_INET6;
322 ipv6_addr_.sin6_port = htons(static_cast<uint16>(port));
323 int err = inet_pton(AF_INET6, ipv6.c_str(), &ipv6_addr_.sin6_addr);
324 if (err == 0) {
325 return Status::Error(PSLICE() << "Failed inet_pton(AF_INET6, " << ipv6 << ")");
326 } else if (err == -1) {
327 return OS_SOCKET_ERROR(PSLICE() << "Failed inet_pton(AF_INET6, " << ipv6 << ")");
328 }
329 is_valid_ = true;
330 return Status::OK();
331 }
332
init_ipv6_as_ipv4_port(CSlice ipv4,int port)333 Status IPAddress::init_ipv6_as_ipv4_port(CSlice ipv4, int port) {
334 return init_ipv6_port(string("::FFFF:").append(ipv4.begin(), ipv4.size()), port);
335 }
336
init_ipv4_port(CSlice ipv4,int port)337 Status IPAddress::init_ipv4_port(CSlice ipv4, int port) {
338 is_valid_ = false;
339 if (port <= 0 || port >= (1 << 16)) {
340 return Status::Error(PSLICE() << "Invalid [IPv4 address port=" << port << "]");
341 }
342 std::memset(&ipv4_addr_, 0, sizeof(ipv4_addr_));
343 ipv4_addr_.sin_family = AF_INET;
344 ipv4_addr_.sin_port = htons(static_cast<uint16>(port));
345 int err = inet_pton(AF_INET, ipv4.c_str(), &ipv4_addr_.sin_addr);
346 if (err == 0) {
347 return Status::Error(PSLICE() << "Failed inet_pton(AF_INET, " << ipv4 << ")");
348 } else if (err == -1) {
349 return OS_SOCKET_ERROR(PSLICE() << "Failed inet_pton(AF_INET, " << ipv4 << ")");
350 }
351 is_valid_ = true;
352 return Status::OK();
353 }
354
get_ip_address(CSlice host)355 Result<IPAddress> IPAddress::get_ip_address(CSlice host) {
356 auto r_address = get_ipv4_address(host);
357 if (r_address.is_ok()) {
358 return r_address.move_as_ok();
359 }
360 r_address = get_ipv6_address(host);
361 if (r_address.is_ok()) {
362 return r_address.move_as_ok();
363 }
364 return Status::Error(PSLICE() << '"' << host << "\" is not a valid IP address");
365 }
366
get_ipv4_address(CSlice host)367 Result<IPAddress> IPAddress::get_ipv4_address(CSlice host) {
368 // sometimes inet_addr allows much more valid IPv4 hosts than inet_pton,
369 // like 0x12.0x34.0x56.0x78, or 0x12345678, or 0x7f.001
370 auto ipv4_numeric_addr = inet_addr(host.c_str());
371 if (ipv4_numeric_addr == INADDR_NONE) {
372 return Status::Error(PSLICE() << '"' << host << "\" is not a valid IPv4 address");
373 }
374
375 host = ::td::get_ip_str(AF_INET, &ipv4_numeric_addr);
376 IPAddress result;
377 auto status = result.init_ipv4_port(host, 1);
378 if (status.is_error()) {
379 return std::move(status);
380 }
381 return std::move(result);
382 }
383
get_ipv6_address(CSlice host)384 Result<IPAddress> IPAddress::get_ipv6_address(CSlice host) {
385 IPAddress result;
386 auto status = result.init_ipv6_port(host, 1);
387 if (status.is_error()) {
388 return Status::Error(PSLICE() << '"' << host << "\" is not a valid IPv6 address");
389 }
390 return std::move(result);
391 }
392
init_host_port(CSlice host,int port,bool prefer_ipv6)393 Status IPAddress::init_host_port(CSlice host, int port, bool prefer_ipv6) {
394 if (host.size() > 2 && host[0] == '[' && host.back() == ']') {
395 return init_ipv6_port(host, port == 0 ? 1 : port);
396 }
397
398 return init_host_port(host, PSLICE() << port, prefer_ipv6);
399 }
400
init_host_port(CSlice host,CSlice port,bool prefer_ipv6)401 Status IPAddress::init_host_port(CSlice host, CSlice port, bool prefer_ipv6) {
402 is_valid_ = false;
403 if (host.empty()) {
404 return Status::Error("Host is empty");
405 }
406 #if TD_WINDOWS
407 if (host == "..localmachine") {
408 return Status::Error("Host is invalid");
409 }
410 #endif
411 TRY_RESULT(ascii_host, idn_to_ascii(host));
412 host = ascii_host; // assign string to CSlice
413
414 if (host[0] == '[' && host.back() == ']') {
415 auto port_int = to_integer<int>(port);
416 return init_ipv6_port(host, port_int == 0 ? 1 : port_int);
417 }
418
419 // some getaddrinfo implementations use inet_pton instead of inet_aton and support only decimal-dotted IPv4 form,
420 // and so doesn't recognize 0x12.0x34.0x56.0x78, or 0x12345678, or 0x7f.001 as valid IPv4 addresses
421 auto ipv4_numeric_addr = inet_addr(host.c_str());
422 if (ipv4_numeric_addr != INADDR_NONE) {
423 host = ::td::get_ip_str(AF_INET, &ipv4_numeric_addr);
424 }
425
426 addrinfo hints;
427 addrinfo *info = nullptr;
428 std::memset(&hints, 0, sizeof(hints));
429 hints.ai_family = AF_UNSPEC;
430 hints.ai_socktype = SOCK_STREAM;
431 hints.ai_protocol = IPPROTO_TCP;
432 LOG(DEBUG + 10) << "Trying to init IP address of " << host << " with port " << port;
433 auto err = getaddrinfo(host.c_str(), port.c_str(), &hints, &info);
434 if (err != 0) {
435 #if TD_WINDOWS
436 return OS_SOCKET_ERROR("Failed to resolve host");
437 #else
438 return Status::Error(PSLICE() << "Failed to resolve host: " << gai_strerror(err));
439 #endif
440 }
441 SCOPE_EXIT {
442 freeaddrinfo(info);
443 };
444
445 addrinfo *best_info = nullptr;
446 for (auto *ptr = info; ptr != nullptr; ptr = ptr->ai_next) {
447 if (ptr->ai_family == AF_INET && (!prefer_ipv6 || best_info == nullptr)) {
448 // just use first IPv4 address if there is no IPv6 and it isn't preferred
449 best_info = ptr;
450 if (!prefer_ipv6) {
451 break;
452 }
453 }
454 if (ptr->ai_family == AF_INET6 && (prefer_ipv6 || best_info == nullptr)) {
455 // or first IPv6 address if there is no IPv4 and it isn't preferred
456 best_info = ptr;
457 if (prefer_ipv6) {
458 break;
459 }
460 }
461 }
462 if (best_info == nullptr) {
463 return Status::Error("Failed to find IPv4/IPv6 address");
464 }
465 return init_sockaddr(best_info->ai_addr, narrow_cast<socklen_t>(best_info->ai_addrlen));
466 }
467
init_host_port(CSlice host_port)468 Status IPAddress::init_host_port(CSlice host_port) {
469 auto pos = host_port.rfind(':');
470 if (pos == static_cast<size_t>(-1)) {
471 return Status::Error("Can't split string into host and port");
472 }
473 return init_host_port(host_port.substr(0, pos).str(), host_port.substr(pos + 1).str());
474 }
475
init_sockaddr(sockaddr * addr)476 Status IPAddress::init_sockaddr(sockaddr *addr) {
477 if (addr->sa_family == AF_INET6) {
478 return init_sockaddr(addr, sizeof(ipv6_addr_));
479 } else if (addr->sa_family == AF_INET) {
480 return init_sockaddr(addr, sizeof(ipv4_addr_));
481 } else {
482 return init_sockaddr(addr, 0);
483 }
484 }
init_sockaddr(sockaddr * addr,socklen_t len)485 Status IPAddress::init_sockaddr(sockaddr *addr, socklen_t len) {
486 if (addr->sa_family == AF_INET6) {
487 CHECK(len == sizeof(ipv6_addr_));
488 std::memcpy(&ipv6_addr_, reinterpret_cast<sockaddr_in6 *>(addr), sizeof(ipv6_addr_));
489 } else if (addr->sa_family == AF_INET) {
490 CHECK(len == sizeof(ipv4_addr_));
491 std::memcpy(&ipv4_addr_, reinterpret_cast<sockaddr_in *>(addr), sizeof(ipv4_addr_));
492 } else {
493 return Status::Error(PSLICE() << "Unknown " << tag("sa_family", addr->sa_family));
494 }
495
496 is_valid_ = true;
497 LOG(DEBUG + 10) << "Have address " << get_ip_str() << " with port " << get_port();
498 return Status::OK();
499 }
500
init_socket_address(const SocketFd & socket_fd)501 Status IPAddress::init_socket_address(const SocketFd &socket_fd) {
502 is_valid_ = false;
503 if (socket_fd.empty()) {
504 return Status::Error("Socket is empty");
505 }
506 auto socket = socket_fd.get_native_fd().socket();
507 socklen_t len = storage_size();
508 int ret = getsockname(socket, &sockaddr_, &len);
509 if (ret != 0) {
510 return OS_SOCKET_ERROR("Failed to get socket address");
511 }
512 is_valid_ = true;
513 return Status::OK();
514 }
515
init_peer_address(const SocketFd & socket_fd)516 Status IPAddress::init_peer_address(const SocketFd &socket_fd) {
517 is_valid_ = false;
518 if (socket_fd.empty()) {
519 return Status::Error("Socket is empty");
520 }
521 auto socket = socket_fd.get_native_fd().socket();
522 socklen_t len = storage_size();
523 int ret = getpeername(socket, &sockaddr_, &len);
524 if (ret != 0) {
525 return OS_SOCKET_ERROR("Failed to get peer socket address");
526 }
527 is_valid_ = true;
528 return Status::OK();
529 }
530
clear_ipv6_interface()531 void IPAddress::clear_ipv6_interface() {
532 if (!is_valid() || get_address_family() != AF_INET6) {
533 return;
534 }
535
536 auto *begin = ipv6_addr_.sin6_addr.s6_addr;
537 static_assert(sizeof(ipv6_addr_.sin6_addr.s6_addr) == 16, "expected 16 bytes buffer for ipv6");
538 static_assert(sizeof(*begin) == 1, "expected array of bytes");
539 std::memset(begin + 8, 0, 8 * sizeof(*begin));
540 }
541
ipv4_to_str(uint32 ipv4)542 string IPAddress::ipv4_to_str(uint32 ipv4) {
543 ipv4 = ntohl(ipv4);
544 return ::td::get_ip_str(AF_INET, &ipv4).str();
545 }
546
ipv6_to_str(Slice ipv6)547 string IPAddress::ipv6_to_str(Slice ipv6) {
548 CHECK(ipv6.size() == 16);
549 return ::td::get_ip_str(AF_INET6, ipv6.ubegin()).str();
550 }
551
get_ip_str() const552 CSlice IPAddress::get_ip_str() const {
553 if (!is_valid()) {
554 return CSlice("0.0.0.0");
555 }
556
557 switch (get_address_family()) {
558 case AF_INET6:
559 return ::td::get_ip_str(AF_INET6, &ipv6_addr_.sin6_addr);
560 case AF_INET:
561 return ::td::get_ip_str(AF_INET, &ipv4_addr_.sin_addr);
562 default:
563 UNREACHABLE();
564 return CSlice();
565 }
566 }
567
get_ip_host() const568 string IPAddress::get_ip_host() const {
569 if (!is_valid()) {
570 return "0.0.0.0";
571 }
572
573 switch (get_address_family()) {
574 case AF_INET6:
575 return PSTRING() << '[' << ::td::get_ip_str(AF_INET6, &ipv6_addr_.sin6_addr) << ']';
576 case AF_INET:
577 return ::td::get_ip_str(AF_INET, &ipv4_addr_.sin_addr).str();
578 default:
579 UNREACHABLE();
580 return string();
581 }
582 }
583
get_port() const584 int IPAddress::get_port() const {
585 if (!is_valid()) {
586 return 0;
587 }
588
589 switch (get_address_family()) {
590 case AF_INET6:
591 return ntohs(ipv6_addr_.sin6_port);
592 case AF_INET:
593 return ntohs(ipv4_addr_.sin_port);
594 default:
595 UNREACHABLE();
596 return 0;
597 }
598 }
599
set_port(int port)600 void IPAddress::set_port(int port) {
601 CHECK(is_valid());
602
603 switch (get_address_family()) {
604 case AF_INET6:
605 ipv6_addr_.sin6_port = htons(static_cast<uint16>(port));
606 break;
607 case AF_INET:
608 ipv4_addr_.sin_port = htons(static_cast<uint16>(port));
609 break;
610 default:
611 UNREACHABLE();
612 }
613 }
614
operator ==(const IPAddress & a,const IPAddress & b)615 bool operator==(const IPAddress &a, const IPAddress &b) {
616 if (!a.is_valid() || !b.is_valid()) {
617 return !a.is_valid() && !b.is_valid();
618 }
619 if (a.get_address_family() != b.get_address_family()) {
620 return false;
621 }
622
623 if (a.get_address_family() == AF_INET) {
624 return a.ipv4_addr_.sin_port == b.ipv4_addr_.sin_port &&
625 std::memcmp(&a.ipv4_addr_.sin_addr, &b.ipv4_addr_.sin_addr, sizeof(a.ipv4_addr_.sin_addr)) == 0;
626 } else if (a.get_address_family() == AF_INET6) {
627 return a.ipv6_addr_.sin6_port == b.ipv6_addr_.sin6_port &&
628 std::memcmp(&a.ipv6_addr_.sin6_addr, &b.ipv6_addr_.sin6_addr, sizeof(a.ipv6_addr_.sin6_addr)) == 0;
629 }
630
631 UNREACHABLE();
632 return false;
633 }
634
operator <(const IPAddress & a,const IPAddress & b)635 bool operator<(const IPAddress &a, const IPAddress &b) {
636 if (!a.is_valid() || !b.is_valid()) {
637 return !a.is_valid() && b.is_valid();
638 }
639 if (a.get_address_family() != b.get_address_family()) {
640 return a.get_address_family() < b.get_address_family();
641 }
642
643 if (a.get_address_family() == AF_INET) {
644 if (a.ipv4_addr_.sin_port != b.ipv4_addr_.sin_port) {
645 return a.ipv4_addr_.sin_port < b.ipv4_addr_.sin_port;
646 }
647 return std::memcmp(&a.ipv4_addr_.sin_addr, &b.ipv4_addr_.sin_addr, sizeof(a.ipv4_addr_.sin_addr)) < 0;
648 } else if (a.get_address_family() == AF_INET6) {
649 if (a.ipv6_addr_.sin6_port != b.ipv6_addr_.sin6_port) {
650 return a.ipv6_addr_.sin6_port < b.ipv6_addr_.sin6_port;
651 }
652 return std::memcmp(&a.ipv6_addr_.sin6_addr, &b.ipv6_addr_.sin6_addr, sizeof(a.ipv6_addr_.sin6_addr)) < 0;
653 }
654
655 UNREACHABLE();
656 return false;
657 }
658
operator <<(StringBuilder & builder,const IPAddress & address)659 StringBuilder &operator<<(StringBuilder &builder, const IPAddress &address) {
660 if (!address.is_valid()) {
661 return builder << "[invalid]";
662 }
663 return builder << "[" << address.get_ip_host() << ":" << address.get_port() << "]";
664 }
665
666 } // namespace td
667