Skip to content

TUN — sing-box ​

sing-box's TUN inbound is the canonical implementation of a Go-land TUN — most other implementations (mihomo's, Clash-Meta, others) are derived from it. The inbound creates a TUN device, parses raw packets in either the system or gVisor stack, and dispatches resulting connections to the routing engine.

Inbound ​

type: "tun":

FieldTypeDefaultAllowed valuesDescription
interface_namestring(auto)<interface name>TUN device name. Empty picks an OS-default (tun0, utun5, etc.).
netnsstring(unset)<network namespace tag / name / path>Linux only. Create the TUN interface inside this network namespace — a tag from the top-level network_namespaces, or a namespace name or path. auto_route / auto_redirect then operate inside the namespace, and no root is needed if the current user owns it. Conflicts with platform.
mtuuint3265535<bytes>MTU for the device. When unset: 65535, or 9000 on Android and 4064 inside an Apple Network Extension.
addressbadoption.Listable[netip.Prefix][]<CIDR>Interface addresses (one IPv4 + one IPv6 typical). The old inet4_address / inet6_address fields are rejected at startup.
dns_modestringhijackdisabled | native | hijackHow DNS is handled on the TUN interface. native sets the platform's interface DNS (systemd-resolved on Linux, per-interface DNS on Windows / Apple); hijack (default) additionally intercepts port-53 traffic — an iproute2 rule on Linux, an nftables DNAT to dns_address with auto_redirect, a WFP filter on Windows with strict_route; disabled does neither.
dns_addressbadoption.Listable[netip.Addr](derived from address)<IP>DNS server address(es) used by dns_mode. When unset, one per family is derived as the next IP after the first address entry, and connections to it are hijacked into the DNS module automatically (like a hijack-dns rule). Once set, that auto-hijack is off — add an explicit hijack-dns route rule if you still need it.
auto_routeboolfalsetrue | falseAuto-install OS routes that direct all traffic to the TUN device.
iproute2_table_indexint2022<int>Linux iproute2 table index used by auto_route.
iproute2_rule_indexint9000<int>Linux iproute2 rule index.
auto_redirectboolfalsetrue | falseLinux NFTables auto-redirect — splice traffic into TUN without changing routes. Faster than auto_route on hot loopback paths.
auto_redirect_input_markFwMark0<uint32>fwmark applied to TUN-bound packets.
auto_redirect_output_markFwMark0<uint32>fwmark applied to TUN-egress packets.
auto_redirect_reset_markFwMark0<uint32>fwmark to remove after processing.
auto_redirect_nfqueueuint160<uint16>NFQUEUE number for the auto-redirect path.
auto_redirect_iproute2_fallback_rule_indexint0<int>Fallback rule index when auto-redirect can't be installed.
exclude_mptcpboolfalsetrue | falseSkip MPTCP flows (let them use the normal kernel path).
loopback_addressbadoption.Listable[netip.Addr][]<IP>Addresses treated as loopback (don't route through TUN).
strict_routeboolfalsetrue | falseBlock traffic from leaking around the TUN device (DROP rules on the default-route boundary).
route_addressbadoption.Listable[netip.Prefix][]<CIDR>When auto_route is on, route only these CIDRs through TUN. Default routes everything.
route_address_setbadoption.Listable[string][]<rule-set tag>Route based on rule-set IP-CIDR entries instead of an explicit list.
route_exclude_addressbadoption.Listable[netip.Prefix][]<CIDR>CIDRs to keep on the default interface (escape hatch).
route_exclude_address_setbadoption.Listable[string][]<rule-set tag>Rule-set-driven exclusion.
include_interfacebadoption.Listable[string][]<interface>Only attach to these interfaces (mobile multi-NIC).
exclude_interfacebadoption.Listable[string][]<interface>Exclude these interfaces.
include_uidbadoption.Listable[uint32][]<uid>Linux/macOS UID inclusion.
include_uid_rangebadoption.Listable[string][]<from:to>UID range inclusion.
exclude_uidbadoption.Listable[uint32][]<uid>UID exclusion.
exclude_uid_rangebadoption.Listable[string][]<from:to>UID range exclusion.
include_android_userbadoption.Listable[int][]<user id>Android multi-user inclusion.
include_packagebadoption.Listable[string][]<package name>Android package inclusion.
exclude_packagebadoption.Listable[string][]<package name>Android package exclusion.
include_mac_addressbadoption.Listable[string][]<MAC address>Linux with auto_route and auto_redirect only. Route only traffic from these source MAC addresses (e.g. LAN clients on a router). Conflicts with exclude_mac_address.
exclude_mac_addressbadoption.Listable[string][]<MAC address>Linux with auto_route and auto_redirect only. Exclude these source MAC addresses. Conflicts with include_mac_address.
udp_timeoutUDPTimeoutCompat5m<duration or seconds>Idle timeout for UDP flows.
udp_mappingUDPNATBehaviorendpoint_independentendpoint_independent | address_dependent | address_and_port_dependentUDP NAT mapping: reuse one mapping per source address and port for all destinations (default), or a separate mapping per destination address / address and port.
udp_filteringUDPNATBehaviorendpoint_independentendpoint_independent | address_dependent | address_and_port_dependentUDP NAT filtering: accept packets from any remote endpoint (default), or only from addresses / address-and-port pairs already sent to.
udp_nat_maxuint320 (auto)<uint32>Maximum number of UDP NAT sessions; the least recently used one is closed when full. 0 means 4096 on iOS, otherwise 4096–16384 based on total memory (16384 if it can't be detected).
stackstring(mixed / system)system | gvisor | mixedTCP/IP stack implementation. system uses the kernel's network stack; gvisor runs a userspace stack; mixed uses the system stack for TCP and gVisor for UDP. Defaults to mixed when built with gVisor, otherwise system.
platform*TunPlatformOptions(unset)TunPlatformOptionsPlatform-specific overrides (currently just http_proxy).

Source: option/tun.go:14-72 · pinned at v1.14.2 (af6e64c)

The struct also embeds InboundOptions (sniff, sniff_override_dest, domain_strategy, …), but only to reject them at startup — see Notes.

Stack choice ​

  • system — kernel's native TCP/IP. Fastest. Requires the OS to expose the right TUN ioctls (Linux: yes; macOS: utun yes; Windows: wintun via DLL).
  • gvisor — Google's userspace TCP/IP stack. Slower but portable; the only choice on platforms without good kernel TUN support.
  • mixed — system for TCP (kernel-grade throughput on the connection-heavy path), gVisor for UDP. The default in builds with gVisor (otherwise system is the default) and what most users want.

Routing models ​

sing-box's TUN supports two routing approaches:

  1. auto_route: true (cross-platform). Installs OS routes directing all traffic to the TUN. On Linux, uses iproute2 table + rule indices. On macOS, programs route add. On Windows, programs the routing table directly.

  2. auto_redirect: true (Linux only, on top of auto_route). Adds nftables rules that redirect traffic into sing-box — better routing and performance than plain auto_route or tproxy, no conflicts with Docker bridge networks, and automatic OpenWrt fw4 integration. Requires nft and matching kernel modules.

strict_route: true adds DROP rules on the surrounding interface to prevent traffic leaking around the TUN — important for kill-switch semantics.

Examples ​

Standard desktop setup (Linux/macOS):

json
{
  "inbounds": [{
    "type": "tun",
    "tag": "tun-in",
    "interface_name": "sing-tun",
    "mtu": 9000,
    "address": ["172.16.0.1/30", "fdfe:dcba:9876::1/126"],
    "auto_route": true,
    "strict_route": true,
    "stack": "mixed"
  }],
  "route": {
    "auto_detect_interface": true,
    "rules": [
      { "action": "sniff" },
      { "protocol": "dns", "action": "hijack-dns" },
      { "ip_is_private": true, "outbound": "direct" }
    ],
    "final": "proxy"
  }
}

Android app filtering — proxy only the listed packages:

json
{
  "inbounds": [{
    "type": "tun",
    "interface_name": "tun0",
    "mtu": 9000,
    "address": ["172.16.0.1/30"],
    "auto_route": true,
    "stack": "system",
    "include_package": ["com.netflix.mediaclient", "com.spotify.music"]
  }]
}

Linux with NFTables auto-redirect (preferred over auto-route on busy hosts):

json
{
  "inbounds": [{
    "type": "tun",
    "auto_route": true,
    "auto_redirect": true,
    "auto_redirect_input_mark": "0x100",
    "auto_redirect_output_mark": "0x200",
    "address": ["172.16.0.1/30"]
  }]
}

Notes ​

  • The default dns_mode (hijack) changes system state: sing-box sets the TUN interface's native DNS and installs port-53 hijacking. Set "dns_mode": "disabled" to leave interface DNS and the firewall untouched.
  • The inet4_address / inet6_address fields, their inet4_* / inet6_* route variants and gso parse but are rejected at startup; they are hidden from the table above. Use address, route_address and route_exclude_address.
  • The inbound fields embedded in this struct (sniff, sniff_override_dest, domain_strategy, …) are rejected at startup — use sniff / resolve route rule actions instead.
  • endpoint_independent_nat is parsed but ignored. UDP NAT behaviour is set with udp_mapping / udp_filtering (endpoint-independent by default) and capped by udp_nat_max.
  • auto_redirect requires auto_route (Linux only) and conflicts with route.default_mark and dial-level routing_mark.
  • With auto_route, strict_route makes unsupported networks unreachable; on Windows it also prevents DNS leaks from multihomed resolution. On Linux with auto_redirect it additionally sends SO_BINDTODEVICE traffic through sing-box.

Cross-core notes ​

  • Xray-core has a minimal TUN inbound — it can install routes via autoSystemRoutingTable, but has no DNS hijack and no app filtering. See TUN — Xray-core.
  • mihomo has a nearly identical feature set under the top-level tun: block, with kebab-case field names and an extra dns-hijack list. See TUN — mihomo.

Source: option/tun.go:14-72 · v1.14.2 (af6e64c)

Core Tutorial by Argsment