feat: enable container access to host localhost services

Rewrite localhost/127.x.x.x/0.0.0.0 target URLs to use host.docker.internal,
allowing the container to reach services running on the host machine.

- Add extra_hosts mapping for host.docker.internal on Linux
- Add HOST_GATEWAY env var to container
- Add rewrite_localhost_targets() to transform localhost URLs
- Support full 127.0.0.0/8 loopback range and IPv6 ::1
This commit is contained in:
0xallam
2026-01-07 11:45:07 -08:00
committed by Ahmed Allam
parent 7af1180a30
commit 06659d98ba
3 changed files with 50 additions and 1 deletions

View File

@@ -30,9 +30,10 @@ from strix.interface.utils import (
image_exists,
infer_target_type,
process_pull_line,
rewrite_localhost_targets,
validate_llm_response,
)
from strix.runtime.docker_runtime import STRIX_IMAGE
from strix.runtime.docker_runtime import HOST_GATEWAY_HOSTNAME, STRIX_IMAGE
from strix.telemetry.tracer import get_global_tracer
@@ -377,6 +378,7 @@ Examples:
parser.error(f"Invalid target '{target}'")
assign_workspace_subdirs(args.targets_info)
rewrite_localhost_targets(args.targets_info, HOST_GATEWAY_HOSTNAME)
return args

View File

@@ -404,6 +404,47 @@ def collect_local_sources(targets_info: list[dict[str, Any]]) -> list[dict[str,
return local_sources
def _is_localhost_host(host: str) -> bool:
host_lower = host.lower().strip("[]")
if host_lower in ("localhost", "0.0.0.0", "::1"): # nosec B104
return True
try:
ip = ipaddress.ip_address(host_lower)
if isinstance(ip, ipaddress.IPv4Address):
return ip.is_loopback # 127.0.0.0/8
if isinstance(ip, ipaddress.IPv6Address):
return ip.is_loopback # ::1
except ValueError:
pass
return False
def rewrite_localhost_targets(targets_info: list[dict[str, Any]], host_gateway: str) -> None:
from yarl import URL # type: ignore[import-not-found]
for target_info in targets_info:
target_type = target_info.get("type")
details = target_info.get("details", {})
if target_type == "web_application":
target_url = details.get("target_url", "")
try:
url = URL(target_url)
except (ValueError, TypeError):
continue
if url.host and _is_localhost_host(url.host):
details["target_url"] = str(url.with_host(host_gateway))
elif target_type == "ip_address":
target_ip = details.get("target_ip", "")
if target_ip and _is_localhost_host(target_ip):
details["target_ip"] = host_gateway
# Repository utilities
def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None) -> str:
console = Console()

View File

@@ -15,6 +15,7 @@ from .runtime import AbstractRuntime, SandboxInfo
STRIX_IMAGE = os.getenv("STRIX_IMAGE", "ghcr.io/usestrix/strix-sandbox:0.1.10")
HOST_GATEWAY_HOSTNAME = "host.docker.internal"
logger = logging.getLogger(__name__)
@@ -121,7 +122,9 @@ class DockerRuntime(AbstractRuntime):
"CAIDO_PORT": str(caido_port),
"TOOL_SERVER_PORT": str(tool_server_port),
"TOOL_SERVER_TOKEN": tool_server_token,
"HOST_GATEWAY": HOST_GATEWAY_HOSTNAME,
},
extra_hosts=self._get_extra_hosts(),
tty=True,
)
@@ -381,6 +384,9 @@ class DockerRuntime(AbstractRuntime):
return "127.0.0.1"
def _get_extra_hosts(self) -> dict[str, str]:
return {HOST_GATEWAY_HOSTNAME: "host-gateway"}
async def destroy_sandbox(self, container_id: str) -> None:
logger.info("Destroying scan container %s", container_id)
try: