diff --git a/sources.cmake b/sources.cmake index 3b80aee29..45b0a1856 100644 --- a/sources.cmake +++ b/sources.cmake @@ -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/*") diff --git a/src/main.cpp b/src/main.cpp index bbc12098f..d6498e80e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -573,6 +573,7 @@ void cmdLineHelp() // " (so n=1 means all Ais will be the test ai)\n" // " " --server=name Start a server (not a playing client).\n" + " --public-server Allow direct connection to the server (without stk server)\n" " --lan-server=name Start a LAN server (not a playing client).\n" " --server-password= Sets a password for a server (both client&server).\n" " --connect-now=ip Connect to a server with IP known now (in format x.x.x.x:xxx(port)).\n" @@ -987,6 +988,10 @@ int handleCmdLine() NetworkConfig::get()->setClientPort(n); NetworkConfig::get()->setServerPort(n); } + if (CommandLine::has("--public-server")) + { + NetworkConfig::get()->setIsPublicServer(); + } if (CommandLine::has("--connect-now", &s)) { TransportAddress ip(s); @@ -1926,6 +1931,8 @@ void runUnitTests() GraphicsRestrictions::unitTesting(); Log::info("UnitTest", "NetworkString"); NetworkString::unitTesting(); + Log::info("UnitTest", "TransportAddress"); + TransportAddress::unitTesting(); Log::info("UnitTest", "Easter detection"); // Test easter mode: in 2015 Easter is 5th of April - check with 0 days diff --git a/src/network/network_config.cpp b/src/network/network_config.cpp index 83e8111d8..efa329b48 100644 --- a/src/network/network_config.cpp +++ b/src/network/network_config.cpp @@ -37,6 +37,7 @@ NetworkConfig::NetworkConfig() { m_network_type = NETWORK_NONE; m_is_server = false; + m_is_public_server = false; m_max_players = 4; m_is_registered = false; m_server_name = ""; diff --git a/src/network/network_config.hpp b/src/network/network_config.hpp index 935a373d2..b7ce8d726 100644 --- a/src/network/network_config.hpp +++ b/src/network/network_config.hpp @@ -34,11 +34,18 @@ private: static NetworkConfig *m_network_config; enum NetworkType - { NETWORK_NONE, NETWORK_WAN, NETWORK_LAN }; + { + NETWORK_NONE, NETWORK_WAN, NETWORK_LAN + }; /** Keeps the type of network connection: none (yet), LAN or WAN. */ NetworkType m_network_type; + /** If set it allows clients to connect directly to this server without + * using the stk server in between. It requires obviously that this + * server is accessible (through the firewall) from the outside. */ + bool m_is_public_server; + /** True if this host is a server, false otherwise. */ bool m_is_server; @@ -79,7 +86,7 @@ public: /** Singleton get, which creates this object if necessary. */ static NetworkConfig *get() { - if(!m_network_config) + if (!m_network_config) m_network_config = new NetworkConfig(); return m_network_config; } // get @@ -102,19 +109,19 @@ public: } // setServerDiscoveryPort // ------------------------------------------------------------------------ /** Sets the port on which this server listens. */ - void setServerPort(uint16_t port) { m_server_port = port; } + void setServerPort(uint16_t port) { m_server_port = port; } // ------------------------------------------------------------------------ /** Sets the port on which a client listens for server connection. */ - void setClientPort(uint16_t port) { m_client_port = port; } + void setClientPort(uint16_t port) { m_client_port = port; } // ------------------------------------------------------------------------ /** Returns the port on which this server listenes. */ - uint16_t getServerPort() const { return m_server_port; } + uint16_t getServerPort() const { return m_server_port; } // ------------------------------------------------------------------------ /** Returns the port for LAN server discovery. */ uint16_t getServerDiscoveryPort() const { return m_server_discovery_port; } // ------------------------------------------------------------------------ /** Returns the port on which a client listens for server connections. */ - uint16_t getClientPort() const { return m_client_port; } + uint16_t getClientPort() const { return m_client_port; } // ------------------------------------------------------------------------ /** Sets the password for a server. */ void setPassword(const std::string &password) { m_password = password; } @@ -122,6 +129,12 @@ public: /** Returns the password. */ const std::string& getPassword() const { return m_password; } // ------------------------------------------------------------------------ + /** Sets that this server can be contacted directly. */ + void setIsPublicServer() { m_is_public_server = true; } + // ------------------------------------------------------------------------ + /** Returns if connections directly to the server are to be accepted. */ + bool isPublicServer() const { return m_is_public_server; } + // ------------------------------------------------------------------------ /** Return if a network setting is happening. A network setting is active * if a host (server or client) exists. */ bool isNetworking() const { return m_network_type!=NETWORK_NONE; } diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index aea6f170b..0583a88a9 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -529,7 +529,7 @@ void* STKHost::mainLoop(void* self) ENetHost* host = myself->m_network->getENetHost(); if(NetworkConfig::get()->isServer() && - NetworkConfig::get()->isLAN() ) + (NetworkConfig::get()->isLAN() || NetworkConfig::get()->isPublicServer()) ) { TransportAddress address(0, NetworkConfig::get()->getServerDiscoveryPort()); ENetAddress eaddr = address.toEnetAddress(); @@ -604,6 +604,7 @@ void STKHost::handleDirectSocketRequest() BareNetworkString message(buffer, len); std::string command; message.decodeString(&command); + if (command == "stk-server") { Log::verbose("STKHost", "Received LAN server query"); @@ -629,6 +630,15 @@ void STKHost::handleDirectSocketRequest() } // if message is server-requested else if (command == "connection-request") { + // In case of a LAN connection, we only allow connections from + // a LAN address (192.168*, ..., and 127.*). + if (NetworkConfig::get()->isLAN() && !sender.isLAN()) + { + Log::error("STKHost", "Client trying to connect from '%s'", + sender.toString().c_str()); + Log::error("STKHost", "which is outside of LAN - rejected."); + return; + } Protocol *c = new ConnectToPeer(sender); c->requestStart(); } diff --git a/src/network/transport_address.cpp b/src/network/transport_address.cpp new file mode 100644 index 000000000..f4aa09e29 --- /dev/null +++ b/src/network/transport_address.cpp @@ -0,0 +1,112 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 Joerg Henrichs +// +// 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/transport_address.hpp" + +/** 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 TransportAddress::isLAN() const +{ + uint32_t ip = getIP(); + 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 (ip >> 24 == 0x7f ) // 127.* localhost + return true; + return false; +} // isLAN + +// ---------------------------------------------------------------------------- +/** Unit testing. Test various LAN patterns to verify that isLAN() works as + * expected. + */ +void TransportAddress::unitTesting() +{ + TransportAddress t1("192.168.0.0"); + assert(t1.getIP() == (192 << 24) + (168 << 16)); + assert(t1.isLAN()); + + TransportAddress t2("192.168.255.255"); + assert(t2.getIP() == (192 << 24) + (168 << 16) + (255 << 8) + 255); + assert(t2.isLAN()); + + TransportAddress t3("193.168.0.1"); + assert(t3.getIP() == (193 << 24) + (168 << 16) + 1); + assert(!t3.isLAN()); + + TransportAddress t4("192.167.255.255"); + assert(t4.getIP() == (192 << 24) + (167 << 16) + (255 << 8) + 255); + assert(!t4.isLAN()); + + TransportAddress t5("192.169.0.0"); + assert(t5.getIP() == (192 << 24) + (169 << 16)); + assert(!t5.isLAN()); + + TransportAddress t6("172.16.0.0"); + assert(t6.getIP() == (172 << 24) + (16 << 16)); + assert(t6.isLAN()); + + TransportAddress t7("172.31.255.255"); + assert(t7.getIP() == (172 << 24) + (31 << 16) + (255 << 8) + 255); + assert(t7.isLAN()); + + TransportAddress t8("172.15.255.255"); + assert(t8.getIP() == (172 << 24) + (15 << 16) + (255 << 8) + 255); + assert(!t8.isLAN()); + + TransportAddress t9("172.32.0.0"); + assert(t9.getIP() == (172 << 24) + (32 << 16)); + assert(!t9.isLAN()); + + TransportAddress t10("10.0.0.0"); + assert(t10.getIP() == (10 << 24)); + assert(t10.isLAN()); + + TransportAddress t11("10.255.255.255"); + assert(t11.getIP() == (10 << 24) + (255 << 16) + (255 << 8) + 255); + assert(t11.isLAN()); + + TransportAddress t12("9.255.255.255"); + assert(t12.getIP() == (9 << 24) + (255 << 16) + (255 << 8) + 255); + assert(!t12.isLAN()); + + TransportAddress t13("11.0.0.0"); + assert(t13.getIP() == (11 << 24) ); + assert(!t13.isLAN()); + + TransportAddress t14("127.0.0.0"); + assert(t14.getIP() == (127 << 24)); + assert(t14.isLAN()); + + TransportAddress t15("127.255.255.255"); + assert(t15.getIP() == (127 << 24) + (255 << 16) + (255 << 8) + 255); + assert(t15.isLAN()); + + TransportAddress t16("126.255.255.255"); + assert(t16.getIP() == (126 << 24) + (255 << 16) + (255 << 8) + 255); + assert(!t16.isLAN()); + + TransportAddress t17("128.0.0.0"); + assert(t17.getIP() == (128 << 24)); + assert(t17.isLAN()); + +} // unitTesting \ No newline at end of file diff --git a/src/network/transport_address.hpp b/src/network/transport_address.hpp index 1767770bd..2e33fb01f 100644 --- a/src/network/transport_address.hpp +++ b/src/network/transport_address.hpp @@ -63,23 +63,21 @@ public: { std::string combined = StringUtils::replace(str, ":", "."); std::vector ip = StringUtils::splitToUInt(combined, '.'); - m_ip = 0; + m_ip = 0; m_port = 0; - if (ip.size() == 5) - { + if (ip.size() >= 4) m_ip = (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3]; + + if(ip.size()==5) m_port = (uint16_t)(ip[4] < 65536 ? ip[4] : 0); - } else - { - m_ip = 0; m_port = 0; - } } // TransportAddress(string of ip) // ------------------------------------------------------------------------ ~TransportAddress() {} // ------------------------------------------------------------------------ + static void unitTesting(); private: friend class NetworkConfig; /** The copy constructor is private, so that the friend class @@ -90,6 +88,7 @@ private: copy(other); } // TransportAddress(const TransportAddress&) public: + bool isLAN() const; // ------------------------------------------------------------------------ /** A copy function (to replace the copy constructor which is disabled * using NoCopy): it copies the data from the argument into this object.*/