From eabe4eb97e1d1c3c8faf93335bdee6b6bce57523 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Wed, 26 Oct 2016 14:43:47 +0200 Subject: [PATCH] Improve remote server console host support when binding to 0.0.0.0 Fix https://github.com/GNS3/gns3-gui/issues/1574 --- gns3server/compute/port_manager.py | 32 ++++++++++++------------------ gns3server/controller/__init__.py | 4 ++++ gns3server/controller/compute.py | 10 +++++++++- gns3server/controller/node.py | 2 +- gns3server/web/web_server.py | 14 +++++++------ tests/compute/test_port_manager.py | 15 ++++++++++++++ tests/conftest.py | 7 ++++--- tests/controller/test_node.py | 2 +- 8 files changed, 55 insertions(+), 31 deletions(-) diff --git a/gns3server/compute/port_manager.py b/gns3server/compute/port_manager.py index 2681abb5..207183c0 100644 --- a/gns3server/compute/port_manager.py +++ b/gns3server/compute/port_manager.py @@ -16,7 +16,6 @@ # along with this program. If not, see . import socket -import ipaddress from aiohttp.web import HTTPConflict from gns3server.config import Config @@ -37,10 +36,8 @@ class PortManager: :param host: IP address to bind for console connections """ - def __init__(self, host="127.0.0.1"): - - self._console_host = host - + def __init__(self): + self._console_host = None # UDP host must be 0.0.0.0, reason: https://github.com/GNS3/gns3-server/issues/265 self._udp_host = "0.0.0.0" self._used_tcp_ports = set() @@ -59,17 +56,6 @@ class PortManager: self._udp_port_range = (udp_start_port_range, udp_end_port_range) log.debug("UDP port range is {}-{}".format(udp_start_port_range, udp_end_port_range)) - if remote_console_connections: - log.warning("Remote console connections are allowed") - if ipaddress.ip_address(host).version == 6: - self._console_host = "::" - else: - self._console_host = "0.0.0.0" - else: - self._console_host = host - - PortManager._instance = self - @classmethod def instance(cls): """ @@ -84,13 +70,21 @@ class PortManager: @property def console_host(self): - + assert self._console_host is not None return self._console_host @console_host.setter def console_host(self, new_host): - - self._console_host = new_host + """ + If allow remote connection we need to bind console host to 0.0.0.0 + """ + server_config = Config.instance().get_section_config("Server") + remote_console_connections = server_config.getboolean("allow_remote_console") + if remote_console_connections: + log.warning("Remote console connections are allowed") + self._console_host = "0.0.0.0" + else: + self._console_host = new_host @property def console_port_range(self): diff --git a/gns3server/controller/__init__.py b/gns3server/controller/__init__.py index 68cf6456..602571c2 100644 --- a/gns3server/controller/__init__.py +++ b/gns3server/controller/__init__.py @@ -57,12 +57,16 @@ class Controller: yield from self.load() server_config = Config.instance().get_section_config("Server") host = server_config.get("host", "localhost") + # If console_host is 0.0.0.0 client will use the ip they use + # to connect to the controller + console_host = host if host == "0.0.0.0": host = "127.0.0.1" yield from self.add_compute(compute_id="local", name=socket.gethostname(), protocol=server_config.get("protocol", "http"), host=host, + console_host=console_host, port=server_config.getint("port", 3080), user=server_config.get("user", ""), password=server_config.get("password", ""), diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 68dd397e..a892b4e0 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -73,7 +73,7 @@ class Compute: A GNS3 compute. """ - def __init__(self, compute_id, controller=None, protocol="http", host="localhost", port=3080, user=None, password=None, name=None): + def __init__(self, compute_id, controller=None, protocol="http", host="localhost", port=3080, user=None, password=None, name=None, console_host=None): self._http_session = None assert controller is not None log.info("Create compute %s", compute_id) @@ -87,6 +87,10 @@ class Compute: self.host = host self.port = port self._user = None + if console_host is None: + self._console_host = host + else: + self._console_host = console_host self._password = None self._connected = False self._closed = False # Close mean we are destroying the compute node @@ -214,6 +218,10 @@ class Compute: def host(self, host): self._host = host + @property + def console_host(self): + return self._console_host + @property def port(self): """ diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index 68356809..a1b109c0 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -568,7 +568,7 @@ class Node: "node_directory": self._node_directory, "name": self._name, "console": self._console, - "console_host": str(self._compute.host), + "console_host": str(self._compute.console_host), "console_type": self._console_type, "command_line": self._command_line, "properties": self._properties, diff --git a/gns3server/web/web_server.py b/gns3server/web/web_server.py index 9bddb5c6..57e57a5e 100644 --- a/gns3server/web/web_server.py +++ b/gns3server/web/web_server.py @@ -60,7 +60,6 @@ class WebServer: self._server = None self._app = None self._start_time = time.time() - self._port_manager = PortManager(host) self._running = False self._closing = False @@ -115,11 +114,11 @@ class WebServer: m = module.instance() yield from m.unload() - if self._port_manager.tcp_ports: - log.warning("TCP ports are still used {}".format(self._port_manager.tcp_ports)) + if PortManager.instance().tcp_ports: + log.warning("TCP ports are still used {}".format(PortManager.instance().tcp_ports)) - if self._port_manager.udp_ports: - log.warning("UDP ports are still used {}".format(self._port_manager.udp_ports)) + if PortManager.instance().udp_ports: + log.warning("UDP ports are still used {}".format(PortManager.instance().udp_ports)) for task in asyncio.Task.all_tasks(): task.cancel() @@ -292,13 +291,16 @@ class WebServer: "http://localhost:8080": aiohttp_cors.ResourceOptions(expose_headers="*", allow_headers="*"), "http://gns3.github.io": aiohttp_cors.ResourceOptions(expose_headers="*", allow_headers="*") }) + + PortManager.instance().console_host = self._host + for method, route, handler in Route.get_routes(): log.debug("Adding route: {} {}".format(method, route)) cors.add(self._app.router.add_route(method, route, handler)) for module in MODULES: log.debug("Loading module {}".format(module.__name__)) m = module.instance() - m.port_manager = self._port_manager + m.port_manager = PortManager.instance() log.info("Starting server on {}:{}".format(self._host, self._port)) self._handler = self._app.make_handler(handler=RequestHandler) diff --git a/tests/compute/test_port_manager.py b/tests/compute/test_port_manager.py index 6710a342..e3102d6f 100644 --- a/tests/compute/test_port_manager.py +++ b/tests/compute/test_port_manager.py @@ -119,3 +119,18 @@ def test_find_unused_port(): def test_find_unused_port_invalid_range(): with pytest.raises(aiohttp.web.HTTPConflict): p = PortManager().find_unused_port(10000, 1000) + + +def test_set_console_host(config): + """ + If allow remote connection we need to bind console host + to 0.0.0.0 + """ + p = PortManager() + config.set_section_config("Server", {"allow_remote_console": False}) + p.console_host = "10.42.1.42" + assert p.console_host == "10.42.1.42" + p = PortManager() + config.set_section_config("Server", {"allow_remote_console": True}) + p.console_host = "10.42.1.42" + assert p.console_host == "0.0.0.0" diff --git a/tests/conftest.py b/tests/conftest.py index 71da9b1d..3b810fc5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -145,8 +145,10 @@ def project(tmpdir): @pytest.fixture(scope="function") def port_manager(): """An instance of port manager""" - - return PortManager("127.0.0.1") + PortManager._instance = None + p = PortManager.instance() + p.console_host = "127.0.0.1" + return p @pytest.fixture(scope="function") @@ -198,7 +200,6 @@ def run_around_tests(monkeypatch, port_manager, controller, config): for module in MODULES: module._instance = None - port_manager._instance = port_manager os.makedirs(os.path.join(tmppath, 'projects')) config.set("Server", "projects_path", os.path.join(tmppath, 'projects')) config.set("Server", "symbols_path", os.path.join(tmppath, 'symbols')) diff --git a/tests/controller/test_node.py b/tests/controller/test_node.py index 89f117f9..7ec283de 100644 --- a/tests/controller/test_node.py +++ b/tests/controller/test_node.py @@ -92,7 +92,7 @@ def test_json(node, compute): "name": "demo", "console": node.console, "console_type": node.console_type, - "console_host": str(compute.host), + "console_host": str(compute.console_host), "command_line": None, "node_directory": None, "properties": node.properties,