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