mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2026-02-04 08:20:31 -07:00
Additional Changes to VPN Tunneling
This commit is contained in:
@@ -47,11 +47,11 @@ def _b64decode(value: str) -> bytes:
|
||||
def _resolve_shell_port() -> int:
|
||||
raw = os.environ.get("BOREALIS_WIREGUARD_SHELL_PORT")
|
||||
try:
|
||||
value = int(raw) if raw is not None else 47001
|
||||
value = int(raw) if raw is not None else 47002
|
||||
except Exception:
|
||||
value = 47001
|
||||
value = 47002
|
||||
if value < 1 or value > 65535:
|
||||
return 47001
|
||||
return 47002
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -22,13 +22,22 @@ import os
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import x25519
|
||||
from signature_utils import verify_and_store_script_signature
|
||||
|
||||
try:
|
||||
from signature_utils import verify_and_store_script_signature
|
||||
except Exception: # pragma: no cover - fallback for runtime path issues
|
||||
import sys
|
||||
from pathlib import Path as _Path
|
||||
|
||||
base_dir = _Path(__file__).resolve().parents[1]
|
||||
if str(base_dir) not in sys.path:
|
||||
sys.path.insert(0, str(base_dir))
|
||||
from signature_utils import verify_and_store_script_signature
|
||||
|
||||
ROLE_NAME = "WireGuardTunnel"
|
||||
ROLE_CONTEXTS = ["system"]
|
||||
@@ -88,18 +97,31 @@ def _generate_client_keys(root: Path) -> Dict[str, str]:
|
||||
return {"private": priv, "public": pub}
|
||||
|
||||
|
||||
@dataclass
|
||||
class SessionConfig:
|
||||
token: Dict[str, Any]
|
||||
virtual_ip: str
|
||||
allowed_ips: str
|
||||
endpoint: str
|
||||
server_public_key: str
|
||||
allowed_ports: str
|
||||
idle_seconds: int = 900
|
||||
preshared_key: Optional[str] = None
|
||||
client_private_key: Optional[str] = None
|
||||
client_public_key: Optional[str] = None
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
token: Dict[str, Any],
|
||||
virtual_ip: str,
|
||||
allowed_ips: str,
|
||||
endpoint: str,
|
||||
server_public_key: str,
|
||||
allowed_ports: str,
|
||||
idle_seconds: int = 900,
|
||||
preshared_key: Optional[str] = None,
|
||||
client_private_key: Optional[str] = None,
|
||||
client_public_key: Optional[str] = None,
|
||||
) -> None:
|
||||
self.token = token
|
||||
self.virtual_ip = virtual_ip
|
||||
self.allowed_ips = allowed_ips
|
||||
self.endpoint = endpoint
|
||||
self.server_public_key = server_public_key
|
||||
self.allowed_ports = allowed_ports
|
||||
self.idle_seconds = idle_seconds
|
||||
self.preshared_key = preshared_key
|
||||
self.client_private_key = client_private_key
|
||||
self.client_public_key = client_public_key
|
||||
|
||||
|
||||
class WireGuardClient:
|
||||
@@ -150,6 +172,19 @@ class WireGuardClient:
|
||||
if port < 1 or port > 65535:
|
||||
raise ValueError("Invalid token port")
|
||||
|
||||
if not signature:
|
||||
if sig_alg or signing_key:
|
||||
raise ValueError("Token signature missing")
|
||||
stored_key = None
|
||||
if signing_client is not None and hasattr(signing_client, "load_server_signing_key"):
|
||||
try:
|
||||
stored_key = signing_client.load_server_signing_key()
|
||||
except Exception:
|
||||
stored_key = None
|
||||
if isinstance(stored_key, str) and stored_key.strip():
|
||||
raise ValueError("Token signature missing")
|
||||
return
|
||||
|
||||
if signature:
|
||||
if sig_alg and str(sig_alg).lower() not in ("ed25519", "eddsa"):
|
||||
raise ValueError("Unsupported token signature algorithm")
|
||||
@@ -292,6 +327,11 @@ class Role:
|
||||
self._log("WireGuard start payload missing/invalid.", error=True)
|
||||
return None
|
||||
|
||||
payload_agent_id = payload.get("agent_id") or payload.get("agent_guid")
|
||||
if payload_agent_id:
|
||||
if str(payload_agent_id).strip() != str(self.ctx.agent_id).strip():
|
||||
return None
|
||||
|
||||
token = payload.get("token") or payload.get("orchestration_token")
|
||||
if not isinstance(token, dict):
|
||||
self._log("WireGuard start missing token payload.", error=True)
|
||||
@@ -351,6 +391,9 @@ class Role:
|
||||
async def _vpn_tunnel_stop(payload):
|
||||
reason = "server_stop"
|
||||
if isinstance(payload, dict):
|
||||
target_agent = payload.get("agent_id")
|
||||
if target_agent and str(target_agent).strip() != str(self.ctx.agent_id).strip():
|
||||
return
|
||||
reason = payload.get("reason") or reason
|
||||
self._log(f"WireGuard stop requested (reason={reason}).")
|
||||
self.client.stop_session(reason=str(reason))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import os
|
||||
import importlib.util
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
@@ -37,8 +39,27 @@ class RoleManager:
|
||||
self.config = config
|
||||
self.loop = loop
|
||||
self.hooks = hooks or {}
|
||||
self._log_hook = self.hooks.get('log_agent')
|
||||
self.roles: Dict[str, object] = {}
|
||||
|
||||
# Ensure role helpers alongside Roles/ are importable (e.g., signature_utils.py).
|
||||
try:
|
||||
base_path = Path(self.base_dir).resolve()
|
||||
parent_path = base_path.parent
|
||||
for candidate in (base_path, parent_path):
|
||||
if candidate and str(candidate) not in sys.path:
|
||||
sys.path.insert(0, str(candidate))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _log(self, message: str, *, error: bool = False) -> None:
|
||||
if callable(self._log_hook):
|
||||
try:
|
||||
target = "agent.error.log" if error else "agent.log"
|
||||
self._log_hook(message, fname=target)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _iter_role_files(self) -> List[str]:
|
||||
roles_dir = os.path.join(self.base_dir, 'Roles')
|
||||
if not os.path.isdir(roles_dir):
|
||||
@@ -56,7 +77,8 @@ class RoleManager:
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(mod)
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
self._log(f"Role load failed during import path={path} error={exc}", error=True)
|
||||
continue
|
||||
|
||||
role_name = getattr(mod, 'ROLE_NAME', None)
|
||||
@@ -75,10 +97,12 @@ class RoleManager:
|
||||
if hasattr(role_obj, 'register_events'):
|
||||
try:
|
||||
role_obj.register_events()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc:
|
||||
self._log(f"Role register_events failed name={role_name} error={exc}", error=True)
|
||||
self.roles[role_name] = role_obj
|
||||
except Exception:
|
||||
self._log(f"Role loaded name={role_name} context={self.context}")
|
||||
except Exception as exc:
|
||||
self._log(f"Role init failed name={role_name} path={path} error={exc}", error=True)
|
||||
continue
|
||||
|
||||
def on_config(self, roles_cfg: List[dict]):
|
||||
@@ -96,4 +120,3 @@ class RoleManager:
|
||||
role.stop_all()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user