Browse Source

Infer ipv6_server from bind_address; fix client connect to IN(6)ADDR_ANY

Kahrl 10 năm trước cách đây
mục cha
commit
6090e95cdc
7 tập tin đã thay đổi với 87 bổ sung46 xóa
  1. 1 0
      minetest.conf.example
  2. 36 27
      src/game.cpp
  3. 22 16
      src/main.cpp
  4. 3 2
      src/server.cpp
  5. 2 1
      src/server.h
  6. 21 0
      src/socket.cpp
  7. 2 0
      src/socket.h

+ 1 - 0
minetest.conf.example

@@ -438,6 +438,7 @@
 #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 =

+ 36 - 27
src/game.cpp

@@ -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

+ 22 - 16
src/main.cpp

@@ -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")) {

+ 3 - 2
src/server.cpp

@@ -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),

+ 2 - 1
src/server.h

@@ -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);

+ 21 - 0
src/socket.cpp

@@ -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;

+ 2 - 0
src/socket.h

@@ -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;