Infer ipv6_server from bind_address; fix client connect to IN(6)ADDR_ANY
authorKahrl <kahrl@gmx.net>
Fri, 7 Mar 2014 00:00:03 +0000 (01:00 +0100)
committersapier <Sapier at GMX dot net>
Thu, 10 Apr 2014 20:03:42 +0000 (22:03 +0200)
minetest.conf.example
src/game.cpp
src/main.cpp
src/server.cpp
src/server.h
src/socket.cpp
src/socket.h

index f728d6c88168b0b81666c82c34e3d89e8edf0e00..4e4495338b6ee866a68be03a5764bac99be1e686 100644 (file)
 #enable_ipv6 = true
 # Enable/disable running an IPv6 server.  An IPv6 server may be restricted
 # to IPv6 clients, depending on system configuration.
+# Ignored if bind_address is set.
 #ipv6_server = false
 
 #main_menu_script =
index 7d881fa88377c5746b5027dfc0754169ed7029d1..f435a4d71ad7f2b4091291be408295e3b7533a63 100644 (file)
@@ -1147,28 +1147,35 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                draw_load_screen(text, device, font,0,25);
                delete[] text;
                infostream<<"Creating server"<<std::endl;
-               server = new Server(map_dir, gamespec,
-                               simple_singleplayer_mode);
 
                std::string bind_str = g_settings->get("bind_address");
                Address bind_addr(0,0,0,0, port);
 
-               if (bind_str != "")
-               {
-                       try {
-                               bind_addr.Resolve(bind_str.c_str());
-                               address = bind_str;
-                       } catch (ResolveError &e) {
-                               infostream << "Resolving bind address \"" << bind_str
-                                                  << "\" failed: " << e.what()
-                                                  << " -- Listening on all addresses." << std::endl;
+               if (g_settings->getBool("ipv6_server")) {
+                       bind_addr.setAddress((IPv6AddressBytes*) NULL);
+               }
+               try {
+                       bind_addr.Resolve(bind_str.c_str());
+                       address = bind_str;
+               } catch (ResolveError &e) {
+                       infostream << "Resolving bind address \"" << bind_str
+                                          << "\" failed: " << e.what()
+                                          << " -- Listening on all addresses." << std::endl;
+               }
 
-                               if (g_settings->getBool("ipv6_server")) {
-                                       bind_addr.setAddress((IPv6AddressBytes*) NULL);
-                               }
-                       }
+               if(bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
+                       error_message = L"Unable to listen on " +
+                               narrow_to_wide(bind_addr.serializeString()) +
+                               L" because IPv6 is disabled";
+                       errorstream<<wide_to_narrow(error_message)<<std::endl;
+                       // Break out of client scope
+                       return;
                }
 
+               server = new Server(map_dir, gamespec,
+                               simple_singleplayer_mode,
+                               bind_addr.isIPv6());
+
                server->start(bind_addr);
        }
 
@@ -1193,31 +1200,33 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                delete[] text;
        }
        Address connect_address(0,0,0,0, port);
-       try{
-               if(address == "")
-               {
+       try {
+               connect_address.Resolve(address.c_str());
+               if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY
                        //connect_address.Resolve("localhost");
-                       if(g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"))
-                       {
+                       if (connect_address.isIPv6()) {
                                IPv6AddressBytes addr_bytes;
                                addr_bytes.bytes[15] = 1;
                                connect_address.setAddress(&addr_bytes);
-                       }
-                       else
-                       {
+                       } else {
                                connect_address.setAddress(127,0,0,1);
                        }
                }
-               else
-                       connect_address.Resolve(address.c_str());
        }
-       catch(ResolveError &e)
-       {
+       catch(ResolveError &e) {
                error_message = L"Couldn't resolve address: " + narrow_to_wide(e.what());
                errorstream<<wide_to_narrow(error_message)<<std::endl;
                // Break out of client scope
                break;
        }
+       if(connect_address.isIPv6() && !g_settings->getBool("enable_ipv6")) {
+               error_message = L"Unable to connect to " +
+                       narrow_to_wide(connect_address.serializeString()) +
+                       L" because IPv6 is disabled";
+               errorstream<<wide_to_narrow(error_message)<<std::endl;
+               // Break out of client scope
+               break;
+       }
        
        /*
                Create client
index e520027729c87e01ddc2b43c5cfa0bbd13e897b6..baaf8ebde807e55ceacf4a3fa0e6014c317ec14a 100644 (file)
@@ -1023,21 +1023,6 @@ int main(int argc, char *argv[])
        if(port == 0)
                port = 30000;
 
-       // Bind address
-       std::string bind_str = g_settings->get("bind_address");
-       Address bind_addr(0,0,0,0, port);
-       try {
-               bind_addr.Resolve(bind_str.c_str());
-       } catch (ResolveError &e) {
-               infostream << "Resolving bind address \"" << bind_str
-                          << "\" failed: " << e.what()
-                          << " -- Listening on all addresses." << std::endl;
-
-               if (g_settings->getBool("ipv6_server")) {
-                       bind_addr.setAddress((IPv6AddressBytes*) NULL);
-               }
-       }
-
        // World directory
        std::string commanded_world = "";
        if(cmd_args.exists("world"))
@@ -1223,8 +1208,29 @@ int main(int argc, char *argv[])
                }
                verbosestream<<_("Using gameid")<<" ["<<gamespec.id<<"]"<<std::endl;
 
+               // Bind address
+               std::string bind_str = g_settings->get("bind_address");
+               Address bind_addr(0,0,0,0, port);
+
+               if (g_settings->getBool("ipv6_server")) {
+                       bind_addr.setAddress((IPv6AddressBytes*) NULL);
+               }
+               try {
+                       bind_addr.Resolve(bind_str.c_str());
+               } catch (ResolveError &e) {
+                       infostream << "Resolving bind address \"" << bind_str
+                                  << "\" failed: " << e.what()
+                                  << " -- Listening on all addresses." << std::endl;
+               }
+               if(bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
+                       errorstream << "Unable to listen on "
+                                   << bind_addr.serializeString()
+                                   << L" because IPv6 is disabled" << std::endl;
+                       return 1;
+               }
+
                // Create server
-               Server server(world_path, gamespec, false);
+               Server server(world_path, gamespec, false, bind_addr.isIPv6());
 
                // Database migration
                if (cmd_args.exists("migrate")) {
index 0cd8630c334468ba339af95da6657bde04ea9da6..5c93988b8f3ac02d1d902628572e3d84852db05e 100644 (file)
@@ -166,7 +166,8 @@ v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
 Server::Server(
                const std::string &path_world,
                const SubgameSpec &gamespec,
-               bool simple_singleplayer_mode
+               bool simple_singleplayer_mode,
+               bool ipv6
        ):
        m_path_world(path_world),
        m_gamespec(gamespec),
@@ -176,7 +177,7 @@ Server::Server(
        m_con(PROTOCOL_ID,
                        512,
                        CONNECTION_TIMEOUT,
-                       g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
+                       ipv6,
                        this),
        m_banmanager(NULL),
        m_rollback(NULL),
index c0928e5743d579a8f4a06203a4718e52b9badf85..ab89fbc6e165d69fdf9374672c5578b18a92a4eb 100644 (file)
@@ -174,7 +174,8 @@ public:
        Server(
                const std::string &path_world,
                const SubgameSpec &gamespec,
-               bool simple_singleplayer_mode
+               bool simple_singleplayer_mode,
+               bool ipv6
        );
        ~Server();
        void start(Address bind_addr);
index 00856fb0094133890cf6754ef073d560591ef7a5..bca9c5390b987a58f9e412b96a88535a79ba890e 100644 (file)
@@ -143,6 +143,15 @@ bool Address::operator!=(Address &address)
 
 void Address::Resolve(const char *name)
 {
+       if (!name || name[0] == 0) {
+               if (m_addr_family == AF_INET) {
+                       setAddress((u32) 0);
+               } else if (m_addr_family == AF_INET6) {
+                       setAddress((IPv6AddressBytes*) 0);
+               }
+               return;
+       }
+
        struct addrinfo *resolved, hints;
        memset(&hints, 0, sizeof(hints));
        
@@ -251,6 +260,18 @@ bool Address::isIPv6() const
        return m_addr_family == AF_INET6;
 }
 
+bool Address::isZero() const
+{
+       if (m_addr_family == AF_INET) {
+               return m_address.ipv4.sin_addr.s_addr == 0;
+       } else if (m_addr_family == AF_INET6) {
+               static const char zero[16] = {0};
+               return memcmp(m_address.ipv6.sin6_addr.s6_addr,
+                             zero, 16) == 0;
+       }
+       return false;
+}
+
 void Address::setAddress(u32 address)
 {
        m_addr_family = AF_INET;
index 7d35a32da0e793a91b0dc70b75e9918bd21a6be0..92e0cbb13034baa8ca6efac168943cb620626758 100644 (file)
@@ -88,6 +88,7 @@ public:
        Address(const IPv6AddressBytes * ipv6_bytes, u16 port);
        bool operator==(Address &address);
        bool operator!=(Address &address);
+       // Resolve() may throw ResolveError (address is unchanged in this case)
        void Resolve(const char *name);
        struct sockaddr_in getAddress() const;
        unsigned short getPort() const;
@@ -97,6 +98,7 @@ public:
        struct sockaddr_in6 getAddress6() const;
        int getFamily() const;
        bool isIPv6() const;
+       bool isZero() const;
        void setPort(unsigned short port);
        void print(std::ostream *s) const;
        std::string serializeString() const;