1 //  SuperTuxKart - a fun racing game with go-kart
2 //  Copyright (C) 2020 SuperTuxKart-Team
3 //
4 //  This program is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU General Public License
6 //  as published by the Free Software Foundation; either version 3
7 //  of the License, or (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 #include "network/socket_address.hpp"
19 #include "network/network_config.hpp"
20 #include "network/stk_ipv6.hpp"
21 #include "utils/log.hpp"
22 #include "utils/string_utils.hpp"
23 
24 #ifdef WIN32
25 #  undef _WIN32_WINNT
26 #  define _WIN32_WINNT 0x600
27 #  include <iphlpapi.h>
28 #else
29 #  include <ifaddrs.h>
30 #  include <sys/ioctl.h>
31 #  include <net/if.h>
32 #  include <string.h>
33 #  include <errno.h>
34 #endif
35 
36 #if defined(WIN32)
37 #  include "ws2tcpip.h"
38 #  define inet_ntop InetNtop
39 #else
40 #  include <arpa/inet.h>
41 #  include <errno.h>
42 #  include <sys/socket.h>
43 #endif
44 
45 #include <sys/types.h>
46 
47 // ----------------------------------------------------------------------------
48 bool SocketAddress::g_ignore_error_message = false;
49 // ----------------------------------------------------------------------------
50 /** IPv4 Constructor. */
SocketAddress(uint32_t ip,uint16_t port)51 SocketAddress::SocketAddress(uint32_t ip, uint16_t port)
52 {
53     clear();
54     setIP(ip);
55     setPort(port);
56 }   // SocketAddress
57 
58 // ----------------------------------------------------------------------------
59 /** IPv4 Constructor (4 bytes). */
SocketAddress(uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint16_t port)60 SocketAddress::SocketAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4,
61                              uint16_t port)
62              : SocketAddress((b1 << 24) + (b2 << 16) + (b3 << 8) + b4, port)
63 {
64 }   // SocketAddress(uint8_t,...)
65 
66 // ----------------------------------------------------------------------------
67 /** ENetAddress constructor. */
SocketAddress(const ENetAddress & ea)68 SocketAddress::SocketAddress(const ENetAddress& ea)
69 {
70 #ifdef ENABLE_IPV6
71     if (isIPv6Socket())
72     {
73         m_family = AF_INET6;
74         m_sockaddr = {};
75         struct sockaddr_in6* in6 = (struct sockaddr_in6*)m_sockaddr.data();
76         in6->sin6_family = AF_INET6;
77         in6->sin6_port = htons(ea.port);
78         // We modify host to use 5 uint32_t (see enet.h)
79         memcpy(in6->sin6_addr.s6_addr, &ea.host.p0, 16);
80         in6->sin6_scope_id = ea.host.p4;
81     }
82     else
83     {
84         m_family = AF_INET;
85         setIP(htonl(ea.host.p0));
86         setPort(ea.port);
87     }
88 #else
89     m_family = AF_INET;
90     setIP(htonl(ea.host));
91     setPort(ea.port);
92 #endif
93 }   // SocketAddress(const ENetAddress&)
94 
95 // ----------------------------------------------------------------------------
96 /** String initialization (Can be IPv4, IPv6 or domain).
97  *  \param str The address (can have a port with :)
98  *  \param port_number The port number, default is 0 or overwritten if
99  *  specified in str
100  *  \param family AF_UNSPEC, AF_INET or AF_INET6 for example
101  */
init(const std::string & str,uint16_t port_number,short family)102 void SocketAddress::init(const std::string& str, uint16_t port_number,
103                          short family)
104 {
105     clear();
106     if (str.empty())
107     {
108         Log::error("SocketAddress", "Empty address is specified.");
109         return;
110     }
111 
112     std::string addr_str;
113     std::string port_str;
114 
115     bool only_1_colon = false;
116     size_t colon_pos = std::string::npos;
117     // Check if only 1 colon, if so then it's either domain:port or IPv4:port
118     for (size_t i = 0; i < str.size(); i++)
119     {
120         if (str[i] == ':')
121         {
122             if (colon_pos == std::string::npos)
123             {
124                 colon_pos = i;
125                 only_1_colon = true;
126             }
127             else
128                 only_1_colon = false;
129         }
130     }
131     if (only_1_colon)
132     {
133         addr_str = std::string(str, 0, colon_pos);
134         if (colon_pos + 1 < str.size())
135             port_str = std::string(str, colon_pos + 1, str.size());
136         else
137             port_str = StringUtils::toString(port_number);
138     }
139     else if (str[0] == '[')
140     {
141         // Handle [IPv6 address]:port format
142         size_t pos = str.find(']');
143         if (pos == std::string::npos || pos - 1 == 0)
144         {
145             Log::error("SocketAddress", "Invalid IPv6 address is specified.");
146             return;
147         }
148         addr_str = std::string(str, 1, pos - 1);
149         if (pos + 2 < str.size() && str[pos + 1] == ':')
150             port_str = std::string(str, pos + 2, str.size());
151         else
152             port_str = StringUtils::toString(port_number);
153     }
154     else
155     {
156         addr_str = str;
157         port_str = StringUtils::toString(port_number);
158     }
159 
160     struct addrinfo hints;
161     struct addrinfo* res = NULL;
162     memset(&hints, 0, sizeof hints);
163     hints.ai_family = family;
164     hints.ai_socktype = SOCK_STREAM;
165 
166     int status = getaddrinfo_compat(addr_str.c_str(), port_str.c_str(), &hints,
167         &res);
168     if (status != 0)
169     {
170 #ifdef WIN32
171         if (!g_ignore_error_message)
172         {
173             wchar_t msgbuf[256] = {};
174             DWORD flags =
175                 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
176                 FORMAT_MESSAGE_MAX_WIDTH_MASK;
177             FormatMessage(flags, NULL, WSAGetLastError(), 0, msgbuf,
178                 sizeof(msgbuf) / sizeof(wchar_t), NULL);
179             Log::error("SocketAddress", "Error in getaddrinfo for "
180                 "SocketAddress (str constructor) %s: %s",
181                 str.c_str(), StringUtils::wideToUtf8(msgbuf).c_str());
182         }
183 #else
184         if (!g_ignore_error_message)
185         {
186             Log::error("SocketAddress", "Error in getaddrinfo for "
187                 "SocketAddress (str constructor) %s: %s",
188                 str.c_str(), gai_strerror(status));
189         }
190 #endif
191         return;
192     }
193     if (res == NULL)
194     {
195         if (!g_ignore_error_message)
196             Log::error("SocketAddress", "No address is resolved.");
197         return;
198     }
199 
200     bool found = false;
201     bool ipv4_mapped = str.size() > 7 && str.compare(0, 7, "::ffff:") == 0;
202     for (struct addrinfo* addr = res; addr != NULL; addr = addr->ai_next)
203     {
204         switch (addr->ai_family)
205         {
206         case AF_INET:
207             memcpy(m_sockaddr.data(), addr->ai_addr, sizeof(sockaddr_in));
208             found = true;
209             break;
210         case AF_INET6:
211             if (ipv4_mapped ||
212                 !isIPv4MappedAddress((const struct sockaddr_in6*)addr->ai_addr))
213             {
214                 // OSX and iOS can return AF_INET6 with ::ffff:x.y.z.w for server
215                 // with A record, skip them and make it only get real AAAA record
216                 m_family = AF_INET6;
217                 memcpy(m_sockaddr.data(), addr->ai_addr, sizeof(sockaddr_in6));
218                 found = true;
219             }
220             break;
221         default:
222             break;
223         }
224         if (found)
225             break;
226     }
227     freeaddrinfo(res);
228 }   // init
229 
230 // ----------------------------------------------------------------------------
231 /** Returns the IPv4 address in decimal, it will handle IPv4 mapped IPv6
232  *  address too. */
getIP() const233 uint32_t SocketAddress::getIP() const
234 {
235     if (m_family == AF_INET6)
236     {
237         sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
238         if (isIPv4MappedAddress(in6))
239             return ntohl(((in_addr*)(in6->sin6_addr.s6_addr + 12))->s_addr);
240         return 0;
241     }
242     else if (m_family == AF_INET)
243     {
244         sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
245         return ntohl(in->sin_addr.s_addr);
246     }
247     return 0;
248 }   // getIP
249 
250 // ----------------------------------------------------------------------------
251 /** Returns the port number. */
getPort() const252 uint16_t SocketAddress::getPort() const
253 {
254     if (m_family == AF_INET)
255     {
256         sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
257         return ntohs(in->sin_port);
258     }
259     else if (m_family == AF_INET6)
260     {
261         sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
262         return ntohs(in6->sin6_port);
263     }
264     return 0;
265 }   // getPort
266 
267 // ----------------------------------------------------------------------------
268 /** Sets the ip address. */
setIP(uint32_t ip)269 void SocketAddress::setIP(uint32_t ip)
270 {
271     if (m_family != AF_INET)
272     {
273         // Reset the structure if different family is used
274         clear();
275     }
276     sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
277     in->sin_addr.s_addr = htonl(ip);
278 }   // setIP
279 
280 // ----------------------------------------------------------------------------
281 /** Set the port. */
setPort(uint16_t port)282 void SocketAddress::setPort(uint16_t port)
283 {
284     if (m_family == AF_INET)
285     {
286         sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
287         in->sin_port = htons(port);
288     }
289     else if (m_family == AF_INET6)
290     {
291         sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
292         in6->sin6_port = htons(port);
293     }
294 }   // setPort
295 
296 // ----------------------------------------------------------------------------
297 /** Returns this IP address is localhost which its equal to any interface
298  *  address. */
isPublicAddressLocalhost() const299 bool SocketAddress::isPublicAddressLocalhost() const
300 {
301     if (m_family == AF_INET && getIP() == 0)
302         return false;
303     if (isLoopback())
304         return true;
305 #ifndef WIN32
306     struct ifaddrs *addresses, *p;
307 
308     if (getifaddrs(&addresses) == -1)
309     {
310         Log::warn("SocketAddress", "Error in getifaddrs");
311         return false;
312     }
313     bool is_local_host = false;
314     for (p = addresses; p; p = p->ifa_next)
315     {
316         if (p->ifa_addr == NULL)
317             continue;
318         if (p->ifa_addr->sa_family == AF_INET)
319         {
320             struct sockaddr_in *sa = (struct sockaddr_in*)p->ifa_addr;
321             if (htonl(sa->sin_addr.s_addr) == getIP())
322             {
323                 is_local_host = true;
324                 break;
325             }
326         }
327         else if (p->ifa_addr->sa_family == AF_INET6 && getFamily() == AF_INET6)
328         {
329             struct sockaddr_in6 addr = {};
330             memcpy(&addr, p->ifa_addr, sizeof(sockaddr_in6));
331             sockaddr_in6* my_in6 = (sockaddr_in6*)m_sockaddr.data();
332             addr.sin6_port = my_in6->sin6_port;
333             if (sameIPV6(my_in6, &addr))
334             {
335                 is_local_host = true;
336                 break;
337             }
338         }
339     }
340     freeifaddrs(addresses);
341     return is_local_host;
342 #else
343     // From docs from microsoft it recommends 15k size
344     const int WORKING_BUFFER_SIZE = 15000;
345     PIP_ADAPTER_ADDRESSES paddr = NULL;
346     unsigned long len = WORKING_BUFFER_SIZE;
347     int return_code = 0;
348     int iteration = 0;
349     do
350     {
351         paddr = (IP_ADAPTER_ADDRESSES*)malloc(len);
352         if (paddr == NULL)
353             return false;
354         long flags = 0;
355         return_code = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, paddr,
356             &len);
357         if (return_code == ERROR_BUFFER_OVERFLOW)
358         {
359             free(paddr);
360             paddr = NULL;
361         }
362         else
363             break;
364         iteration++;
365     } while ((return_code == ERROR_BUFFER_OVERFLOW) && (iteration < 10));
366 
367     if (return_code == ERROR_BUFFER_OVERFLOW)
368         return false;
369 
370     bool is_local_host = false;
371     for (IP_ADAPTER_ADDRESSES *p = paddr; p; p = p->Next)
372     {
373         if (is_local_host)
374             break;
375         if (p->OperStatus != IfOperStatusUp)
376             continue;
377 
378         for (PIP_ADAPTER_UNICAST_ADDRESS unicast = p->FirstUnicastAddress;
379             unicast != NULL; unicast = unicast->Next)
380         {
381             if (unicast->Address.lpSockaddr->sa_family == AF_INET)
382             {
383                 const sockaddr_in *sa = (sockaddr_in*)unicast->Address.lpSockaddr;
384                 if (htonl(sa->sin_addr.s_addr) == getIP())
385                 {
386                     is_local_host = true;
387                     break;
388                 }
389             }
390             else if (unicast->Address.lpSockaddr->sa_family == AF_INET6 &&
391                 getFamily() == AF_INET6)
392             {
393                 struct sockaddr_in6 addr = {};
394                 memcpy(&addr, unicast->Address.lpSockaddr, sizeof(sockaddr_in6));
395                 sockaddr_in6* my_in6 = (sockaddr_in6*)m_sockaddr.data();
396                 addr.sin6_port = my_in6->sin6_port;
397                 if (sameIPV6(my_in6, &addr))
398                 {
399                     is_local_host = true;
400                     break;
401                 }
402             }
403         }
404     }
405     free(paddr);
406     return is_local_host;
407 #endif
408 }   // isPublicAddressLocalhost
409 
410 // ----------------------------------------------------------------------------
411 /** Returns if this IP is loopback (ie for IPv4 127.0.0.0/8, IPv6 ::1/128)
412  */
isLoopback() const413 bool SocketAddress::isLoopback() const
414 {
415     uint32_t ip = getIP();
416     if (ip != 0)
417     {
418         if (ip >> 24 == 0x7f)
419             return true;
420     }
421     else if (m_family == AF_INET6)
422     {
423         sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
424         uint8_t w0 = in6->sin6_addr.s6_addr[0];
425         uint8_t w1 = in6->sin6_addr.s6_addr[1];
426         uint8_t w2 = in6->sin6_addr.s6_addr[2];
427         uint8_t w3 = in6->sin6_addr.s6_addr[3];
428         uint8_t w4 = in6->sin6_addr.s6_addr[4];
429         uint8_t w5 = in6->sin6_addr.s6_addr[5];
430         uint8_t w6 = in6->sin6_addr.s6_addr[6];
431         uint8_t w7 = in6->sin6_addr.s6_addr[7];
432         uint8_t w8 = in6->sin6_addr.s6_addr[8];
433         uint8_t w9 = in6->sin6_addr.s6_addr[9];
434         uint8_t w10 = in6->sin6_addr.s6_addr[10];
435         uint8_t w11 = in6->sin6_addr.s6_addr[11];
436         uint8_t w12 = in6->sin6_addr.s6_addr[12];
437         uint8_t w13 = in6->sin6_addr.s6_addr[13];
438         uint8_t w14 = in6->sin6_addr.s6_addr[14];
439         uint8_t w15 = in6->sin6_addr.s6_addr[15];
440         if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 &&
441             w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 &&
442             w10 == 0 && w11 == 0 && w12 == 0 && w13 == 0 && w14 == 0
443             && w15 == 1)
444         {
445             // ::1/128 Loopback
446             return true;
447         }
448     }
449     return false;
450 }   // isLoopback
451 
452 // ----------------------------------------------------------------------------
453 /** Returns if this IP address belongs to a LAN, i.e. is in 192.168* or
454  *  10*, 172.16-31.*, or is on the same host, i.e. 127*.
455  */
isLAN() const456 bool SocketAddress::isLAN() const
457 {
458     if (isLoopback())
459         return true;
460     uint32_t ip = getIP();
461     if (ip != 0)
462     {
463         // IPv4 test
464         if (ip >> 16 == 0xc0a8)         // Check for 192.168.*
465             return true;
466         else if (ip >> 20 == 0xac1 )    // 172.16-31.*
467             return true;
468         else if (ip >> 24 == 0x0a  )    // 10.*
469             return true;
470     }
471     else if (m_family == AF_INET6)
472     {
473         sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
474         uint8_t w0 = in6->sin6_addr.s6_addr[0];
475         uint8_t w1 = in6->sin6_addr.s6_addr[1];
476         uint16_t _16 = ((uint16_t)w0) << 8 | w1;
477         if (_16 >= 0xfc00 && _16 <= 0xfdff)
478         {
479             // fc00::/7 Unique Local Address (ULA)
480             return true;
481         }
482         if (_16 >= 0xfe80 && _16 <= 0xfebf)
483         {
484             // fe80::/10 Link-Local Address
485             return true;
486         }
487     }
488     return false;
489 }   // isLAN
490 
491 // ----------------------------------------------------------------------------
492 /** Compares if ip address and port are identical. */
operator ==(const SocketAddress & other) const493 bool SocketAddress::operator==(const SocketAddress& other) const
494 {
495     if (m_family == AF_INET && other.m_family == AF_INET)
496     {
497         sockaddr_in* in_a = (sockaddr_in*)m_sockaddr.data();
498         sockaddr_in* in_b = (sockaddr_in*)(other.m_sockaddr.data());
499         return in_a->sin_addr.s_addr == in_b->sin_addr.s_addr &&
500             in_a->sin_port == in_b->sin_port;
501     }
502     else if (m_family == AF_INET6 && other.m_family == AF_INET6)
503     {
504         sockaddr_in6* in6_a = (sockaddr_in6*)m_sockaddr.data();
505         sockaddr_in6* in6_b = (sockaddr_in6*)(other.m_sockaddr.data());
506         return sameIPV6(in6_a, in6_b);
507     }
508     return false;
509 }   // operator==
510 
511 // ----------------------------------------------------------------------------
512 /** Compares if ip address and port are not identical. */
operator !=(const SocketAddress & other) const513 bool SocketAddress::operator!=(const SocketAddress& other) const
514 {
515     if (m_family == AF_INET && other.m_family == AF_INET)
516     {
517         sockaddr_in* in_a = (sockaddr_in*)m_sockaddr.data();
518         sockaddr_in* in_b = (sockaddr_in*)(other.m_sockaddr.data());
519         return in_a->sin_addr.s_addr != in_b->sin_addr.s_addr ||
520             in_a->sin_port != in_b->sin_port;
521     }
522     else if (m_family == AF_INET6 && other.m_family == AF_INET6)
523     {
524         sockaddr_in6* in6_a = (sockaddr_in6*)m_sockaddr.data();
525         sockaddr_in6* in6_b = (sockaddr_in6*)(other.m_sockaddr.data());
526         return !sameIPV6(in6_a, in6_b);
527     }
528     return true;
529 }   // operator!=
530 
531 // ----------------------------------------------------------------------------
toString(bool show_port) const532 std::string SocketAddress::toString(bool show_port) const
533 {
534     std::string result;
535     uint32_t ip = getIP();
536     if (ip != 0 || m_family == AF_INET)
537     {
538         result = StringUtils::insertValues("%d.%d.%d.%d",
539             ((ip >> 24) & 0xff), ((ip >> 16) & 0xff),
540             ((ip >>  8) & 0xff), ((ip >>  0) & 0xff));
541         if (show_port)
542             result += ":" + StringUtils::toString(getPort());
543     }
544     else
545     {
546         result = getIPV6ReadableFromIn6((sockaddr_in6*)m_sockaddr.data());
547         if (show_port)
548         {
549             result.insert (0, 1, '[');
550             result += "]";
551             result += ":" + StringUtils::toString(getPort());
552         }
553     }
554     return result;
555 }   // toString
556 
557 // ----------------------------------------------------------------------------
convertForIPv6Socket(bool ipv6)558 void SocketAddress::convertForIPv6Socket(bool ipv6)
559 {
560 #ifdef ENABLE_IPV6
561     if (m_family == AF_INET && ipv6)
562     {
563         std::string ipv4 = toString(false/*show_port*/);
564         uint16_t port = getPort();
565         auto ip_type = NetworkConfig::get()->getIPType();
566         if (ip_type == NetworkConfig::IP_V6_NAT64)
567         {
568             ipv4 = NetworkConfig::get()->getNAT64Prefix() + ipv4;
569         }
570         else
571         {
572             // Assume the system has dual stack if it uses an IPv6 socket
573             ipv4 = std::string("::ffff:") + ipv4;
574         }
575         init(ipv4, port);
576     }
577 #endif
578 }   // convertForIPv6Socket
579 
580 // ----------------------------------------------------------------------------
581 /** Unit testing. Test various LAN patterns to verify that isLAN() works as
582  *  expected.
583  */
unitTesting()584 void SocketAddress::unitTesting()
585 {
586     SocketAddress t1("192.168.0.0");
587     assert(t1.getIP() == (192u << 24) + (168u << 16));
588     assert(t1.isLAN());
589 
590     SocketAddress t2("192.168.255.255");
591     assert(t2.getIP() == (192u << 24) + (168u << 16) + (255u << 8) + 255u);
592     assert(t2.isLAN());
593 
594     SocketAddress t3("::ffff:193.168.0.1");
595     assert(t3.getIP() == (193u << 24) + (168u << 16) + 1);
596     assert(!t3.isLAN());
597 
598     SocketAddress t4("192.167.255.255");
599     assert(t4.getIP() == (192u << 24) + (167u << 16) + (255u << 8) + 255u);
600     assert(!t4.isLAN());
601 
602     SocketAddress t5("192.169.0.0");
603     assert(t5.getIP() == (192u << 24) + (169u << 16));
604     assert(!t5.isLAN());
605 
606     SocketAddress t6("172.16.0.0");
607     assert(t6.getIP() == (172u << 24) + (16u << 16));
608     assert(t6.isLAN());
609 
610     SocketAddress t7("172.31.255.255");
611     assert(t7.getIP() == (172u << 24) + (31u << 16) + (255u << 8) + 255u);
612     assert(t7.isLAN());
613 
614     SocketAddress t8("172.15.255.255");
615     assert(t8.getIP() == (172u << 24) + (15u << 16) + (255u << 8) + 255u);
616     assert(!t8.isLAN());
617 
618     SocketAddress t9("172.32.0.0");
619     assert(t9.getIP() == (172u << 24) + (32u << 16));
620     assert(!t9.isLAN());
621 
622     SocketAddress t10("10.0.0.0");
623     assert(t10.getIP() == (10u << 24));
624     assert(t10.isLAN());
625 
626     SocketAddress t11("10.255.255.255");
627     assert(t11.getIP() == (10u << 24) + (255u << 16) + (255u << 8) + 255u);
628     assert(t11.isLAN());
629 
630     SocketAddress t12("9.255.255.255");
631     assert(t12.getIP() == (9u << 24) + (255u << 16) + (255u << 8) + 255u);
632     assert(!t12.isLAN());
633 
634     SocketAddress t13("11.0.0.0");
635     assert(t13.getIP() == (11u << 24));
636     assert(!t13.isLAN());
637 
638     SocketAddress t14("127.0.0.0");
639     assert(t14.getIP() == (127u << 24));
640     assert(t14.isLAN());
641 
642     SocketAddress t15("::ffff:127.255.255.255");
643     assert(t15.getIP() == (127u << 24) + (255u << 16) + (255u << 8) + 255u);
644     assert(t15.isLAN());
645 
646     SocketAddress t16("126.255.255.255");
647     assert(t16.getIP() == (126u << 24) + (255u << 16) + (255u << 8) + 255u);
648     assert(!t16.isLAN());
649 
650     SocketAddress t17("128.0.0.0");
651     assert(t17.getIP() == (128u << 24));
652     assert(!t17.isLAN());
653 
654     // Test constructors
655     SocketAddress t18("128.0.0.0");
656     assert(t18.getIP() == (128u << 24));
657     assert(t18.getPort() == 0);
658 
659     SocketAddress t19("128.0.0.0", 1);
660     assert(t19.getIP() == (128u << 24));
661     assert(t19.getPort() == 1);
662 
663     SocketAddress t20("128.0.0.0", 123);
664     assert(t20.getIP() == (128u << 24));
665     assert(t20.getPort() == 123);
666 
667     SocketAddress v6_1("0:0:0:0:0:0:0:1");
668     assert(v6_1.isLAN());
669 
670     SocketAddress v6_2("fe80::221:86ff:fea0:ce84");
671     assert(v6_2.isLAN());
672 
673     SocketAddress v6_3("fdf8:f53b:82e4::53");
674     assert(v6_3.isLAN());
675 
676     // Boundary test
677     // fc00::/7 Unique Local Address (ULA)
678     SocketAddress v6_4("fc00::");
679     assert(v6_4.isLAN());
680 
681     SocketAddress v6_5("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
682     assert(v6_5.isLAN());
683 
684     SocketAddress v6_6("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
685     assert(!v6_6.isLAN());
686 
687     SocketAddress v6_7("fe00::");
688     assert(!v6_7.isLAN());
689 
690     // fe80::/10 Link-Local Address
691     SocketAddress v6_8("fe80::");
692     assert(v6_8.isLAN());
693 
694     SocketAddress v6_9("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
695     assert(v6_9.isLAN());
696 
697     SocketAddress v6_10("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
698     assert(!v6_10.isLAN());
699 
700     SocketAddress v6_11("fec0::");
701     assert(!v6_11.isLAN());
702 
703     SocketAddress ipv4_port("0.0.0.1:1");
704     assert(ipv4_port.getIP() == 1);
705     assert(ipv4_port.getPort() == 1);
706 
707     SocketAddress ipv6_port("[::2]:1");
708     assert(ipv6_port.toString(false) == "::2");
709     assert(ipv6_port.getPort() == 1);
710 
711 }   // unitTesting
712 
713 // ----------------------------------------------------------------------------
toENetAddress() const714 ENetAddress SocketAddress::toENetAddress() const
715 {
716     ENetAddress ea = {};
717     uint32_t ip = getIP();
718 #ifdef ENABLE_IPV6
719     if (isIPv6Socket())
720     {
721         struct sockaddr_in6* in6 = (struct sockaddr_in6*)m_sockaddr.data();
722         memcpy(&ea.host.p0, in6->sin6_addr.s6_addr, 16);
723         ea.host.p4 = in6->sin6_scope_id;
724     }
725     else
726     {
727         // because ENet wants little endian
728         ea.host.p0 = ((ip & 0xff000000) >> 24) +
729             ((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
730             ((ip & 0x000000ff) << 24);
731     }
732 #else
733     ea.host = ((ip & 0xff000000) >> 24) +
734         ((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
735         ((ip & 0x000000ff) << 24);
736 #endif
737     ea.port = getPort();
738     return ea;
739 }   // toENetAddress
740