Transport, Proxy, and DNS

Go SDK Transport, Proxy, and DNS

Configure how Go agents reach the rstream engine.


Transport settings control how a Go process reaches the rstream engine. They do not change what a tunnel publishes. A published HTTP tunnel, a private TCP tunnel, and a datagram tunnel can all use the same agent transport policy.

Direct TLS Transport

The default transport opens a TCP connection to the engine and negotiates the rstream TLS session end to end.

client, err := rstream.NewClient(rstream.ClientOptions{
  Engine: "project-endpoint.cluster.example.rstream.test:443",
  Token:  os.Getenv("RSTREAM_AUTHENTICATION_TOKEN"),
})
if err != nil {
  log.Fatal(err)
}

Bind options can pin the local source address or constrain the address family.

client := &rstream.Client{
  EngineURL: "project-endpoint.cluster.example.rstream.test:443",
  Token:     os.Getenv("RSTREAM_AUTHENTICATION_TOKEN"),
  Transport: &rstream.Transport{
    LocalAddr: rstream.StringPtr("10.10.0.25"),
    ForceIPv4: rstream.BoolPtr(true),
  },
}

MPTCPEnabled can be enabled for TCP paths when the host and network support Multipath TCP.

QUIC Transport

QUICTransport uses one QUIC connection for SDK-to-engine streams and datagrams. Select it directly in code when the process owns its transport configuration.

client := &rstream.Client{
  EngineURL: "project-endpoint.cluster.example.rstream.test:443",
  Token:     os.Getenv("RSTREAM_AUTHENTICATION_TOKEN"),
  Transport: &rstream.QUICTransport{},
}

The config bridge can select QUIC for a process with RSTREAM_QUIC_TRANSPORT=1, or from YAML with transport.useQuic: true.

contexts:
  - name: lab
    engine: project-endpoint.cluster.example.rstream.test:443
    transport:
      useQuic: true

QUICTransport is stateful. Keep one instance for the lifetime of the client and create a fresh instance after a connection failure.

Proxy Support Matrix

The Go SDK supports proxying the agent-to-engine session for both TCP/TLS and QUIC transports.

Agent transportProxy typeProtocol used between agent and proxy
Transportproxy.httpHTTP CONNECT for a TCP tunnel to the engine.
Transportproxy.socks5SOCKS5 CONNECT for a TCP tunnel to the engine.
QUICTransportproxy.httpHTTPS MASQUE CONNECT-UDP to the engine UDP endpoint.
QUICTransportproxy.socks5SOCKS5 UDP ASSOCIATE to the engine UDP endpoint.

Configure only one proxy type at a time. The SDK rejects configurations that set both proxy.http and proxy.socks5.

proxy.fromEnvironment: true reads the process proxy environment when neither proxy.http nor proxy.socks5 is set. The lookup honors HTTPS_PROXY, HTTP_PROXY, ALL_PROXY, and NO_PROXY in upper- and lower-case forms. HTTP and HTTPS proxy URLs become HTTP proxy transport settings, while socks5:// and socks5h:// become SOCKS5 proxy settings.

contexts:
  - name: corp-env
    engine: project-endpoint.cluster.example.rstream.test:443
    transport:
      proxy:
        fromEnvironment: true

The Go SDK does not read desktop proxy preferences directly from macOS System Settings, Windows Internet Options, or similar GUI stores. Agents and services should receive deterministic process environment variables or explicit YAML transport settings.

HTTP CONNECT Proxy for TCP/TLS

Use proxy.http when a network requires outbound TCP through an HTTP proxy.

contexts:
  - name: corp
    engine: project-endpoint.cluster.example.rstream.test:443
    transport:
      proxy:
        http: http://proxy.corp:3128
        username: agent
        password: "<proxy-password>"
        headers:
          X-Company: acme

In Go code, the equivalent configuration is explicit on rstream.Transport.

transport := &rstream.Transport{
  ProxyHTTP:     rstream.StringPtr("http://proxy.corp:3128"),
  ProxyUsername: rstream.StringPtr("agent"),
  ProxyPassword: rstream.StringPtr(os.Getenv("PROXY_PASSWORD")),
  ProxyHTTPHeaders: map[string]string{
    "X-Company": "acme",
  },
}

The HTTP proxy sees the CONNECT target authority. The rstream TLS session is negotiated through that TCP tunnel and remains end to end between the SDK and the engine.

MASQUE Proxy for QUIC Transport

QUIC transport cannot use classic HTTP CONNECT because QUIC runs over UDP. When QUICTransport is combined with proxy.http, the SDK uses HTTPS MASQUE CONNECT-UDP.

contexts:
  - name: masque
    engine: project-endpoint.cluster.example.rstream.test:443
    transport:
      useQuic: true
      proxy:
        http: https://masque-proxy.corp

The default MASQUE URI template expands to the standard well-known CONNECT-UDP route.

https://masque-proxy.corp:443/.well-known/masque/udp/{target_host}/{target_port}/

Use a custom template when the proxy publishes a different route.

transport:
  useQuic: true
  proxy:
    http: https://masque-proxy.corp/connect-udp/{target_host}/{target_port}

proxy.username, proxy.password, and proxy.headers apply to HTTP CONNECT proxy paths. For QUIC over MASQUE, authenticate the proxy endpoint at the MASQUE layer or with the deployment policy provided by that proxy.

SOCKS5 Proxy

Use proxy.socks5 when a SOCKS5 proxy is the approved egress path.

contexts:
  - name: socks
    engine: project-endpoint.cluster.example.rstream.test:443
    transport:
      proxy:
        socks5: socks5://proxy.corp:1080
        username: agent
        password: "<proxy-password>"

The same proxy.socks5 setting works with transport.useQuic: true. TCP/TLS uses SOCKS5 CONNECT. QUIC uses SOCKS5 UDP ASSOCIATE.

contexts:
  - name: socks-quic
    engine: project-endpoint.cluster.example.rstream.test:443
    transport:
      useQuic: true
      proxy:
        socks5: socks5://proxy.corp:1080

HTTP proxy headers do not apply to SOCKS5.

DNS Behavior

With no custom DNS settings, proxied target resolution stays with the proxy whenever the proxy protocol supports it. HTTP CONNECT, MASQUE CONNECT-UDP, and SOCKS5 can receive the engine hostname and resolve it from the proxy side.

When transport.dns is configured, the SDK intentionally resolves the engine name before opening the proxied connection and sends the selected IP address to the proxy. This is the correct mode when the client must use a dedicated resolver, DNS over TLS, DNSSEC validation, or a resolver reachable through a specific local route.

transport:
  dns:
    override: 1.1.1.1:853
    tls: true
    serverName: cloudflare-dns.com
    dnssec: true

The same DNS policy is used for direct engine hostname resolution and for ECH discovery through DNS SVCB and HTTPS records. Without explicit DNS settings, the SDK uses the platform resolver configuration. On macOS, scoped per-domain resolvers from the system DNS state are respected.

Bind and address-family settings apply to the local side of the selected path. With a proxy, that means the TCP or UDP socket opened toward the proxy is bound or constrained; with custom DNS, the SDK resolves the engine hostname first and sends the selected IP address through the proxy protocol.

Environment Variables

The config bridge reads the same core environment variables as the CLI.

VariableUse
RSTREAM_CONFIGSelect the configuration file path.
RSTREAM_CONTEXTSelect a named context from the configuration file.
RSTREAM_ENGINEOverride the engine endpoint used by runtime clients.
RSTREAM_AUTHENTICATION_TOKENOverride the authentication token used by the SDK.
RSTREAM_MTLS_CERT_FILEClient certificate file for mTLS agent authentication.
RSTREAM_MTLS_KEY_FILEClient private key file for mTLS agent authentication.
RSTREAM_QUIC_TRANSPORTSet to 1 to make config.NewClientFromEnv() use QUIC transport while preserving configured bind, DNS, and proxy settings.
HTTPS_PROXY / HTTP_PROXY / ALL_PROXY / NO_PROXYUsed when transport.proxy.fromEnvironment is true and no explicit proxy URL is configured.

Token authentication and mTLS agent authentication are mutually exclusive for the control-channel connection. When both mTLS variables are set, the SDK authenticates that connection with the client certificate and does not use a stored context token.