diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py index 24f1d8a8..f528d0d8 100644 --- a/gns3server/compute/qemu/qemu_vm.py +++ b/gns3server/compute/qemu/qemu_vm.py @@ -45,7 +45,7 @@ from ..nios.nio_tap import NIOTAP from ..base_node import BaseNode from ...utils.asyncio import monitor_process from ...utils.images import md5sum -from ...utils import macaddress_to_int, int_to_macaddress +from ...utils import macaddress_to_int, int_to_macaddress, is_ipv6_enabled from ...utils.hostname import is_rfc1123_hostname_valid from gns3server.schemas.compute.qemu_nodes import Qemu, QemuPlatform @@ -1855,14 +1855,17 @@ class QemuVM(BaseNode): if port: console_host = self._manager.port_manager.console_host if console_host == "0.0.0.0": - if socket.has_ipv6: - # to fix an issue with Qemu when IPv4 is not enabled - # see https://github.com/GNS3/gns3-gui/issues/2352 - # FIXME: consider making this more global (not just for Qemu + SPICE) - console_host = "::" - else: - raise QemuError("IPv6 must be enabled in order to use the SPICE console") - return ["-spice", f"addr={console_host},port={port},disable-ticketing", "-vga", "qxl"] + try: + if is_ipv6_enabled(): + # to fix an issue with Qemu when IPv4 is not enabled + # see https://github.com/GNS3/gns3-gui/issues/2352 + # FIXME: consider making this more global (not just for Qemu + SPICE) + console_host = "::" + except OSError as e: + raise QemuError("Could not check if IPv6 is enabled: {}".format(e)) + return ["-spice", + f"addr={console_host},port={port},disable-ticketing", + "-vga", "qxl"] else: return [] diff --git a/gns3server/utils/__init__.py b/gns3server/utils/__init__.py index 3d7dd67f..faae1210 100644 --- a/gns3server/utils/__init__.py +++ b/gns3server/utils/__init__.py @@ -21,6 +21,8 @@ import re import shlex import textwrap import posixpath +import socket +import errno def force_unix_path(path): @@ -89,3 +91,21 @@ def parse_version(version): version.append("000000") version.append("final") return tuple(version) + + +def is_ipv6_enabled() -> bool: + + if not socket.has_ipv6: + return False # the socket library has no support for IPv6 + try: + with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock: + sock.bind(("::1", 0)) + return True + except OSError as e: + if e.errno in (errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT): + # EADDRNOTAVAIL is the errno if IPv6 modules/drivers are loaded but disabled. + # EAFNOSUPPORT is the errno if IPv6 modules/drivers are not loaded at all. + return False + if e.errno == errno.EADDRINUSE: + return True + raise diff --git a/requirements.txt b/requirements.txt index b5dd7267..156f77d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,12 +2,12 @@ uvicorn==0.29.0 fastapi==0.111.0 python-multipart==0.0.9 websockets==12.0 -aiohttp==3.9.3 +aiohttp>=3.9.5,<3.10 async-timeout==4.0.3 -aiofiles==23.2.1 +aiofiles>=24.1.0,<25.0 Jinja2>=3.1.4,<3.2 -sentry-sdk==2.1.1,<2.2 -psutil==5.9.8 +sentry-sdk==2.7.1,<2.8 +psutil==6.0.0 distro>=1.9.0 py-cpuinfo==9.0.0 sqlalchemy==2.0.29