Fixed Agent Role Implementation Errors / Bugs

This commit is contained in:
2025-12-01 02:54:46 -07:00
parent fe4511ecaf
commit 52e40c3753
4 changed files with 38 additions and 23 deletions

View File

@@ -29,7 +29,7 @@ from typing import Callable, Deque, Dict, Iterable, List, Optional, Tuple
from collections import deque from collections import deque
from threading import Thread from threading import Thread
from .ReverseTunnel.Powershell import PowershellChannelServer from .ReverseTunnelProtocols import PowershellChannelServer
try: # websockets is added to engine requirements try: # websockets is added to engine requirements
import websockets import websockets
@@ -1000,7 +1000,12 @@ class ReverseTunnelService:
if lease is None or (lease.domain or "").lower() != "ps": if lease is None or (lease.domain or "").lower() != "ps":
return None return None
bridge = self.ensure_bridge(lease) bridge = self.ensure_bridge(lease)
server = PowershellChannelServer(bridge=bridge, service=self) server = PowershellChannelServer(
bridge=bridge,
service=self,
frame_cls=TunnelFrame,
close_frame_fn=close_frame,
)
self._ps_servers[tunnel_id] = server self._ps_servers[tunnel_id] = server
return server return server

View File

@@ -1,2 +0,0 @@
"""Protocol-specific helpers for Reverse Tunnel (Engine side)."""

View File

@@ -5,24 +5,21 @@ import json
from collections import deque from collections import deque
from typing import Any, Deque, Dict, List, Optional from typing import Any, Deque, Dict, List, Optional
from ..ReverseTunnel import ( # Mirror framing constants to avoid circular imports.
CLOSE_AGENT_SHUTDOWN, MSG_CHANNEL_OPEN = 0x03
CLOSE_OK, MSG_CHANNEL_ACK = 0x04
CLOSE_PROTOCOL_ERROR, MSG_DATA = 0x05
MSG_CHANNEL_ACK, MSG_CONTROL = 0x09
MSG_CHANNEL_OPEN, MSG_CLOSE = 0x08
MSG_CLOSE, CLOSE_OK = 0
MSG_CONTROL, CLOSE_PROTOCOL_ERROR = 3
MSG_DATA, CLOSE_AGENT_SHUTDOWN = 6
TunnelFrame,
close_frame,
)
class PowershellChannelServer: class PowershellChannelServer:
"""Coordinate PowerShell channel frames over a TunnelBridge.""" """Coordinate PowerShell channel frames over a TunnelBridge."""
def __init__(self, bridge, service, *, channel_id: int = 1): def __init__(self, bridge, service, *, channel_id: int = 1, frame_cls=None, close_frame_fn=None):
self.bridge = bridge self.bridge = bridge
self.service = service self.service = service
self.channel_id = channel_id self.channel_id = channel_id
@@ -33,9 +30,11 @@ class PowershellChannelServer:
self._output: Deque[str] = deque() self._output: Deque[str] = deque()
self._close_reason: Optional[str] = None self._close_reason: Optional[str] = None
self._close_code: Optional[int] = None self._close_code: Optional[int] = None
self._frame_cls = frame_cls
self._close_frame_fn = close_frame_fn
# ------------------------------------------------------------------ Agent frame handling # ------------------------------------------------------------------ Agent frame handling
def handle_agent_frame(self, frame: TunnelFrame) -> None: def handle_agent_frame(self, frame) -> None:
if frame.channel_id != self.channel_id: if frame.channel_id != self.channel_id:
return return
if frame.msg_type == MSG_CHANNEL_ACK: if frame.msg_type == MSG_CHANNEL_ACK:
@@ -73,7 +72,7 @@ class PowershellChannelServer:
{"protocol": "ps", "metadata": {"cols": cols, "rows": rows}}, {"protocol": "ps", "metadata": {"cols": cols, "rows": rows}},
separators=(",", ":"), separators=(",", ":"),
).encode("utf-8") ).encode("utf-8")
frame = TunnelFrame(msg_type=MSG_CHANNEL_OPEN, channel_id=self.channel_id, payload=payload) frame = self._frame_cls(msg_type=MSG_CHANNEL_OPEN, channel_id=self.channel_id, payload=payload)
self.bridge.operator_to_agent(frame) self.bridge.operator_to_agent(frame)
self._open_sent = True self._open_sent = True
self.logger.info( self.logger.info(
@@ -88,21 +87,29 @@ class PowershellChannelServer:
if self._closed: if self._closed:
return return
payload = data.encode("utf-8", errors="replace") payload = data.encode("utf-8", errors="replace")
frame = TunnelFrame(msg_type=MSG_DATA, channel_id=self.channel_id, payload=payload) frame = self._frame_cls(msg_type=MSG_DATA, channel_id=self.channel_id, payload=payload)
self.bridge.operator_to_agent(frame) self.bridge.operator_to_agent(frame)
def send_resize(self, cols: int, rows: int) -> None: def send_resize(self, cols: int, rows: int) -> None:
if self._closed: if self._closed:
return return
payload = json.dumps({"cols": cols, "rows": rows}, separators=(",", ":")).encode("utf-8") payload = json.dumps({"cols": cols, "rows": rows}, separators=(",", ":")).encode("utf-8")
frame = TunnelFrame(msg_type=MSG_CONTROL, channel_id=self.channel_id, payload=payload) frame = self._frame_cls(msg_type=MSG_CONTROL, channel_id=self.channel_id, payload=payload)
self.bridge.operator_to_agent(frame) self.bridge.operator_to_agent(frame)
def close(self, code: int = CLOSE_AGENT_SHUTDOWN, reason: str = "operator_close") -> None: def close(self, code: int = CLOSE_AGENT_SHUTDOWN, reason: str = "operator_close") -> None:
if self._closed: if self._closed:
return return
self._closed = True self._closed = True
self.bridge.operator_to_agent(close_frame(self.channel_id, code, reason)) if callable(self._close_frame_fn):
frame = self._close_frame_fn(self.channel_id, code, reason)
else:
frame = self._frame_cls(
msg_type=MSG_CLOSE,
channel_id=self.channel_id,
payload=json.dumps({"code": code, "reason": reason}, separators=(",", ":")).encode("utf-8"),
)
self.bridge.operator_to_agent(frame)
# ------------------------------------------------------------------ Output polling # ------------------------------------------------------------------ Output polling
def drain_output(self) -> List[str]: def drain_output(self) -> List[str]:
@@ -127,4 +134,3 @@ class PowershellChannelServer:
"close_reason": self._close_reason, "close_reason": self._close_reason,
"close_code": self._close_code, "close_code": self._close_code,
} }

View File

@@ -0,0 +1,6 @@
"""Protocol-specific helpers for Reverse Tunnel (Engine side)."""
from .Powershell import PowershellChannelServer
__all__ = ["PowershellChannelServer"]