Add firewall penetration for IPv6 client

This commit is contained in:
Benau 2020-01-27 12:07:28 +08:00
parent 6abd3bbf69
commit 9132fba714
10 changed files with 177 additions and 19 deletions

View File

@ -23,6 +23,7 @@
#include "network/event.hpp" #include "network/event.hpp"
#include "network/network_config.hpp" #include "network/network_config.hpp"
#include "network/network_string.hpp" #include "network/network_string.hpp"
#include "network/socket_address.hpp"
#include "network/transport_address.hpp" #include "network/transport_address.hpp"
#include "utils/file_utils.hpp" #include "utils/file_utils.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -179,6 +180,90 @@ int Network::receiveRawPacket(char *buffer, int buf_len,
return len; return len;
} // receiveRawPacket } // receiveRawPacket
// ----------------------------------------------------------------------------
/** \brief Sends a packet whithout ENet adding its headers.
* This function is used in particular to achieve the STUN protocol.
* \param data : Data to send.
* \param dst : Destination of the packet.
*/
void Network::sendRawPacket(const BareNetworkString &buffer,
const SocketAddress& dst)
{
sendto(m_host->socket, buffer.getData(), buffer.size(), 0,
dst.getSockaddr(), dst.getSocklen());
if (m_connection_debug)
{
Log::verbose("Network", "Raw packet sent to %s",
dst.toString().c_str());
}
Network::logPacket(buffer, false);
} // sendRawPacket
// ----------------------------------------------------------------------------
/** \brief Receives a packet directly from the network interface and
* filter its address.
* Receive a packet whithout ENet processing it. Checks that the
* sender of the packet is the one that corresponds to the sender
* parameter. Does not check the port right now.
* \param buffer A buffer to receive the data in.
* \param buf_len Length of the buffer.
* \param[out] sender : Transport address of the original sender of the
* wanted packet. If the ip address is 0, do not check
* the sender's ip address, otherwise wait till a message
* from the specified sender arrives. All other messages
* are discarded.
* \param max_tries : Number of times we try to read data from the
* socket. This is aproximately the time we wait in
* milliseconds. -1 means eternal tries.
* \return Length of the received data, or -1 if no data was received.
*/
int Network::receiveRawPacket(char *buffer, int buf_len,
SocketAddress *sender, int max_tries)
{
memset(buffer, 0, buf_len);
struct sockaddr_storage addr = {};
socklen_t from_len = sizeof(addr);
int len = recvfrom(m_host->socket, buffer, buf_len, 0,
(struct sockaddr*)(&addr), &from_len);
int count = 0;
// wait to receive the message because enet sockets are non-blocking
while(len < 0 && (count<max_tries || max_tries==-1) )
{
count++;
StkTime::sleep(1); // wait 1 millisecond between two checks
len = recvfrom(m_host->socket, buffer, buf_len, 0,
(struct sockaddr*)(&addr), &from_len);
}
// No message received
if(len<0)
return -1;
Network::logPacket(BareNetworkString(buffer, len), true);
switch (addr.ss_family)
{
case AF_INET:
sender->setSockAddrIn(AF_INET, (sockaddr*)(&addr),
sizeof(sockaddr_in));
break;
case AF_INET6:
sender->setSockAddrIn(AF_INET6, (sockaddr*)(&addr),
sizeof(sockaddr_in6));
break;
default:
break;
}
if (m_connection_debug)
{
Log::verbose("Network", "Address of the sender was %s",
sender->toString().c_str());
}
return len;
} // receiveRawPacket
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** \brief Broadcasts a packet to all peers. /** \brief Broadcasts a packet to all peers.
* \param data : Data to send. * \param data : Data to send.

View File

@ -37,6 +37,7 @@
class BareNetworkString; class BareNetworkString;
class NetworkString; class NetworkString;
class TransportAddress; class TransportAddress;
class SocketAddress;
/** \class EnetHost /** \class EnetHost
* A small wrapper around enet to allow sending and receiving * A small wrapper around enet to allow sending and receiving
@ -68,6 +69,10 @@ public:
const TransportAddress& dst); const TransportAddress& dst);
int receiveRawPacket(char *buffer, int buf_len, int receiveRawPacket(char *buffer, int buf_len,
TransportAddress* sender, int max_tries = -1); TransportAddress* sender, int max_tries = -1);
void sendRawPacket(const BareNetworkString &buffer,
const SocketAddress& dst);
int receiveRawPacket(char *buffer, int buf_len,
SocketAddress* sender, int max_tries = -1);
void broadcastPacket(NetworkString *data, void broadcastPacket(NetworkString *data,
bool reliable = true); bool reliable = true);

View File

@ -17,7 +17,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "network/protocols/connect_to_peer.hpp" #include "network/protocols/connect_to_peer.hpp"
#include "network/network.hpp"
#include "network/stk_host.hpp" #include "network/stk_host.hpp"
#include "utils/time.hpp" #include "utils/time.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -26,7 +26,7 @@
/** Constructor for peer address. /** Constructor for peer address.
* \param address The address to connect to. * \param address The address to connect to.
*/ */
ConnectToPeer::ConnectToPeer(const TransportAddress &address) ConnectToPeer::ConnectToPeer(const SocketAddress &address)
: Protocol(PROTOCOL_CONNECTION) : Protocol(PROTOCOL_CONNECTION)
{ {
m_peer_address = address; m_peer_address = address;
@ -62,13 +62,14 @@ void ConnectToPeer::asynchronousUpdate()
// the client will use enet intercept to discover if server // the client will use enet intercept to discover if server
// address or port is different from stk addons database. // address or port is different from stk addons database.
// (Happens if there is firewall in between) // (Happens if there is firewall in between)
TransportAddress broadcast_address; BareNetworkString aloha("aloha-stk");
broadcast_address = m_peer_address;
// Enet packet will not have 0xFFFF for first 2 bytes // Enet packet will not have 0xFFFF for first 2 bytes
BareNetworkString aloha("aloha-stk"); // We use the feature to distinguish between the enet packets
// and this aloha
aloha.getBuffer().insert(aloha.getBuffer().begin(), 2, 0xFF); aloha.getBuffer().insert(aloha.getBuffer().begin(), 2, 0xFF);
STKHost::get()->sendRawPacket(aloha, broadcast_address);
STKHost::get()->sendRawPacket(aloha, m_peer_address);
Log::debug("ConnectToPeer", "Broadcast aloha sent."); Log::debug("ConnectToPeer", "Broadcast aloha sent.");
// 20 seconds timeout // 20 seconds timeout
if (m_tried_connection++ > 10) if (m_tried_connection++ > 10)

View File

@ -20,7 +20,7 @@
#define CONNECT_TO_PEER_HPP #define CONNECT_TO_PEER_HPP
#include "network/protocol.hpp" #include "network/protocol.hpp"
#include "network/transport_address.hpp" #include "network/socket_address.hpp"
#include "utils/cpp2011.hpp" #include "utils/cpp2011.hpp"
/** One instance of this is started for every peer who tries to /** One instance of this is started for every peer who tries to
@ -29,8 +29,7 @@
class ConnectToPeer : public Protocol class ConnectToPeer : public Protocol
{ {
protected: protected:
SocketAddress m_peer_address;
TransportAddress m_peer_address;
/** Timer use for tracking broadcast. */ /** Timer use for tracking broadcast. */
uint64_t m_timer = 0; uint64_t m_timer = 0;
@ -46,7 +45,7 @@ protected:
} m_state; } m_state;
public: public:
ConnectToPeer(const TransportAddress &address); ConnectToPeer(const SocketAddress &address);
virtual ~ConnectToPeer() {} virtual ~ConnectToPeer() {}
virtual void setup() OVERRIDE {} virtual void setup() OVERRIDE {}
virtual void update(int ticks) OVERRIDE {} virtual void update(int ticks) OVERRIDE {}

