Skip to content

Direct — sing-box ​

Direct is sing-box's passthrough outbound and a useful "test echo" inbound. The outbound side is deliberately minimal — destination overrides are a route-engine concern (route actions), not outbound fields.

Inbound ​

type: "direct":

FieldTypeDefaultAllowed valuesDescription
networkNetworkList(tcp+udp)tcp | udp | Restrict to TCP-only or UDP-only.
override_addressstring(unset)<host>Rewrite the destination address of every accepted connection.
override_portuint16(unset)<port>Rewrite the destination port of every accepted connection.

Source: option/direct.go:10-15 · pinned at v1.14.2 (af6e64c)

Embeds ListenOptions (listen address, port, …). The Direct inbound is mostly used as a port-forwarder — accept on one port, rewrite the destination, route through any outbound.

Outbound ​

type: "direct":

FieldTypeDefaultAllowed valuesDescription
override_addressstring(rejected)(use route actions)Not supported on the outbound: setting it produces a startup error pointing at route actions.
override_portuint16(rejected)(use route actions)Same as override_address — not supported; use route actions.
proxy_protocoluint8(unsupported)0Not supported: any non-zero value is rejected at startup.

Source: option/direct.go:17-25 · pinned at v1.14.2 (af6e64c)

The outbound consists only of the embedded DialerOptions (bind_interface, routing_mark, detour, …). The three fields above are rejected at config load; set destination overrides with route rule options instead (override_address / override_port on a route action).

Examples ​

Bare direct outbound (the most common case — just give traffic an exit):

json
{
  "outbounds": [
    { "type": "direct", "tag": "direct" }
  ]
}

Direct outbound bound to a specific interface:

json
{
  "outbounds": [
    {
      "type": "direct",
      "tag": "direct-eth0",
      "bind_interface": "eth0"
    }
  ]
}

Inbound port-forwarder (accept on 8080, rewrite destination to internal:80):

json
{
  "inbounds": [
    {
      "type": "direct",
      "tag": "forward-8080",
      "listen": "0.0.0.0",
      "listen_port": 8080,
      "override_address": "10.0.0.5",
      "override_port": 80
    }
  ]
}

Notes ​

  • The route-action replacement for override_address / override_port looks like:

    json
    {
      "route": {
        "rules": [
          {
            "inbound": ["forward-8080"],
            "action": "route",
            "outbound": "direct",
            "override_address": "10.0.0.5",
            "override_port": 80
          }
        ]
      }
    }

    That moves the same behavior from the protocol layer to the routing rule, which composes more cleanly with the rest of the routing surface.

  • The bridge outbound is the L3 counterpart of direct: it forwards L3 traffic (TCP, UDP, ICMP) from a TUN or other L3 endpoint straight out of a network interface. See Outbounds.

Cross-core notes ​

  • Xray-core calls this Freedom. The outbound exposes a much richer feature set — TCP/TLS fragmentation, noise injection, the redirect field — see Freedom — Xray-core.
  • mihomo has the same minimal Direct shape and auto-injects a built-in DIRECT named proxy. See Direct — mihomo.

Source: option/direct.go:10-25 · v1.14.2 (af6e64c)

Core Tutorial by Argsment