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":
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
interface_name | string | (auto) | <interface name> | TUN device name. Empty picks an OS-default (`tun0`, `utun5`, etc.). |
mtu | uint32 | 9000 | <bytes> | MTU for the device. 9000 is sing-box's default — high to amortize packet overhead. |
address | badoption.Listable[netip.Prefix] | [] | <CIDR> | Interface addresses (one IPv4 + one IPv6 typical). Replaces the deprecated `inet4_address` / `inet6_address` pair. |
auto_route | bool | false | true | false | Auto-install OS routes that direct all traffic to the TUN device. |
iproute2_table_index | int | 2022 | <int> | Linux iproute2 table index used by `auto_route`. |
iproute2_rule_index | int | 9000 | <int> | Linux iproute2 rule index. |
auto_redirect | bool | false | true | false | Linux NFTables auto-redirect — splice traffic into TUN without changing routes. Faster than auto_route on hot loopback paths. |
auto_redirect_input_mark | FwMark | 0 | <uint32> | fwmark applied to TUN-bound packets. |
auto_redirect_output_mark | FwMark | 0 | <uint32> | fwmark applied to TUN-egress packets. |
auto_redirect_reset_mark | FwMark | 0 | <uint32> | fwmark to remove after processing. |
auto_redirect_nfqueue | uint16 | 0 | <uint16> | NFQUEUE number for the auto-redirect path. |
auto_redirect_iproute2_fallback_rule_index | int | 0 | <int> | Fallback rule index when auto-redirect can't be installed. |
exclude_mptcp | bool | false | true | false | Skip MPTCP flows (let them use the normal kernel path). |
loopback_address | badoption.Listable[netip.Addr] | [] | <IP> | Addresses treated as loopback (don't route through TUN). |
strict_route | bool | false | true | false | Block traffic from leaking around the TUN device (DROP rules on the default-route boundary). |
route_address | badoption.Listable[netip.Prefix] | [] | <CIDR> | When `auto_route` is on, route only these CIDRs through TUN. Default routes everything. |
route_address_set | badoption.Listable[string] | [] | <rule-set tag> | Route based on rule-set IP-CIDR entries instead of an explicit list. |
route_exclude_address | badoption.Listable[netip.Prefix] | [] | <CIDR> | CIDRs to keep on the default interface (escape hatch). |
route_exclude_address_set | badoption.Listable[string] | [] | <rule-set tag> | Rule-set-driven exclusion. |
include_interface | badoption.Listable[string] | [] | <interface> | Only attach to these interfaces (mobile multi-NIC). |
exclude_interface | badoption.Listable[string] | [] | <interface> | Exclude these interfaces. |
include_uid | badoption.Listable[uint32] | [] | <uid> | Linux/macOS UID inclusion. |
include_uid_range | badoption.Listable[string] | [] | <from:to> | UID range inclusion. |
exclude_uid | badoption.Listable[uint32] | [] | <uid> | UID exclusion. |
exclude_uid_range | badoption.Listable[string] | [] | <from:to> | UID range exclusion. |
include_android_user | badoption.Listable[int] | [] | <user id> | Android multi-user inclusion. |
include_package | badoption.Listable[string] | [] | <package name> | Android package inclusion. |
exclude_package | badoption.Listable[string] | [] | <package name> | Android package exclusion. |
udp_timeout | UDPTimeoutCompat | 5m | <duration or seconds> | Idle timeout for UDP flows. |
stack | string | mixed | system | gvisor | mixed | TCP/IP stack implementation. `system` uses the kernel's network stack; `gvisor` runs a userspace stack; `mixed` uses gVisor for TCP and the system for UDP. |
platform | *TunPlatformOptions | (unset) | TunPlatformOptions | Platform-specific overrides (currently just `http_proxy`). |
gso | bool | — | — | Deprecated: removed |
inet4_address | badoption.Listable[netip.Prefix] | — | — | Deprecated: merged to Address |
inet6_address | badoption.Listable[netip.Prefix] | — | — | Deprecated: merged to Address |
inet4_route_address | badoption.Listable[netip.Prefix] | — | — | Deprecated: merged to RouteAddress |
inet6_route_address | badoption.Listable[netip.Prefix] | — | — | Deprecated: merged to RouteAddress |
inet4_route_exclude_address | badoption.Listable[netip.Prefix] | — | — | Deprecated: merged to RouteExcludeAddress |
inet6_route_exclude_address | badoption.Listable[netip.Prefix] | — | — | Deprecated: merged to RouteExcludeAddress |
endpoint_independent_nat | bool | — | — | Deprecated: removed |
Source: option/tun.go:13-63 · pinned at v1.13.11 (553cfa1)
The struct also embeds InboundOptions (sniff, sniff_override_dest, domain_strategy, …).
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— gVisor for TCP (where userspace state-machine bugs matter less), system for UDP (where it matters more). The default and what most users want.
Routing models
sing-box's TUN supports two routing approaches:
auto_route: true(cross-platform). Installs OS routes directing all traffic to the TUN. On Linux, uses iproute2 table + rule indices. On macOS, programsroute add. On Windows, programs the routing table directly.auto_redirect: true(Linux only). Installs NFTables redirect rules instead of changing routes. Faster on hot-loopback paths because there's no extra hop. Requiresnftand 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):
{
"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",
"sniff": true,
"sniff_override_dest": true
}],
"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:
{
"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):
{
"inbounds": [{
"type": "tun",
"auto_redirect": true,
"auto_redirect_input_mark": "0x100",
"auto_redirect_output_mark": "0x200",
"address": ["172.16.0.1/30"]
}]
}Notes
addresswas previously two fields (inet4_address/inet6_address). Both still parse but emit deprecation warnings — configs should use the new combinedaddresslist.endpoint_independent_natwas removed. Set it on the route rule action instead (viaudp_disable_domain_unmapping).gsowas removed — kernel GSO is auto-detected.auto_routeandauto_redirectare mutually exclusive. Pick one.strict_routeon Linux uses NFTables when available, falls back to iptables. Both require root.
Cross-core notes
- Xray-core has a minimal TUN inbound — no auto-route, no DNS hijack, 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 extradns-hijacklist. See TUN — mihomo.
Source: option/tun.go:13-63 · v1.13.11 (553cfa1)
