From c4327ec74c63e2085324b5da9b88744eb31c5e35 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 9 Dec 2016 16:41:15 +0100 Subject: [PATCH] Improve docker HTTP console Fix #816 --- gns3server/compute/docker/docker_vm.py | 13 +++++++++---- gns3server/utils/asyncio/raw_command_server.py | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/gns3server/compute/docker/docker_vm.py b/gns3server/compute/docker/docker_vm.py index ed4df187..063c9589 100644 --- a/gns3server/compute/docker/docker_vm.py +++ b/gns3server/compute/docker/docker_vm.py @@ -434,15 +434,20 @@ class DockerVM(BaseNode): @asyncio.coroutine def _start_http(self): """ - Start an HTTP tunnel to container localhost + Start an HTTP tunnel to container localhost. It's not perfect + but the only way we have to inject network packet is using nc. """ log.debug("Forward HTTP for %s to %d", self.name, self._console_http_port) command = ["docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "nc", "127.0.0.1", str(self._console_http_port)] - # We replace the port in the server answer otherwise some link could be broken + # We replace host and port in the server answer otherwise some link could be broken server = AsyncioRawCommandServer(command, replaces=[ ( - '{}'.format(self._console_http_port).encode(), - '{}'.format(self.console).encode(), + '://127.0.0.1'.encode(), # {{HOST}} mean client host + '://{{HOST}}'.encode(), + ), + ( + ':{}'.format(self._console_http_port).encode(), + ':{}'.format(self.console).encode(), ) ]) self._telnet_servers.append((yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console))) diff --git a/gns3server/utils/asyncio/raw_command_server.py b/gns3server/utils/asyncio/raw_command_server.py index bf8db42e..da6e82c1 100644 --- a/gns3server/utils/asyncio/raw_command_server.py +++ b/gns3server/utils/asyncio/raw_command_server.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import re +import copy import asyncio import asyncio.subprocess @@ -59,6 +60,15 @@ class AsyncioRawCommandServer: @asyncio.coroutine def _process(self, network_reader, network_writer, process_reader, process_writer): + replaces = [] + # Server host from the client point of view + host = network_writer.transport.get_extra_info("sockname")[0] + for replace in self._replaces: + if b'{{HOST}}' in replace[1]: + replaces.append((replace[0], replace[1].replace(b'{{HOST}}', host.encode()), )) + else: + replaces.append((replace[0], replace[1], )) + network_read = asyncio.async(network_reader.read(READ_SIZE)) reader_read = asyncio.async(process_reader.read(READ_SIZE)) timeout = 30 @@ -89,7 +99,7 @@ class AsyncioRawCommandServer: reader_read = asyncio.async(process_reader.read(READ_SIZE)) - for replace in self._replaces: + for replace in replaces: data = data.replace(replace[0], replace[1]) timeout = 2 # We reduce the timeout when the process start to return stuff to avoid problem with server not closing the connection @@ -102,8 +112,8 @@ if __name__ == '__main__': loop = asyncio.get_event_loop() command = ["nc", "localhost", "80"] - server = AsyncioRawCommandServer(command) - coro = asyncio.start_server(server.run, '127.0.0.1', 4444, loop=loop) + server = AsyncioRawCommandServer(command, replaces=[(b"work", b"{{HOST}}", )]) + coro = asyncio.start_server(server.run, '0.0.0.0', 4444, loop=loop) s = loop.run_until_complete(coro) try: