Add socket address to support both IPv4 and IPv6
This commit is contained in:
parent
a79a2a7fab
commit
6abd3bbf69
@ -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/*")
|
||||
|
@ -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();
|
||||
|
||||
|
576
src/network/socket_address.cpp
Normal file
576
src/network/socket_address.cpp
Normal 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
|
144
src/network/socket_address.hpp
Normal file
144
src/network/socket_address.hpp
Normal 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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user