Fix port allocation to skip ports used by external Docker containers
Some checks failed
Build Ghidra Plugin / build (push) Has been cancelled
Some checks failed
Build Ghidra Plugin / build (push) Has been cancelled
When port 8192 was already in use by a non-MCGhidra container (e.g., LTspice), docker_start would fail instead of trying the next port. Now loops through the pool, checking each candidate against Docker's published ports before using it. Also includes Docker build retry improvements from earlier session.
This commit is contained in:
parent
57f042a802
commit
112c1969c8
@ -25,8 +25,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
||||
# Download and extract Ghidra
|
||||
WORKDIR /opt
|
||||
RUN curl -fsSL "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
|
||||
-o ghidra.zip \
|
||||
# Download with retries and resume support for unreliable connections
|
||||
RUN for i in 1 2 3 4 5; do \
|
||||
curl -fSL --http1.1 -C - \
|
||||
"https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
|
||||
-o ghidra.zip && break || sleep 30; \
|
||||
done \
|
||||
&& unzip -q ghidra.zip \
|
||||
&& rm ghidra.zip \
|
||||
&& mv ghidra_${GHIDRA_VERSION}_PUBLIC ghidra
|
||||
@ -89,8 +93,12 @@ RUN groupadd -g 1001 ghidra && useradd -u 1001 -g ghidra -m -s /bin/bash ghidra
|
||||
|
||||
# Download and extract Ghidra (in runtime stage for cleaner image)
|
||||
WORKDIR /opt
|
||||
RUN curl -fsSL "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
|
||||
-o ghidra.zip \
|
||||
# Download with retries and resume support for unreliable connections
|
||||
RUN for i in 1 2 3 4 5; do \
|
||||
curl -fSL --http1.1 -C - \
|
||||
"https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
|
||||
-o ghidra.zip && break || sleep 30; \
|
||||
done \
|
||||
&& unzip -q ghidra.zip \
|
||||
&& rm ghidra.zip \
|
||||
&& mv ghidra_${GHIDRA_VERSION}_PUBLIC ghidra \
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "mcghidra"
|
||||
version = "2025.12.3"
|
||||
version = "2026.2.11"
|
||||
description = "AI-assisted reverse engineering bridge: a multi-instance Ghidra plugin exposed via a HATEOAS REST API plus an MCP Python bridge for decompilation, analysis & binary manipulation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
@ -22,7 +22,7 @@ requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/mcghidra"]
|
||||
packages = ["mcghidra"]
|
||||
|
||||
[tool.hatch.build]
|
||||
sources = ["src"]
|
||||
|
||||
@ -581,14 +581,6 @@ class DockerMixin(MCGhidraMixinBase):
|
||||
if not binary_file.exists():
|
||||
return {"error": f"Binary not found: {binary_path}"}
|
||||
|
||||
# Always allocate from pool to prevent conflicts between sessions
|
||||
port = self.port_pool.allocate(self.session_id)
|
||||
if port is None:
|
||||
return {
|
||||
"error": "Port pool exhausted (8192-8223). Stop some containers first.",
|
||||
"allocated_ports": self.port_pool.get_allocated_ports(),
|
||||
}
|
||||
|
||||
# Generate container name if not specified
|
||||
if name is None:
|
||||
name = self._generate_container_name(binary_file.name)
|
||||
@ -602,19 +594,38 @@ class DockerMixin(MCGhidraMixinBase):
|
||||
["ps", "-a", "-q", "-f", f"name=^{name}$"], check=False
|
||||
)
|
||||
if check_result.stdout.strip():
|
||||
self.port_pool.release(port)
|
||||
return {
|
||||
"error": f"Container '{name}' already exists. Stop it first with docker_stop."
|
||||
}
|
||||
|
||||
# Check if port is already in use by a non-pool container
|
||||
# Allocate a port that's both lockable AND not in use by Docker
|
||||
# This handles external containers (not managed by MCGhidra) using ports in our range
|
||||
port = None
|
||||
ports_tried = []
|
||||
for _ in range(PORT_POOL_END - PORT_POOL_START + 1):
|
||||
candidate_port = self.port_pool.allocate(self.session_id)
|
||||
if candidate_port is None:
|
||||
break # Pool exhausted
|
||||
|
||||
# Check if this port is already in use by a Docker container
|
||||
port_check = await self._run_docker_cmd(
|
||||
["ps", "-q", "-f", f"publish={port}"], check=False
|
||||
["ps", "-q", "-f", f"publish={candidate_port}"], check=False
|
||||
)
|
||||
if port_check.stdout.strip():
|
||||
self.port_pool.release(port)
|
||||
# Port is in use by Docker - release and try next
|
||||
ports_tried.append(candidate_port)
|
||||
self.port_pool.release(candidate_port)
|
||||
continue
|
||||
|
||||
# Found a usable port!
|
||||
port = candidate_port
|
||||
break
|
||||
|
||||
if port is None:
|
||||
return {
|
||||
"error": f"Port {port} is already in use by another container"
|
||||
"error": "Port pool exhausted (8192-8223). All ports are in use by Docker containers.",
|
||||
"ports_checked": ports_tried if ports_tried else "all ports locked by other MCGhidra sessions",
|
||||
"allocated_ports": self.port_pool.get_allocated_ports(),
|
||||
}
|
||||
|
||||
# Build label arguments
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user