From acdc1e5ebbdbdfe84ba82b762dcbbaca6d482292 Mon Sep 17 00:00:00 2001 From: grossmj Date: Fri, 20 May 2016 20:19:28 -0600 Subject: [PATCH 1/9] Fixes check for NPF service and add check for NPCAP service on Windows. --- gns3server/utils/interfaces.py | 30 +++++++++++++++++------------- utils/vmnet.py | 3 ++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/gns3server/utils/interfaces.py b/gns3server/utils/interfaces.py index 1f53e2c0..bb12151d 100644 --- a/gns3server/utils/interfaces.py +++ b/gns3server/utils/interfaces.py @@ -138,6 +138,21 @@ def is_interface_up(interface): # TODO: Windows & OSX support return True +def _check_windows_service(service_name): + + import pywintypes + import win32service + import win32serviceutil + + try: + if win32serviceutil.QueryServiceStatus(service_name, None)[1] != win32service.SERVICE_RUNNING: + return False + except pywintypes.error as e: + if e.winerror == 1060: + return False + else: + raise aiohttp.web.HTTPInternalServerError(text="Could not check if the {} service is running: {}".format(service_name, e.strerror)) + return True def interfaces(): """ @@ -163,19 +178,8 @@ def interfaces(): "mac_address": mac_address}) else: try: - import pywintypes - import win32service - import win32serviceutil - - try: - if win32serviceutil.QueryServiceStatus("npf", None)[1] != win32service.SERVICE_RUNNING: - raise aiohttp.web.HTTPInternalServerError(text="The NPF service is not running") - except pywintypes.error as e: - if e[0] == 1060: - raise aiohttp.web.HTTPInternalServerError(text="The NPF service is not installed") - else: - raise aiohttp.web.HTTPInternalServerError(text="Could not check if the NPF service is running: {}".format(e[2])) - + if not _check_windows_service("npf") and not _check_windows_service("npcap"): + raise aiohttp.web.HTTPInternalServerError("The NPF or Npcap is not installed or running") results = get_windows_interfaces() except ImportError: message = "pywin32 module is not installed, please install it on the server to get the available interface names" diff --git a/utils/vmnet.py b/utils/vmnet.py index 1f437411..a9be3f1c 100644 --- a/utils/vmnet.py +++ b/utils/vmnet.py @@ -168,7 +168,8 @@ def vmnet_windows(args, vmnet_range_start, vmnet_range_end): os.system('"{}" -- add adapter vmnet{}'.format(vnetlib_path, vmnet_number)) os.system("net stop npf") os.system("net start npf") - + os.system("net stop npcap") + os.system("net start npcap") def vmnet_unix(args, vmnet_range_start, vmnet_range_end): """ From 67e346ba92e9206c6770b9d4a987cd02aa596859 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 21 May 2016 13:20:18 -0600 Subject: [PATCH 2/9] Fixed startup-config is lost if you change any IOS router settings. Fixes #1233. --- gns3server/modules/dynamips/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py index b4b38aba..e5df157a 100644 --- a/gns3server/modules/dynamips/__init__.py +++ b/gns3server/modules/dynamips/__init__.py @@ -603,8 +603,8 @@ class Dynamips(BaseManager): elif startup_config_content: startup_config_path = self._create_config(vm, default_startup_config_path, startup_config_content) yield from vm.set_configs(startup_config_path) - # An empty startup config crash dynamips - else: + elif os.path.isfile(default_startup_config_path) and os.path.getsize(default_startup_config_path) == 0: + # An empty startup-config may crash Dynamips startup_config_path = self._create_config(vm, default_startup_config_path, "!\n") yield from vm.set_configs(startup_config_path) From a2ebbaa322f4be4fdf068fb471ac0cc867adf6e9 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 21 May 2016 14:43:10 -0600 Subject: [PATCH 3/9] Force Npcap DLL to be used first for Dynamips and uBridge (instead of the one from Winpcap if installed). --- gns3server/modules/dynamips/hypervisor.py | 10 +++++++++- gns3server/ubridge/hypervisor.py | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/gns3server/modules/dynamips/hypervisor.py b/gns3server/modules/dynamips/hypervisor.py index 18c35352..a94e32df 100644 --- a/gns3server/modules/dynamips/hypervisor.py +++ b/gns3server/modules/dynamips/hypervisor.py @@ -19,6 +19,7 @@ Represents a Dynamips hypervisor and starts/stops the associated Dynamips process. """ +import sys import os import subprocess import asyncio @@ -117,6 +118,12 @@ class Hypervisor(DynamipsHypervisor): """ self._command = self._build_command() + env = os.environ.copy() + if sys.platform.startswith("win"): + # add the Npcap directory to $PATH to force Dynamips to use npcap DLL instead of Winpcap (if installed) + system_root = os.path.join(os.path.expandvars("%SystemRoot%"), "System32", "Npcap") + if os.path.isdir(system_root): + env["PATH"] = system_root + ';' + env["PATH"] try: log.info("Starting Dynamips: {}".format(self._command)) self._stdout_file = os.path.join(self.working_dir, "dynamips_i{}_stdout.txt".format(self._id)) @@ -125,7 +132,8 @@ class Hypervisor(DynamipsHypervisor): self._process = yield from asyncio.create_subprocess_exec(*self._command, stdout=fd, stderr=subprocess.STDOUT, - cwd=self._working_dir) + cwd=self._working_dir, + env=env) log.info("Dynamips process started PID={}".format(self._process.pid)) self._started = True except (OSError, subprocess.SubprocessError) as e: diff --git a/gns3server/ubridge/hypervisor.py b/gns3server/ubridge/hypervisor.py index 929d06f6..7c43e838 100644 --- a/gns3server/ubridge/hypervisor.py +++ b/gns3server/ubridge/hypervisor.py @@ -19,6 +19,7 @@ Represents a uBridge hypervisor and starts/stops the associated uBridge process. """ +import sys import os import subprocess import asyncio @@ -140,6 +141,12 @@ class Hypervisor(UBridgeHypervisor): """ yield from self._check_ubridge_version() + env = os.environ.copy() + if sys.platform.startswith("win"): + # add the Npcap directory to $PATH to force Dynamips to use npcap DLL instead of Winpcap (if installed) + system_root = os.path.join(os.path.expandvars("%SystemRoot%"), "System32", "Npcap") + if os.path.isdir(system_root): + env["PATH"] = system_root + ';' + env["PATH"] try: command = self._build_command() log.info("starting ubridge: {}".format(command)) @@ -149,7 +156,8 @@ class Hypervisor(UBridgeHypervisor): self._process = yield from asyncio.create_subprocess_exec(*command, stdout=fd, stderr=subprocess.STDOUT, - cwd=self._working_dir) + cwd=self._working_dir, + env=env) log.info("ubridge started PID={}".format(self._process.pid)) except (OSError, subprocess.SubprocessError) as e: From 3e89543ab98906c4068cddf1ba9e4da0ac266b41 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 21 May 2016 15:19:32 -0600 Subject: [PATCH 4/9] Fixes wrong exception in Docker VM implementation. --- gns3server/modules/docker/docker_vm.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gns3server/modules/docker/docker_vm.py b/gns3server/modules/docker/docker_vm.py index 71ee58aa..6cc689b4 100644 --- a/gns3server/modules/docker/docker_vm.py +++ b/gns3server/modules/docker/docker_vm.py @@ -27,7 +27,6 @@ import aiohttp import json import os -from ...ubridge.hypervisor import Hypervisor from .docker_error import * from ..base_vm import BaseVM from ..adapters.ethernet_adapter import EthernetAdapter @@ -765,7 +764,7 @@ class DockerVM(BaseVM): adapter = "bridge{}".format(adapter_number) if not self._ubridge_hypervisor or not self._ubridge_hypervisor.is_running(): - raise VMwareError("Cannot start the packet capture: uBridge is not running") + raise DockerError("Cannot start the packet capture: uBridge is not running") yield from self._ubridge_hypervisor.send('bridge start_capture {name} "{output_file}"'.format(name=adapter, output_file=output_file)) @asyncio.coroutine @@ -778,7 +777,7 @@ class DockerVM(BaseVM): adapter = "bridge{}".format(adapter_number) if not self._ubridge_hypervisor or not self._ubridge_hypervisor.is_running(): - raise VMwareError("Cannot stop the packet capture: uBridge is not running") + raise DockerError("Cannot stop the packet capture: uBridge is not running") yield from self._ubridge_hypervisor.send("bridge stop_capture {name}".format(name=adapter)) @asyncio.coroutine From cb6df28f598b00a51b00f0c9dd83ba5da0af17f1 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 21 May 2016 17:42:34 -0600 Subject: [PATCH 5/9] Fixes disabling the VPCS relay feature. Fixes #521. --- gns3server/modules/port_manager.py | 2 +- gns3server/modules/vpcs/vpcs_vm.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gns3server/modules/port_manager.py b/gns3server/modules/port_manager.py index f3846bd8..bcaa74af 100644 --- a/gns3server/modules/port_manager.py +++ b/gns3server/modules/port_manager.py @@ -106,7 +106,7 @@ class PortManager: return self._udp_host @udp_host.setter - def host(self, new_host): + def udp_host(self, new_host): self._udp_host = new_host diff --git a/gns3server/modules/vpcs/vpcs_vm.py b/gns3server/modules/vpcs/vpcs_vm.py index 054ed47e..16984918 100644 --- a/gns3server/modules/vpcs/vpcs_vm.py +++ b/gns3server/modules/vpcs/vpcs_vm.py @@ -419,8 +419,10 @@ class VPCSVM(BaseVM): command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset command.extend(["-i", "1"]) # option to start only one VPC instance command.extend(["-F"]) # option to avoid the daemonization of VPCS - if self._vpcs_version > parse_version("0.8"): - command.extend(["-R"]) # disable relay feature of VPCS (starting with VPCS 0.8) + if self._vpcs_version >= parse_version("0.8b"): + command.extend(["-R"]) # disable the relay feature of VPCS (starting with VPCS 0.8) + else: + log.warn("The VPCS relay feature could not be disabled because the VPCS version is below 0.8b") nio = self._ethernet_adapter.get_nio(0) if nio: From 1ae17b74dfbfa7f409d1387f9b280521a81e2b92 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 21 May 2016 18:58:28 -0600 Subject: [PATCH 6/9] Extract private-config only when necessary (content is different than the default). Fixes #520. --- gns3server/modules/dynamips/nodes/router.py | 5 +---- gns3server/modules/iou/iou_vm.py | 8 +++----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index f79f0b0b..b3196ac9 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -1521,7 +1521,6 @@ class Router(BaseVM): if startup_config_base64: if not self.startup_config: self._startup_config = os.path.join("configs", "i{}_startup-config.cfg".format(self._dynamips_id)) - try: config = base64.b64decode(startup_config_base64).decode("utf-8", errors="replace") config = "!\n" + config.replace("\r", "") @@ -1532,13 +1531,11 @@ class Router(BaseVM): except (binascii.Error, OSError) as e: raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e)) - if private_config_base64: + if private_config_base64 and base64.b64decode(private_config_base64) != b'\nkerberos password \nend\n': if not self.private_config: self._private_config = os.path.join("configs", "i{}_private-config.cfg".format(self._dynamips_id)) - try: config = base64.b64decode(private_config_base64).decode("utf-8", errors="replace") - config = "!\n" + config.replace("\r", "") config_path = os.path.join(module_workdir, self.private_config) with open(config_path, "wb") as f: log.info("saving private-config to {}".format(self.private_config)) diff --git a/gns3server/modules/iou/iou_vm.py b/gns3server/modules/iou/iou_vm.py index 303c078e..fb610ccf 100644 --- a/gns3server/modules/iou/iou_vm.py +++ b/gns3server/modules/iou/iou_vm.py @@ -108,7 +108,6 @@ class IOUVM(BaseVM): self.manager.port_manager.release_udp_port(nio.lport, self._project) yield from self.stop() - self.save_configs() @property def path(self): @@ -681,6 +680,7 @@ class IOUVM(BaseVM): self._iouyap_process = None self._started = False + self.save_configs() def _terminate_process_iouyap(self): """ @@ -1097,7 +1097,7 @@ class IOUVM(BaseVM): if private_config is None: private_config = '' - # We disallow erasing the startup config file + # We disallow erasing the private config file if len(private_config) == 0 and os.path.exists(private_config_path): return @@ -1204,18 +1204,16 @@ class IOUVM(BaseVM): config_path = os.path.join(self.working_dir, "startup-config.cfg") try: config = startup_config_content.decode("utf-8", errors="replace") - config = "!\n" + config.replace("\r", "") with open(config_path, "wb") as f: log.info("saving startup-config to {}".format(config_path)) f.write(config.encode("utf-8")) except (binascii.Error, OSError) as e: raise IOUError("Could not save the startup configuration {}: {}".format(config_path, e)) - if private_config_content: + if private_config_content and private_config_content != b'\nend\n': config_path = os.path.join(self.working_dir, "private-config.cfg") try: config = private_config_content.decode("utf-8", errors="replace") - config = "!\n" + config.replace("\r", "") with open(config_path, "wb") as f: log.info("saving private-config to {}".format(config_path)) f.write(config.encode("utf-8")) From 7bc0570735b214a671581beaf49c548efccf37ed Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 21 May 2016 19:13:36 -0600 Subject: [PATCH 7/9] Allow an IOS router to stop even the Dynamips hypervisor command fail to be sent. Ref #488. --- gns3server/modules/dynamips/nodes/router.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index b3196ac9..4af427ff 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -270,7 +270,10 @@ class Router(BaseVM): status = yield from self.get_status() if status != "inactive": - yield from self._hypervisor.send('vm stop "{name}"'.format(name=self._name)) + try: + yield from self._hypervisor.send('vm stop "{name}"'.format(name=self._name)) + except DynamipsError as e: + log.warn("Could not stop {}: {}".format(self._name, e)) self.status = "stopped" log.info('Router "{name}" [{id}] has been stopped'.format(name=self._name, id=self._id)) yield from self.save_configs() @@ -335,8 +338,8 @@ class Router(BaseVM): try: yield from self.stop() yield from self._hypervisor.send('vm delete "{}"'.format(self._name)) - except DynamipsError: - pass + except DynamipsError as e: + log.warn("Could not stop and delete {}: {}".format(self._name, e)) yield from self.hypervisor.stop() if self._auto_delete_disks: From 1ddb16eca0f95441fa4d4fac031dbe50c75cca39 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Mon, 23 May 2016 15:08:23 +0200 Subject: [PATCH 8/9] 1.5.0b1 --- CHANGELOG | 15 +++++++++++++++ gns3server/version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index aeadeea7..006554dc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,20 @@ # Change Log +## 1.5.0b1 23/05/2016 + +* Allow an IOS router to stop even the Dynamips hypervisor command fail to be sent. Ref #488. +* Extract private-config only when necessary (content is different than the default). Fixes #520. +* Fixes disabling the VPCS relay feature. Fixes #521. +* Fixes wrong exception in Docker VM implementation. +* Force Npcap DLL to be used first for Dynamips and uBridge (instead of the one from Winpcap if installed). +* Fixed startup-config is lost if you change any IOS router settings. Fixes #1233. +* Fixes check for NPF service and add check for NPCAP service on Windows. +* Fix ProcessLookupError X11VNC +* Force tag latest for docker image if no tag is specified +* Cleanup unbreakable space +* Do not raise error if vmrun.exe is named vmrun.EXE +* Load docker api only for Linux + ## 1.5.0a2 10/05/2016 * Fix distribution on PyPi diff --git a/gns3server/version.py b/gns3server/version.py index 21ff02ff..0fd1ec23 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,5 +23,5 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "1.5.0dev3" +__version__ = "1.5.0b1" __version_info__ = (1, 5, 0, -99) From cdd54b951a47c5f744a428852ea9061980664b67 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Mon, 23 May 2016 15:13:19 +0200 Subject: [PATCH 9/9] 1.5.0 dev 4 --- gns3server/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gns3server/version.py b/gns3server/version.py index 0fd1ec23..7bd35cd5 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,5 +23,5 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "1.5.0b1" +__version__ = "1.5.0dev4" __version_info__ = (1, 5, 0, -99)