From 22400124023cde5f83bd29d048a01700b4bfef2d Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 22 Apr 2026 14:13:19 +0800 Subject: [PATCH 1/5] Rename gns3-wireshark-setup to wireshark for simpler command Co-Authored-By: Claude Opus 4.6 --- docs/development-setup.md | 2 +- docs/features/web-wireshark-business-process.md | 6 +++--- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/development-setup.md b/docs/development-setup.md index b6ae3a42c..17de34965 100644 --- a/docs/development-setup.md +++ b/docs/development-setup.md @@ -103,7 +103,7 @@ source venv/bin/activate # For China mainland users, use mirror: # pip install -e . -i https://mirrors.aliyun.com/pypi/simple/ -pip install -e . && gns3-wireshark-setup +pip install -e . && wireshark pip install -e .[ai-copilot] pip install -e .[dev] ``` diff --git a/docs/features/web-wireshark-business-process.md b/docs/features/web-wireshark-business-process.md index 338eec3ee..bb1fbab19 100644 --- a/docs/features/web-wireshark-business-process.md +++ b/docs/features/web-wireshark-business-process.md @@ -27,10 +27,10 @@ Before using Web Wireshark, install the GNS3 server and set up the Docker image: ```bash # Development install -pip install -e . && gns3-wireshark-setup +pip install -e . && wireshark # Production install -pip install gns3-server && gns3-wireshark-setup +pip install gns3-server && wireshark ``` This command will: @@ -38,7 +38,7 @@ This command will: 2. Pull the `gns3/web-wireshark:latest` image from Docker Hub 3. If pull fails, build the image locally using the included Dockerfile -The `gns3-wireshark-setup` command shows the raw output from `docker pull` or `docker build`, allowing you to see the full progress. +The `wireshark` command shows the raw output from `docker pull` or `docker build`, allowing you to see the full progress. --- diff --git a/pyproject.toml b/pyproject.toml index 63a48aead..3135699d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ ai-copilot = {file = ['ai-requirements.txt']} gns3server = "gns3server.main:main" gns3vmnet = "gns3server.utils.vmnet:main" gns3server-uninstall-ai-copilot = "gns3server.utils.uninstall_ai_copilot:main" -gns3-wireshark-setup = "gns3server.agent.web_wireshark.setup_wireshark_image:main" +wireshark = "gns3server.agent.web_wireshark.setup_wireshark_image:main" [tool.setuptools] packages = ["gns3server"] From e304b1907627508d0c81d9716986fcc06e0b2384 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 22 Apr 2026 16:08:05 +0800 Subject: [PATCH 2/5] fix: lower Docker minimum API version to 1.40 for broader compatibility The minimum Docker API version was reduced from 1.44 to 1.40 to support older Docker installations that do not provide API version 1.44, ensuring the web Wireshark agent can connect to a wider range of Docker environments. --- gns3server/agent/web_wireshark/docker_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gns3server/agent/web_wireshark/docker_client.py b/gns3server/agent/web_wireshark/docker_client.py index c40f7c5fe..e350ae6d3 100644 --- a/gns3server/agent/web_wireshark/docker_client.py +++ b/gns3server/agent/web_wireshark/docker_client.py @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) # Docker API configuration DOCKER_SOCKET = "/var/run/docker.sock" -DOCKER_MINIMUM_API_VERSION = "1.44" +DOCKER_MINIMUM_API_VERSION = "1.40" DOCKER_PREFERRED_API_VERSION = "1.44" From 6c96e7493fc7f67e0c1dc242340343613508ddb8 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 22 Apr 2026 22:35:50 +0800 Subject: [PATCH 3/5] feat(web-wireshark): add method to retrieve container IP and refactor websocket endpoint - Add `get_container_ip` method to WebWiresharkManager for retrieving container IP addresses in wireshark network - Method uses Docker API as primary approach with container command execution as fallback - Refactor web_wireshark_websocket endpoint to use new method instead of direct Docker queries - Improve error handling and logging for container IP retrieval failures --- gns3server/agent/web_wireshark/manager.py | 44 +++++++++++++++++++++++ gns3server/api/routes/controller/links.py | 19 ++-------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/gns3server/agent/web_wireshark/manager.py b/gns3server/agent/web_wireshark/manager.py index 696226675..8fedb8f22 100644 --- a/gns3server/agent/web_wireshark/manager.py +++ b/gns3server/agent/web_wireshark/manager.py @@ -526,6 +526,50 @@ class WebWiresharkManager: return None + async def get_container_ip(self, container_name: str, container_id: str = None) -> Optional[str]: + """Get the container IP address in the wireshark network. + + Args: + container_name: Container name (e.g., "gns3-wireshark-project_id") + container_id: Container ID (optional, only used for fallback method) + + Returns: + Container IP address (e.g., 172.31.0.2) or None if not found + """ + # Method 1: Get from Docker Container API (fastest) + try: + container = await self.docker.get_container(container_name) + if container: + networks = container.get("NetworkSettings", {}).get("Networks", {}) + # Find gns3-wireshark network + for network_name, network_config in networks.items(): + if "wireshark" in network_name.lower(): + container_ip = network_config.get("IPAddress") + if container_ip: + logger.info(f"Got container IP from Docker API: {container_ip}") + return container_ip + except Exception as e: + logger.debug(f"Cannot get container IP from Docker API: {e}") + + # Fallback: Execute command inside container to get IP (slower) + if container_id: + try: + # Use 'hostname -I' to get all IP addresses and take the first one + # This works on most Linux systems and is more portable than 'ip' command + returncode, stdout, stderr = await self._exec_in_container( + container_id, + "hostname -I 2>/dev/null | awk '{print $1}'" + ) + if returncode == 0 and stdout.strip(): + container_ip = stdout.strip() + logger.info(f"Got container IP from container command: {container_ip}") + return container_ip + except Exception as e: + logger.debug(f"Cannot get container IP from container command: {e}") + + logger.warning(f"Failed to get container IP for {container_name}") + return None + async def _fix_localhost_url(self, url: str, container_id: str) -> str: """Fix URL with localhost/127.0.0.1 for container access. diff --git a/gns3server/api/routes/controller/links.py b/gns3server/api/routes/controller/links.py index 5f812fa00..2a6eec200 100644 --- a/gns3server/api/routes/controller/links.py +++ b/gns3server/api/routes/controller/links.py @@ -37,6 +37,7 @@ from gns3server.utils.http_client import HTTPClient from gns3server.utils.port_allocator import link_id_to_port from gns3server.utils.websocket_to_websocket import websocket_proxy from gns3server import schemas +from gns3server.agent.web_wireshark.manager import WebWiresharkManager from .dependencies.database import get_repository from .dependencies.rbac import has_privilege, has_privilege_on_websocket @@ -385,22 +386,8 @@ async def web_wireshark_websocket( xpra_port = link_id_to_port(link_id) # Get container IP - from gns3server.compute.docker import Docker - - docker_manager = Docker.instance() - container_info = await docker_manager.query( - "GET", - f"containers/{container_name}/json" - ) - - networks = container_info["NetworkSettings"]["Networks"] - container_ip = None - - # Find gns3-wireshark network - for network_name, network_config in networks.items(): - if "wireshark" in network_name.lower(): - container_ip = network_config["IPAddress"] - break + manager = WebWiresharkManager() + container_ip = await manager.get_container_ip(container_name) if not container_ip: log.error(f"Container {container_name} not found in wireshark network") From 117025a8a235c85d2bbcf4bb294bb911f807578b Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 22 Apr 2026 23:12:56 +0800 Subject: [PATCH 4/5] fix(web-wireshark): improve Docker API version compatibility with fallback mechanism - Change initial API version from 1.40 to 1.44 to support Docker 29.3+ (API 1.54) - Add automatic fallback to API 1.40 for older Docker versions (20.10, API 1.41) - Fixes "client version 1.40 is too old. Minimum supported API version is 1.44" error - Ensures compatibility across Docker versions 20.10 (API 1.41) to 29.3+ (API 1.54+) Co-Authored-By: Claude Sonnet 4.6 --- gns3server/agent/web_wireshark/docker_client.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gns3server/agent/web_wireshark/docker_client.py b/gns3server/agent/web_wireshark/docker_client.py index e350ae6d3..ca9e86360 100644 --- a/gns3server/agent/web_wireshark/docker_client.py +++ b/gns3server/agent/web_wireshark/docker_client.py @@ -46,7 +46,9 @@ class DockerHTTPClient: self._connector = None self._session = None self._connected = False - self._api_version = DOCKER_MINIMUM_API_VERSION + # Start with preferred API version (1.44) to support newer Docker + # Will fallback to minimum version (1.40) if server doesn't support it + self._api_version = DOCKER_PREFERRED_API_VERSION async def _get_connector(self): """Get or create Unix socket connector.""" @@ -142,6 +144,14 @@ class DockerHTTPClient: raise RuntimeError(f"Docker API timeout after {self.REQUEST_TIMEOUT}s for {endpoint}") except aiohttp.ClientError as e: raise RuntimeError(f"Docker connection error: {e}") from e + except RuntimeError as e: + # Retry with lower API version if Docker daemon doesn't support current version + error_msg = str(e) + if ("400" in error_msg or "not found" in error_msg.lower()) and self._api_version == DOCKER_PREFERRED_API_VERSION: + logger.warning(f"Docker daemon doesn't support API version {self._api_version}, falling back to {DOCKER_MINIMUM_API_VERSION}") + self._api_version = DOCKER_MINIMUM_API_VERSION + return await self._request(method, endpoint, check_connection=False, **kwargs) + raise async def create_network(self, name: str, driver: str = "bridge", subnet: str = None): """Create Docker network.""" From a189a98723293d038bcef36b4c41b807bcb8128f Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Wed, 22 Apr 2026 23:30:33 +0800 Subject: [PATCH 5/5] docs(web-wireshark): add Docker API compatibility documentation - Document API version negotiation mechanism (1.44 with fallback to 1.40) - Add tested configurations table for Docker 20.10 and 29.3+ - Document container IP retrieval dual-strategy approach - Explain KeyError bug fix for missing NetworkSettings.Networks field Co-Authored-By: Claude Sonnet 4.6 --- .../web-wireshark-business-process.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/features/web-wireshark-business-process.md b/docs/features/web-wireshark-business-process.md index bb1fbab19..6ef611345 100644 --- a/docs/features/web-wireshark-business-process.md +++ b/docs/features/web-wireshark-business-process.md @@ -552,6 +552,43 @@ Configured via `WebWiresharkSettings` in `gns3server/schemas/config.py`: --- +## Docker API Compatibility + +### Version Negotiation Mechanism + +The Web Wireshark feature implements automatic Docker API version negotiation to ensure compatibility across different Docker versions: + +1. **Primary**: Try API version 1.44 first + - Supports Docker 29.3+ (API 1.54+), which requires minimum API 1.44 + +2. **Fallback**: If server rejects 1.44 with 400 error, downgrade to API 1.40 + - Supports Docker 20.10 (API 1.41) + +### Tested Configurations + +| Docker Version | API Version | API 1.40 | API 1.44 | Solution | +|----------------|-------------|----------|----------|----------| +| 20.10 | 1.41 | ✓ | ✗ | Fallback to 1.40 | +| 29.3+ | 1.54+ | ✗ | ✓ | Use 1.44 | + +### Container IP Retrieval + +The `get_container_ip()` method implements a dual-strategy approach for retrieving container IP addresses: + +1. **Primary Method**: Query Docker Container API + - Uses `docker inspect` via HTTP API + - Safe access to `NetworkSettings.Networks` field using `.get()` + - Handles missing fields gracefully (fixes KeyError bug) + +2. **Fallback Method**: Execute `hostname -I` command inside container + - Works when Docker API response lacks network information + - Compatible with containers without `ip` command + - Returns first IP address from `hostname -I` output + +This dual approach ensures compatibility across different Docker API versions that may have varying response formats. + +--- + ## Known Limitations 1. **JWT Token Visibility**: Token passed via command-line arguments (visible in `/proc//cmdline`)