Add socket address to support both IPv4 and IPv6

This commit is contained in:
Benau 2020-01-27 11:50:15 +08:00
parent a79a2a7fab
commit 6abd3bbf69
6 changed files with 748 additions and 16 deletions

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -227,6 +227,7 @@
#include "network/server.hpp"
#include "network/server_config.hpp"
#include "network/servers_manager.hpp"
#include "network/socket_address.hpp"
#include "network/stk_host.hpp"
#include "network/stk_peer.hpp"
#include "online/profile_manager.hpp"
@ -2586,6 +2587,8 @@ void runUnitTests()
NetworkString::unitTesting();
Log::info("UnitTest", "TransportAddress");
TransportAddress::unitTesting();
Log::info("UnitTest", "SocketAddress");
SocketAddress::unitTesting();
Log::info("UnitTest", "StringUtils::versionToInt");
StringUtils::unitTesting();

View File

@ -0,0 +1,576 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2020 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "network/socket_address.hpp"
#include "network/network_config.hpp"
#include "network/stk_ipv6.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
#ifdef WIN32
# undef _WIN32_WINNT
# define _WIN32_WINNT 0x600
# include <iphlpapi.h>
#else
# include <ifaddrs.h>
# include <sys/ioctl.h>
# include <net/if.h>
# include <string.h>
# include <errno.h>
#endif
#if defined(WIN32)
# include "ws2tcpip.h"
# define inet_ntop InetNtop
#else
# include <arpa/inet.h>
# include <errno.h>
# include <sys/socket.h>
#endif
#include <sys/types.h>
// ----------------------------------------------------------------------------
/** IPv4 Constructor. */
SocketAddress::SocketAddress(uint32_t ip, uint16_t port)
{
clear();
setIP(ip);
setPort(port);
} // SocketAddress
// ----------------------------------------------------------------------------
/** IPv4 Constructor (4 bytes). */
SocketAddress::SocketAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4,
uint16_t port)
: SocketAddress((b1 << 24) + (b2 << 16) + (b3 << 8) + b4, port)
{
} // SocketAddress(uint8_t,...)
// ----------------------------------------------------------------------------
/** String initialization (Can be IPv4, IPv6 or domain). */
void SocketAddress::init(const std::string& str, uint16_t port_number)
{
clear();
struct addrinfo hints;
struct addrinfo* res = NULL;
std::string port_str = StringUtils::toString(port_number);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int status = getaddrinfo_compat(str.c_str(), port_str.c_str(), &hints,
&res);
if (status != 0 || res == NULL)
{
Log::error("TransportAddress", "Error in getaddrinfo for "
" TransportAddress (str constructor) %s: %s",
str.c_str(), gai_strerror(status));
return;
}
bool found = false;
for (struct addrinfo* addr = res; addr != NULL; addr = addr->ai_next)
{
switch (addr->ai_family)
{
case AF_INET:
memcpy(m_sockaddr.data(), addr->ai_addr, sizeof(sockaddr_in));
found = true;
break;
case AF_INET6:
m_family = AF_INET6;
memcpy(m_sockaddr.data(), addr->ai_addr, sizeof(sockaddr_in6));
found = true;
break;
default:
break;
}
if (found)
break;
}
freeaddrinfo(res);
} // init
// ----------------------------------------------------------------------------
/** Returns the IPv4 address in decimal, it will handle IPv4 mapped IPv6
* address too. */
uint32_t SocketAddress::getIP() const
{
if (m_family == AF_INET6)
{
sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
if (isIPv4MappedAddress(in6))
return ntohl(((in_addr*)(in6->sin6_addr.s6_addr + 12))->s_addr);
return 0;
}
else if (m_family == AF_INET)
{
sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
return ntohl(in->sin_addr.s_addr);
}
return 0;
} // getIP
// ----------------------------------------------------------------------------
/** Returns the port number. */
uint16_t SocketAddress::getPort() const
{
if (m_family == AF_INET)
{
sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
return ntohs(in->sin_port);
}
else if (m_family == AF_INET6)
{
sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
return ntohs(in6->sin6_port);
}
return 0;
} // getPort
// ----------------------------------------------------------------------------
/** Sets the ip address. */
void SocketAddress::setIP(uint32_t ip)
{
if (m_family != AF_INET)
{
// Reset the structure if different family is used
clear();
}
sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
in->sin_addr.s_addr = htonl(ip);
} // setIP
// ----------------------------------------------------------------------------
/** Set the port. */
void SocketAddress::setPort(uint16_t port)
{
if (m_family == AF_INET)
{
sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
in->sin_port = htons(port);
}
else if (m_family == AF_INET6)
{
sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
in6->sin6_port = htons(port);
}
} // setPort
// ----------------------------------------------------------------------------
/** Returns this IP address is localhost which its equal to any interface
* address. */
bool SocketAddress::isPublicAddressLocalhost() const
{
if (m_family == AF_INET && getIP() == 0)
return false;
if (isLoopback())
return true;
#ifndef WIN32
struct ifaddrs *addresses, *p;
if (getifaddrs(&addresses) == -1)
{
Log::warn("SocketAddress", "Error in getifaddrs");
return false;
}
bool is_local_host = false;
for (p = addresses; p; p = p->ifa_next)
{
if (p->ifa_addr == NULL)
continue;
if (p->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in *sa = (struct sockaddr_in*)p->ifa_addr;
if (htonl(sa->sin_addr.s_addr) == getIP())
{
is_local_host = true;
break;
}
}
else if (p->ifa_addr->sa_family == AF_INET6 && getFamily() == AF_INET6)
{
struct sockaddr_in6 addr = {};
memcpy(&addr, p->ifa_addr, sizeof(sockaddr_in6));
sockaddr_in6* my_in6 = (sockaddr_in6*)m_sockaddr.data();
addr.sin6_port = my_in6->sin6_port;
if (sameIPV6(my_in6, &addr))
{
is_local_host = true;
break;
}
}
}
freeifaddrs(addresses);
return is_local_host;
#else
// From docs from microsoft it recommends 15k size
const int WORKING_BUFFER_SIZE = 15000;
PIP_ADAPTER_ADDRESSES paddr = NULL;
unsigned long len = WORKING_BUFFER_SIZE;
int return_code = 0;
int iteration = 0;
do
{
paddr = (IP_ADAPTER_ADDRESSES*)malloc(len);
if (paddr == NULL)
return false;
long flags = 0;
return_code = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, paddr,
&len);
if (return_code == ERROR_BUFFER_OVERFLOW)
{
free(paddr);
paddr = NULL;
}
else
break;
iteration++;
} while ((return_code == ERROR_BUFFER_OVERFLOW) && (iteration < 10));
if (return_code == ERROR_BUFFER_OVERFLOW)
return false;
bool is_local_host = false;
for (IP_ADAPTER_ADDRESSES *p = paddr; p; p = p->Next)
{
if (is_local_host)
break;
if (p->OperStatus != IfOperStatusUp)
continue;
for (PIP_ADAPTER_UNICAST_ADDRESS unicast = p->FirstUnicastAddress;
unicast != NULL; unicast = unicast->Next)
{
if (unicast->Address.lpSockaddr->sa_family == AF_INET)
{
const sockaddr_in *sa = (sockaddr_in*)unicast->Address.lpSockaddr;
if (htonl(sa->sin_addr.s_addr) == getIP())
{
is_local_host = true;
break;
}
}
else if (unicast->Address.lpSockaddr->sa_family == AF_INET6 &&
getFamily() == AF_INET6)
{
struct sockaddr_in6 addr = {};
memcpy(&addr, unicast->Address.lpSockaddr, sizeof(sockaddr_in6));
sockaddr_in6* my_in6 = (sockaddr_in6*)m_sockaddr.data();
addr.sin6_port = my_in6->sin6_port;
if (sameIPV6(my_in6, &addr))
{
is_local_host = true;
break;
}
}
}
}
free(paddr);
return is_local_host;
#endif
} // isPublicAddressLocalhost
// ----------------------------------------------------------------------------
/** Returns if this IP is loopback (ie for IPv4 127.0.0.0/8, IPv6 ::1/128)
*/
bool SocketAddress::isLoopback() const
{
uint32_t ip = getIP();
if (ip != 0)
{
if (ip >> 24 == 0x7f)
return true;
}
else if (m_family == AF_INET6)
{
sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
uint8_t w0 = in6->sin6_addr.s6_addr[0];
uint8_t w1 = in6->sin6_addr.s6_addr[1];
uint8_t w2 = in6->sin6_addr.s6_addr[2];
uint8_t w3 = in6->sin6_addr.s6_addr[3];
uint8_t w4 = in6->sin6_addr.s6_addr[4];
uint8_t w5 = in6->sin6_addr.s6_addr[5];
uint8_t w6 = in6->sin6_addr.s6_addr[6];
uint8_t w7 = in6->sin6_addr.s6_addr[7];
uint8_t w8 = in6->sin6_addr.s6_addr[8];
uint8_t w9 = in6->sin6_addr.s6_addr[9];
uint8_t w10 = in6->sin6_addr.s6_addr[10];
uint8_t w11 = in6->sin6_addr.s6_addr[11];
uint8_t w12 = in6->sin6_addr.s6_addr[12];
uint8_t w13 = in6->sin6_addr.s6_addr[13];
uint8_t w14 = in6->sin6_addr.s6_addr[14];
uint8_t w15 = in6->sin6_addr.s6_addr[15];
if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 &&
w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 &&
w10 == 0 && w11 == 0 && w12 == 0 && w13 == 0 && w14 == 0
&& w15 == 1)
{
// ::1/128 Loopback
return true;
}
}
return false;
} // isLoopback
// ----------------------------------------------------------------------------
/** Returns if this IP address belongs to a LAN, i.e. is in 192.168* or
* 10*, 172.16-31.*, or is on the same host, i.e. 127*.
*/
bool SocketAddress::isLAN() const
{
if (isLoopback())
return true;
uint32_t ip = getIP();
if (ip != 0)
{
// IPv4 test
if (ip >> 16 == 0xc0a8) // Check for 192.168.*
return true;
else if (ip >> 20 == 0xac1 ) // 172.16-31.*
return true;
else if (ip >> 24 == 0x0a ) // 10.*
return true;
}
else if (m_family == AF_INET6)
{
sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
uint8_t w0 = in6->sin6_addr.s6_addr[0];
uint8_t w1 = in6->sin6_addr.s6_addr[1];
uint16_t _16 = ((uint16_t)w0) << 8 | w1;
if (_16 >= 0xfc00 && _16 <= 0xfdff)
{
// fc00::/7 Unique Local Address (ULA)
return true;
}
if (_16 >= 0xfe80 && _16 <= 0xfebf)
{
// fe80::/10 Link-Local Address
return true;
}
}
return false;
} // isLAN
// ----------------------------------------------------------------------------
/** Compares if ip address and port are identical. */
bool SocketAddress::operator==(const SocketAddress& other) const
{
if (m_family == AF_INET && other.m_family == AF_INET)
{
sockaddr_in* in_a = (sockaddr_in*)m_sockaddr.data();
sockaddr_in* in_b = (sockaddr_in*)(other.m_sockaddr.data());
return in_a->sin_addr.s_addr == in_b->sin_addr.s_addr &&
in_a->sin_port == in_b->sin_port;
}
else if (m_family == AF_INET6 && other.m_family == AF_INET6)
{
sockaddr_in6* in6_a = (sockaddr_in6*)m_sockaddr.data();
sockaddr_in6* in6_b = (sockaddr_in6*)(other.m_sockaddr.data());
return sameIPV6(in6_a, in6_b);
}
return false;
} // operator==
// ----------------------------------------------------------------------------
/** Compares if ip address and port are not identical. */
bool SocketAddress::operator!=(const SocketAddress& other) const
{
if (m_family == AF_INET && other.m_family == AF_INET)
{
sockaddr_in* in_a = (sockaddr_in*)m_sockaddr.data();
sockaddr_in* in_b = (sockaddr_in*)(other.m_sockaddr.data());
return in_a->sin_addr.s_addr != in_b->sin_addr.s_addr ||
in_a->sin_port != in_b->sin_port;
}
else if (m_family == AF_INET6 && other.m_family == AF_INET6)
{
sockaddr_in6* in6_a = (sockaddr_in6*)m_sockaddr.data();
sockaddr_in6* in6_b = (sockaddr_in6*)(other.m_sockaddr.data());
return !sameIPV6(in6_a, in6_b);
}
return true;
} // operator!=
// ----------------------------------------------------------------------------
std::string SocketAddress::toString(bool show_port) const
{
std::string result;
uint32_t ip = getIP();
if (ip != 0 || m_family == AF_INET)
{
result = StringUtils::insertValues("%d.%d.%d.%d",
((ip >> 24) & 0xff), ((ip >> 16) & 0xff),
((ip >> 8) & 0xff), ((ip >> 0) & 0xff));
if (show_port)
result += ":" + StringUtils::toString(getPort());
}
else
{
result = getIPV6ReadableFromIn6((sockaddr_in6*)m_sockaddr.data());
if (show_port)
{
result.insert (0, 1, '[');
result += "]";
result += ":" + StringUtils::toString(getPort());
}
}
return result;
} // toString
// ----------------------------------------------------------------------------
void SocketAddress::convertForIPv6Socket()
{
#ifdef ENABLE_IPV6
if (m_family == AF_INET && isIPv6Socket())
{
std::string ipv4 = toString(false/*show_port*/);
uint16_t port = getPort();
auto ip_type = NetworkConfig::get()->getIPType();
if (ip_type == NetworkConfig::IP_DUAL_STACK)
ipv4 = std::string("::ffff:") + ipv4;
else if (ip_type == NetworkConfig::IP_V6_NAT64)
ipv4 = NetworkConfig::get()->getNAT64Prefix() + ipv4;
init(ipv4, port);
}
#endif
} // convertForIPv6Socket
// ----------------------------------------------------------------------------
/** Unit testing. Test various LAN patterns to verify that isLAN() works as
* expected.
*/
void SocketAddress::unitTesting()
{
SocketAddress t1("192.168.0.0");
assert(t1.getIP() == (192u << 24) + (168u << 16));
assert(t1.isLAN());
SocketAddress t2("192.168.255.255");
assert(t2.getIP() == (192u << 24) + (168u << 16) + (255u << 8) + 255u);
assert(t2.isLAN());
SocketAddress t3("::ffff:193.168.0.1");
assert(t3.getIP() == (193u << 24) + (168u << 16) + 1);
assert(!t3.isLAN());
SocketAddress t4("192.167.255.255");
assert(t4.getIP() == (192u << 24) + (167u << 16) + (255u << 8) + 255u);
assert(!t4.isLAN());
SocketAddress t5("192.169.0.0");
assert(t5.getIP() == (192u << 24) + (169u << 16));
assert(!t5.isLAN());
SocketAddress t6("172.16.0.0");
assert(t6.getIP() == (172u << 24) + (16u << 16));
assert(t6.isLAN());
SocketAddress t7("172.31.255.255");
assert(t7.getIP() == (172u << 24) + (31u << 16) + (255u << 8) + 255u);
assert(t7.isLAN());
SocketAddress t8("172.15.255.255");
assert(t8.getIP() == (172u << 24) + (15u << 16) + (255u << 8) + 255u);
assert(!t8.isLAN());
SocketAddress t9("172.32.0.0");
assert(t9.getIP() == (172u << 24) + (32u << 16));
assert(!t9.isLAN());
SocketAddress t10("10.0.0.0");
assert(t10.getIP() == (10u << 24));
assert(t10.isLAN());
SocketAddress t11("10.255.255.255");
assert(t11.getIP() == (10u << 24) + (255u << 16) + (255u << 8) + 255u);
assert(t11.isLAN());
SocketAddress t12("9.255.255.255");
assert(t12.getIP() == (9u << 24) + (255u << 16) + (255u << 8) + 255u);
assert(!t12.isLAN());
SocketAddress t13("11.0.0.0");
assert(t13.getIP() == (11u << 24));
assert(!t13.isLAN());
SocketAddress t14("127.0.0.0");
assert(t14.getIP() == (127u << 24));
assert(t14.isLAN());
SocketAddress t15("::ffff:127.255.255.255");
assert(t15.getIP() == (127u << 24) + (255u << 16) + (255u << 8) + 255u);
assert(t15.isLAN());
SocketAddress t16("126.255.255.255");
assert(t16.getIP() == (126u << 24) + (255u << 16) + (255u << 8) + 255u);
assert(!t16.isLAN());
SocketAddress t17("128.0.0.0");
assert(t17.getIP() == (128u << 24));
assert(!t17.isLAN());
// Test constructors
SocketAddress t18("128.0.0.0");
assert(t18.getIP() == (128u << 24));
assert(t18.getPort() == 0);
SocketAddress t19("128.0.0.0", 1);
assert(t19.getIP() == (128u << 24));
assert(t19.getPort() == 1);
SocketAddress t20("128.0.0.0", 123);
assert(t20.getIP() == (128u << 24));
assert(t20.getPort() == 123);
SocketAddress v6_1("0:0:0:0:0:0:0:1");
assert(v6_1.isLAN());
SocketAddress v6_2("fe80::221:86ff:fea0:ce84");
assert(v6_2.isLAN());
SocketAddress v6_3("fdf8:f53b:82e4::53");
assert(v6_3.isLAN());
// Boundary test
// fc00::/7 Unique Local Address (ULA)
SocketAddress v6_4("fc00::");
assert(v6_4.isLAN());
SocketAddress v6_5("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
assert(v6_5.isLAN());
SocketAddress v6_6("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
assert(!v6_6.isLAN());
SocketAddress v6_7("fe00::");
assert(!v6_7.isLAN());
// fe80::/10 Link-Local Address
SocketAddress v6_8("fe80::");
assert(v6_8.isLAN());
SocketAddress v6_9("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
assert(v6_9.isLAN());
SocketAddress v6_10("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
assert(!v6_10.isLAN());
SocketAddress v6_11("fec0::");
assert(!v6_11.isLAN());
} // unitTesting

View File

@ -0,0 +1,144 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2020 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file types.hpp
* \brief Declares the general types that are used by the network.
*/
#ifndef HEADER_SOCKET_ADDRESS_HPP
#define HEADER_SOCKET_ADDRESS_HPP
#include "utils/types.hpp"
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#else
# include <netdb.h>
# include <netinet/in.h>
#endif
#include <array>
#include <cstring>
#include <string>
#include <vector>
// ============================================================================
/*! \class SocketAddress
* \brief Describes a IPv4 or IPv6 address in sockaddr_in(6) format, suitable
* in using with sendto.
*/
class SocketAddress
{
private:
// We need to have a biggest size to hold all type of sockaddr
static_assert(sizeof(sockaddr_in6) > sizeof(sockaddr_in),
"Invalid sockaddr size");
std::array<char, sizeof(sockaddr_in6)> m_sockaddr;
short m_family;
public:
// ------------------------------------------------------------------------
static void unitTesting();
// ------------------------------------------------------------------------
SocketAddress(uint32_t ip = 0, uint16_t port = 0);
// ------------------------------------------------------------------------
/** IPv4 Constructor (4 bytes). */
SocketAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4,
uint16_t port=0);
// ------------------------------------------------------------------------
SocketAddress(const std::string& str, uint16_t port_number = 0)
{
init(str, port_number);
}
// ------------------------------------------------------------------------
bool operator==(const SocketAddress& other) const;
// ------------------------------------------------------------------------
bool operator!=(const SocketAddress& other) const;
// ------------------------------------------------------------------------
void init(const std::string& str, uint16_t port_number = 0);
// ------------------------------------------------------------------------
bool isLAN() const;
// ------------------------------------------------------------------------
bool isUnset() const
{
if (getPort() == 0)
return true;
if (m_family == AF_INET && getIP() == 0)
return true;
return false;
}
// ------------------------------------------------------------------------
/** Resets ip and port to 0. */
void clear()
{
m_family = AF_INET;
m_sockaddr.fill(0);
sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
in->sin_family = AF_INET;
} // clear
// ------------------------------------------------------------------------
uint32_t getIP() const;
// ------------------------------------------------------------------------
uint16_t getPort() const;
// ------------------------------------------------------------------------
void setIP(uint32_t ip);
// ------------------------------------------------------------------------
void setPort(uint16_t port);
// ------------------------------------------------------------------------
std::string toString(bool show_port = true) const;
// ------------------------------------------------------------------------
sockaddr* getSockaddr() const { return (sockaddr*)m_sockaddr.data(); }
// ------------------------------------------------------------------------
socklen_t getSocklen() const
{
if (m_family == AF_INET)
return sizeof(sockaddr_in);
else if (m_family == AF_INET6)
return sizeof(sockaddr_in6);
return 0;
}
// ------------------------------------------------------------------------
void setSockAddrIn(short family, sockaddr* new_sockaddr, socklen_t len)
{
m_family = family;
m_sockaddr.fill(0);
memcpy(m_sockaddr.data(), new_sockaddr, len);
}
// ------------------------------------------------------------------------
short getFamily() const { return m_family; }
// ------------------------------------------------------------------------
bool isPublicAddressLocalhost() const;
// ------------------------------------------------------------------------
/** Return true if this is an IPv6 address, if it's an IPv4 mapped IPv6
* address it will return false (::ffff:x.y.x.w). */
bool isIPv6() const
{
if (m_family == AF_INET6)
{
if (getIP() != 0)
return false;
return true;
}
return false;
}
// ------------------------------------------------------------------------
bool isLoopback() const;
// ------------------------------------------------------------------------
void convertForIPv6Socket();
}; // SocketAddress
#endif // HEADER_SOCKET_ADDRESS_HPP

View File

@ -48,6 +48,28 @@ extern "C"
#include <string>
// ----------------------------------------------------------------------------
bool isIPv4MappedAddress(const struct sockaddr_in6* in6)
{
uint8_t w0 = in6->sin6_addr.s6_addr[0];
uint8_t w1 = in6->sin6_addr.s6_addr[1];
uint8_t w2 = in6->sin6_addr.s6_addr[2];
uint8_t w3 = in6->sin6_addr.s6_addr[3];
uint8_t w4 = in6->sin6_addr.s6_addr[4];
uint8_t w5 = in6->sin6_addr.s6_addr[5];
uint8_t w6 = in6->sin6_addr.s6_addr[6];
uint8_t w7 = in6->sin6_addr.s6_addr[7];
uint8_t w8 = in6->sin6_addr.s6_addr[8];
uint8_t w9 = in6->sin6_addr.s6_addr[9];
uint8_t w10 = in6->sin6_addr.s6_addr[10];
uint8_t w11 = in6->sin6_addr.s6_addr[11];
if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 &&
w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 &&
w10 == 0xff && w11 == 0xff)
return true;
return false;
} // isIPv4MappedAddress
// ----------------------------------------------------------------------------
std::string getIPV6ReadableFromIn6(const struct sockaddr_in6* in)
{
@ -338,21 +360,7 @@ void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea)
return;
}
uint8_t w0 = in6->sin6_addr.s6_addr[0];
uint8_t w1 = in6->sin6_addr.s6_addr[1];
uint8_t w2 = in6->sin6_addr.s6_addr[2];
uint8_t w3 = in6->sin6_addr.s6_addr[3];
uint8_t w4 = in6->sin6_addr.s6_addr[4];
uint8_t w5 = in6->sin6_addr.s6_addr[5];
uint8_t w6 = in6->sin6_addr.s6_addr[6];
uint8_t w7 = in6->sin6_addr.s6_addr[7];
uint8_t w8 = in6->sin6_addr.s6_addr[8];
uint8_t w9 = in6->sin6_addr.s6_addr[9];
uint8_t w10 = in6->sin6_addr.s6_addr[10];
uint8_t w11 = in6->sin6_addr.s6_addr[11];
if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 &&
w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 &&
w10 == 0xff && w11 == 0xff)
if (isIPv4MappedAddress(in6))
{
ea->host = ((in_addr*)(in6->sin6_addr.s6_addr + 12))->s_addr;
ea->port = ntohs(in6->sin6_port);

View File

@ -39,3 +39,4 @@ std::string getIPV6ReadableFromIn6(const struct sockaddr_in6* in);
bool sameIPV6(const struct sockaddr_in6* in_1,
const struct sockaddr_in6* in_2);
void removeDisconnectedMappedAddress();
bool isIPv4MappedAddress(const struct sockaddr_in6* in6);