View File

@ -31,6 +31,7 @@
#include "network/crypto.hpp" #include "network/crypto.hpp"
#include "network/event.hpp" #include "network/event.hpp"
#include "network/game_setup.hpp" #include "network/game_setup.hpp"
#include "network/network.hpp"
#include "network/network_config.hpp" #include "network/network_config.hpp"
#include "network/network_player_profile.hpp" #include "network/network_player_profile.hpp"
#include "network/peer_vote.hpp" #include "network/peer_vote.hpp"
@ -2604,7 +2605,9 @@ void ServerLobby::checkIncomingConnectionRequests()
{ {
uint32_t addr, id; uint32_t addr, id;
uint16_t port; uint16_t port;
std::string ipv6;
users_xml->getNode(i)->get("ip", &addr); users_xml->getNode(i)->get("ip", &addr);
users_xml->getNode(i)->get("ipv6", &ipv6);
users_xml->getNode(i)->get("port", &port); users_xml->getNode(i)->get("port", &port);
users_xml->getNode(i)->get("id", &id); users_xml->getNode(i)->get("id", &id);
users_xml->getNode(i)->get("aes-key", &keys[id].m_aes_key); users_xml->getNode(i)->get("aes-key", &keys[id].m_aes_key);
@ -2615,7 +2618,10 @@ void ServerLobby::checkIncomingConnectionRequests()
keys[id].m_tried = false; keys[id].m_tried = false;
if (ServerConfig::m_firewalled_server) if (ServerConfig::m_firewalled_server)
{ {
TransportAddress peer_addr(addr, port); SocketAddress peer_addr(addr, port);
if (!ipv6.empty())
peer_addr.init(ipv6, port);
peer_addr.convertForIPv6Socket();
std::string peer_addr_str = peer_addr.toString(); std::string peer_addr_str = peer_addr.toString();
if (sl->m_pending_peer_connection.find(peer_addr_str) != if (sl->m_pending_peer_connection.find(peer_addr_str) !=
sl->m_pending_peer_connection.end()) sl->m_pending_peer_connection.end())

View File

@ -344,9 +344,7 @@ void loadServerLobbyFromConfig()
if (m_ipv6_server) if (m_ipv6_server)
{ {
#ifdef ENABLE_IPV6 #ifndef ENABLE_IPV6
m_firewalled_server = false;
#else
Log::warn("ServerConfig", "IPv6 support not compiled."); Log::warn("ServerConfig", "IPv6 support not compiled.");
#endif #endif
} }

View File

@ -1302,7 +1302,7 @@ void STKHost::handleDirectSocketRequest(Network* direct_socket,
const int LEN=2048; const int LEN=2048;
char buffer[LEN]; char buffer[LEN];
TransportAddress sender; SocketAddress sender;
int len = direct_socket->receiveRawPacket(buffer, LEN, &sender, 1); int len = direct_socket->receiveRawPacket(buffer, LEN, &sender, 1);
if(len<=0) return; if(len<=0) return;
BareNetworkString message(buffer, len); BareNetworkString message(buffer, len);
@ -1383,6 +1383,25 @@ bool STKHost::peerExists(const TransportAddress& peer)
return false; return false;
} // peerExists } // peerExists
// ----------------------------------------------------------------------------
/** \brief Tells if a peer is known.
* \return True if the peer is known, false elseway.
*/
bool STKHost::peerExists(const SocketAddress& peer)
{
std::lock_guard<std::mutex> lock(m_peers_mutex);
for (auto p : m_peers)
{
auto stk_peer = p.second;
if (stk_peer->getSocketAddress() == peer ||
((stk_peer->getSocketAddress().isPublicAddressLocalhost() &&
peer.isPublicAddressLocalhost()) &&
stk_peer->getSocketAddress().getPort() == peer.getPort()))
return true;
}
return false;
} // peerExists
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** \brief Return the only server peer for client. /** \brief Return the only server peer for client.
* \return STKPeer the STKPeer of server. * \return STKPeer the STKPeer of server.
@ -1691,3 +1710,17 @@ std::string STKHost::getVaildPublicAddress() const
return m_public_address.toString(); return m_public_address.toString();
return ""; return "";
} // getVaildPublicAddress } // getVaildPublicAddress
// ----------------------------------------------------------------------------
int STKHost::receiveRawPacket(char *buffer, int buffer_len,
SocketAddress* sender, int max_tries)
{
return m_network->receiveRawPacket(buffer, buffer_len, sender,
max_tries);
} // receiveRawPacket
// ----------------------------------------------------------------------------
void STKHost::sendRawPacket(const BareNetworkString &buffer,
const SocketAddress& dst)
{
m_network->sendRawPacket(buffer, dst);
} // sendRawPacket

View File

@ -54,6 +54,7 @@ class NetworkTimerSynchronizer;
class Server; class Server;
class ServerLobby; class ServerLobby;
class SeparateProcess; class SeparateProcess;
class SocketAddress;
enum ENetCommandType : unsigned int enum ENetCommandType : unsigned int
{ {
@ -273,6 +274,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool peerExists(const TransportAddress& peer_address); bool peerExists(const TransportAddress& peer_address);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool peerExists(const SocketAddress& peer_address);
// ------------------------------------------------------------------------
bool isConnectedTo(const TransportAddress& peer_address); bool isConnectedTo(const TransportAddress& peer_address);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
std::shared_ptr<STKPeer> getServerPeerForClient() const; std::shared_ptr<STKPeer> getServerPeerForClient() const;
@ -307,6 +310,12 @@ public:
m_network->sendRawPacket(buffer, dst); m_network->sendRawPacket(buffer, dst);
} // sendRawPacket } // sendRawPacket
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
int receiveRawPacket(char *buffer, int buffer_len,
SocketAddress* sender, int max_tries = -1);
// ------------------------------------------------------------------------
void sendRawPacket(const BareNetworkString &buffer,
const SocketAddress& dst);
// ------------------------------------------------------------------------
Network* getNetwork() const { return m_network; } Network* getNetwork() const { return m_network; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns a copied list of peers. */ /** Returns a copied list of peers. */

View File

@ -23,6 +23,7 @@
#include "network/event.hpp" #include "network/event.hpp"
#include "network/network_config.hpp" #include "network/network_config.hpp"
#include "network/network_string.hpp" #include "network/network_string.hpp"
#include "network/socket_address.hpp"
#include "network/stk_ipv6.hpp" #include "network/stk_ipv6.hpp"
#include "network/stk_host.hpp" #include "network/stk_host.hpp"
#include "network/transport_address.hpp" #include "network/transport_address.hpp"
@ -38,9 +39,25 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id)
: m_peer_address(enet_peer->address), m_host(host) : m_peer_address(enet_peer->address), m_host(host)
{ {
m_addons_scores.fill(-1); m_addons_scores.fill(-1);
// We use 0.x.x.x ip to map to IPv6 address internally uint32_t addr = htonl(enet_peer->address.host);
if (m_peer_address.getIP() < 16777216) #ifdef ENABLE_IPV6
m_ipv6_address = getIPV6ReadableFromMappedAddress(&enet_peer->address); if (isIPv6Socket())
{
// This will return the mapped IPv4 address too for IPv6 socket
// So we can sendto directly with it
struct sockaddr_in6 in6 = {};
getIPV6FromMappedAddress(&enet_peer->address, &in6);
m_socket_address.reset(new SocketAddress());
m_socket_address->setSockAddrIn(AF_INET6, (sockaddr*)&in6, sizeof(in6));
if (m_socket_address->isIPv6())
m_ipv6_address = m_socket_address->toString(false/*show_port*/);
}
else
#endif
{
m_socket_address.reset(
new SocketAddress(addr, enet_peer->address.port));
}
m_enet_peer = enet_peer; m_enet_peer = enet_peer;
m_host_id = host_id; m_host_id = host_id;
m_connected_time = StkTime::getMonoTimeMs(); m_connected_time = StkTime::getMonoTimeMs();

View File

@ -43,7 +43,7 @@ class Crypto;
class NetworkPlayerProfile; class NetworkPlayerProfile;
class NetworkString; class NetworkString;
class STKHost; class STKHost;
class TransportAddress; class SocketAddress;
enum PeerDisconnectInfo : unsigned int enum PeerDisconnectInfo : unsigned int
{ {
@ -89,6 +89,8 @@ protected:
TransportAddress m_peer_address; TransportAddress m_peer_address;
std::unique_ptr<SocketAddress> m_socket_address;
STKHost* m_host; STKHost* m_host;
std::vector<std::shared_ptr<NetworkPlayerProfile> > m_players; std::vector<std::shared_ptr<NetworkPlayerProfile> > m_players;
@ -293,6 +295,9 @@ public:
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
int getConsecutiveMessages() const { return m_consecutive_messages; } int getConsecutiveMessages() const { return m_consecutive_messages; }
// ------------------------------------------------------------------------
const SocketAddress& getSocketAddress() const
{ return *m_socket_address.get(); }
}; // STKPeer }; // STKPeer
#endif // STK_PEER_HPP #endif // STK_PEER_HPP