Tunneling

Goauld agent tunneling

This page covers the transports used to carry the agent’s outbound SSH data connection. That connection carries shells, file transfers, proxies, forwards, and other operator data. If an SSH transport fails, the agent automatically falls back to the next configured method.

The agent also maintains a separate Socket.IO control connection for registration, heartbeats, metadata, and control instructions. Socket.IO uses HTTP long polling, WebSocket over HTTP(S), or WebSocket encapsulated over DNS; it is not carried directly by the SSH, TLS, or QUIC data transports. See Connection flow for the complete two-path model.

Choose a transport

Use the simplest transport that the target network permits:

Network conditionRecommended configuration
Direct outbound TCPDirect SSH
TLS allowed, SSH blockedSSH over TLS
HTTP(S) egress onlySSH over WebSocket or HTTP
DNS is the only permitted egressSSH over DNS
QUIC is available and desiredSSH over QUIC

Set the SSH data transport order with --rssh-order. The agent tries each configured transport in order and continues with the next one after a failure. The agent also derives compatible Socket.IO connection attempts from this order, but the control connection remains a separate protocol and connection.

Supported transports

The agent can connect using these transports (in default order):

  1. Direct SSH connection
  2. SSH over TLS
  3. SSH over WebSocket
  4. SSH over HTTP
  5. SSH over DNS
  6. SSH over QUIC (optional, requires --rssh-order configuration)

Default behavior

For each SSH data transport and compatible Socket.IO control strategy, the agent attempts connection with a 60-second timeout (configurable with --timeout). After exhausting the configured order, the agent retries indefinitely by default during the kill-switch duration (7 days by default), after which the agent kills itself. Each retry cycle starts from the beginning.

Connection timeouts

--timeout (default: 60 seconds) is the single timeout governing every connection the agent makes to the server. It bounds:

  • each SSH tunnel attempt, per data transport;
  • each Socket.IO control connection strategy attempted;
  • the configuration exchange that follows registration;
  • the keepalive liveness check: if the server does not answer a keepalive ping within this period, the control connection is considered dead and the agent restarts (see Connection flow).

Without these bounds the agent could stay blocked indefinitely against a server that accepts a connection but never replies. Reaching any of them makes the agent give up and restart, so it retries from the beginning of the transport order rather than hanging.

Configure transport selection

SSH data transport order and retry behavior can be customized:

  • --rssh-order (short -O): Customize the order in which the agent tries SSH data transports. The agent attempts each transport sequentially until one succeeds. Example: --rssh-order=ssh,tls,ws,http,dns tries SSH first, then TLS, then WebSocket, and so on. For an HTTP(S)-only deployment, use -O WS or --rssh-order WS; add DNS as a fallback when DNS egress is also available. The agent maps these choices to compatible Socket.IO control strategies: HTTP polling, WebSocket over HTTP(S), or WebSocket over DNS.
  • --max-retries: Limit retry attempts (example: --max-retries 5 stops after 5 failed cycles; default is unlimited). Independently of this flag, the retry loop is also bounded by the kill-switch duration (see Killswitch); use --kill-switch 0 to disable that time bound for a truly indefinite retry loop.

Direct SSH connection

Use this when the target can reach the server’s SSH listener directly.

Flags

  • --ssh-server: ([IP/Hostname]:[PORT])
  • --rssh-port: the remote port the SSH tunnel binds to on the server side (default: 0, meaning a random port is chosen).

SSH over TLS

The SSH connection is encapsulated over a TLS connection.

Flags

  • --tls-server: ([IP/Hostname]:[PORT]) address of the TLS listener on the server.

The target SSH service itself is still the one configured via the --ssh-server flag; --tls-server only configures the TLS transport used to reach it.

SSH over WebSocket

The SSH connection is encapsulated over a WebSocket connection.

This makes it easier to bypass restrictive proxies while maintaining acceptable performance.

Flags

  • --server: the WebSocket endpoint is [server]/wssh/

SSH over HTTP

The SSH connection is encapsulated over HTTP requests/responses.

Flags

  • --server: the HTTP endpoint is [server]/sshttp/

SSH over DNS

This transport encapsulates SSH traffic inside DNS queries and responses, allowing communication in highly restricted environments where only DNS traffic is permitted.

Flags

  • --dns-server: DNS resolvers used to reach the Goauld DNS server. Optionally includes the Goauld server itself if directly reachable.
    • The special value system automatically adds detected system DNS servers to the list.
  • --dns-domain: the domain on which DNS queries are performed
  • --custom-dns-command: in some cases, the DNS queries are not feasible directly, but system commands such as Resolve-DnsName are still allowed to perform DNS queries. When this flag is used, the provided command is executed for each DNS query. The command is responsible for performing the DNS query, and parsing the DNS response and returning the response as raw bytes.
((Resolve-DnsName -Type TXT -Server 127.0.0.1 '%s')[0].Strings -join '' -replace '\s+', '' -split '..' | ForEach-Object { [Convert]::ToByte($_,16) } )
dig +short +unknownformat -t TXT '%s' @127.0.0.1 | head -n1 | cut -d ' ' -f3- | tr -d ' '  | xxd -r -p

SSH over QUIC

The SSH connection is encapsulated over QUIC. This transport is opt-in and not part of the default --rssh-order (see the note above); add quic to --rssh-order to enable it.

Flags

  • --quic-domain: the QUIC domain used to tunnel traffic.

Browser proxy

The agent can use a web browser to tunnel all the traffic.

  1. The agent exposes a simple web page with custom JavaScript. The JavaScript opens 4 WebSocket connections
    1. Two connecting to the server (Control & data)
    2. Two connecting to the agent (Control & data)
      • The agent exposes a custom endpoint to allow the browser to initiate the connection to the agent
  2. The web page pipes the WebSocket connections

Flags

  • --browser-proxy-port: the port used to expose the custom web pages and the WebSocket endpoints used by the browser to connect to the agent.

Egress proxies

If required, the agent will try to reach the server using the proxy configuration identified on the system (see https://github.com/aus/proxyplease?tab=readme-ov-file#proxy-selection).

Flags

  • --proxy: use a custom proxy instead of the system proxy
  • --proxy-username: Username to authenticate on the proxy
  • --proxy-password: Password to authenticate on the proxy
  • --proxy-domain: Domain to authenticate on the proxy
  • --no-proxy: Ignore the system proxy

The proxy will be selected by the following priority:

Windows

  1. --proxy [PROXY_URL] (or any other means allowing configuration of the proxy flag; see Compilation)
  2. Environment Variable: HTTPS_PROXY, HTTP_PROXY, FTP_PROXY, or ALL_PROXY. NO_PROXY is respected.
  3. Internet Options: Automatically detect settings (WPAD)
  4. Internet Options: Use automatic configuration script (PAC)
  5. Internet Options: Manual proxy server
  6. WINHTTP: (netsh winhttp)

Linux

  1. --proxy [PROXY_URL] (or any other means allowing configuration of the proxy flag; see Compilation)
  2. Environment Variable: HTTPS_PROXY, HTTP_PROXY, FTP_PROXY, or ALL_PROXY. NO_PROXY is respected.

macOS

  1. --proxy [PROXY_URL] (or any other means allowing configuration of the proxy flag; see Compilation)
  2. Environment Variable: HTTPS_PROXY, HTTP_PROXY, FTP_PROXY, or ALL_PROXY. NO_PROXY is respected.
  3. Network Settings: scutil

Agent binding

The client connects directly to the port exposed by the agent (see Agent binding).

Flags

  • --rssh-order=bind
  • --bind-port