TUN — mihomo
mihomo's tun: is a top-level config block (not a listeners: entry). The schema is nearly identical to sing-box's TUN inbound (mihomo's implementation is derived from sing-box's) with a few mihomo-specific additions: explicit dns-hijack, MAC-address filtering, ICMP-drop toggle, and Darwin recvmsg_x/sendmsg_x optimization flags.
Top-level tun: block
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
enable | bool | false | true | false | Master switch. When false the rest of the block is ignored. |
device | string | (auto) | <interface name> | TUN device name. |
stack | C.TUNStack | mixed | system | gvisor | mixed | Same as sing-box: pick the TCP/IP stack. |
dns-hijack | []string | [] | [<address>] | Addresses that should be hijacked as DNS — outgoing UDP to these endpoints is redirected to the internal DNS engine. Standard value: `[any:53]` (catch all). |
auto-route | bool | false | true | false | Auto-install OS routes. |
auto-detect-interface | bool | false | true | false | Auto-discover the default outbound interface — used for excluding TUN-bound traffic from re-entering TUN. |
mtu | uint32 | 0 (auto) | <bytes> | Device MTU. 0 picks a sensible default (9000 on most platforms). |
gso | bool | false | true | false | Generic Segmentation Offload (Linux). Improves throughput when the kernel supports it. |
gso-max-size | uint32 | 65536 | <bytes> | Maximum segment size when GSO is active. |
inet6-address | []netip.Prefix | [] | <CIDR> | IPv6 addresses to assign to the device. IPv4 uses the top-level `inet4-address` field (currently commented in source — see `config/config.go:278`). |
iproute2-table-index | int | 2022 | <int> | Linux iproute2 table index. |
iproute2-rule-index | int | 9000 | <int> | Linux iproute2 rule index. |
auto-redirect | bool | false | true | false | Linux NFTables auto-redirect (faster than auto-route on hot paths). |
auto-redirect-input-mark | uint32 | 0 | <uint32> | fwmark on TUN-bound packets. |
auto-redirect-output-mark | uint32 | 0 | <uint32> | fwmark on TUN-egress packets. |
auto-redirect-iproute2-fallback-rule-index | int | 0 | <int> | Fallback rule index when auto-redirect can't install. |
loopback-address | []netip.Addr | [] | <IP> | Addresses treated as loopback. |
strict-route | bool | false | true | false | Block traffic that would otherwise bypass TUN (kill-switch semantics). |
route-address | []netip.Prefix | [] | <CIDR> | Route only these CIDRs through TUN when `auto-route` is on. |
route-address-set | []string | [] | <rule-provider name> | Rule-provider-driven inclusion. |
route-exclude-address | []netip.Prefix | [] | <CIDR> | CIDRs to keep on the default interface. |
route-exclude-address-set | []string | [] | <rule-provider name> | Rule-provider-driven exclusion. |
include-interface | []string | [] | <interface> | Only attach to these interfaces. |
exclude-interface | []string | [] | <interface> | Exclude these interfaces. |
include-uid | []uint32 | [] | <uid> | UID inclusion. |
include-uid-range | []string | [] | <from:to> | UID range inclusion. |
exclude-uid | []uint32 | [] | <uid> | UID exclusion. |
exclude-uid-range | []string | [] | <from:to> | UID range exclusion. |
exclude-src-port | []uint16 | [] | <port> | Source-port exclusion. |
exclude-src-port-range | []string | [] | <from:to> | Source-port range exclusion. |
exclude-dst-port | []uint16 | [] | <port> | Destination-port exclusion. |
exclude-dst-port-range | []string | [] | <from:to> | Destination-port range exclusion. |
include-android-user | []int | [] | <user id> | Android multi-user inclusion. |
include-package | []string | [] | <package name> | Android package inclusion. |
exclude-package | []string | [] | <package name> | Android package exclusion. |
include-mac-address | []string | [] | <MAC> | MAC-based inclusion (mihomo-specific, not in sing-box). |
exclude-mac-address | []string | [] | <MAC> | MAC-based exclusion. |
endpoint-independent-nat | bool | false | true | false | Enable endpoint-independent NAT for UDP. Required by some games / VoIP apps. |
udp-timeout | int64 | 300 | <seconds> | UDP idle timeout in seconds. |
disable-icmp-forwarding | bool | false | true | false | Drop ICMP packets at the TUN layer (mihomo-specific). |
file-descriptor | int | 0 | <fd> | Use a pre-opened file descriptor instead of creating a TUN device. Useful for VPN-service integration where the OS hands you the fd. |
inet4-route-address | []netip.Prefix | — | — | |
inet6-route-address | []netip.Prefix | — | — | |
inet4-route-exclude-address | []netip.Prefix | — | — | |
inet6-route-exclude-address | []netip.Prefix | — | — | |
recvmsgx | bool | false | true | false | Darwin only — use the recvmsg_x syscall for batching. |
sendmsgx | bool | false | true | false | Darwin only — use sendmsg_x. |
Source: config/config.go:268-321 · pinned at v1.19.27 (5184081)
Stack choice
Identical to sing-box:
system— kernel TCP/IP. Fastest, requires kernel TUN support.gvisor— userspace stack. Slower, portable.mixed— gVisor for TCP, system for UDP. Default.
DNS hijack
dns-hijack is mihomo's idiomatic way to route DNS queries through the internal resolver:
tun:
enable: true
dns-hijack:
- any:53 # All UDP/53 traffic
- tcp://any:53 # And TCP/53
- 8.8.8.8:53 # Specific server onlyThis is implemented at the TUN layer — DNS packets are intercepted before they reach the routing rules. It's faster than running a UDP inbound on 53 and routing back through the rules.
Examples
Desktop transparent proxy:
tun:
enable: true
device: mihomo-tun
stack: mixed
mtu: 9000
dns-hijack:
- any:53
- tcp://any:53
auto-route: true
auto-detect-interface: true
strict-route: true
route-address:
- 0.0.0.0/1
- 128.0.0.0/1
- ::/1
- 8000::/1
route-exclude-address:
- 192.168.0.0/16
- 10.0.0.0/8Linux NFTables auto-redirect:
tun:
enable: true
device: utun0
stack: system
dns-hijack: [any:53]
auto-redirect: true
auto-redirect-input-mark: 0x100
auto-redirect-output-mark: 0x200Android app split — proxy only specific apps:
tun:
enable: true
stack: system
mtu: 9000
dns-hijack: [any:53]
auto-route: true
include-package:
- com.netflix.mediaclient
- com.spotify.music
exclude-package:
- com.google.android.gmsNotes
inet4-addressis commented out in the source (config/config.go:278) — mihomo currently uses a hard-coded default IPv4 range (198.18.0.1/30). IPv6 still uses the explicitinet6-addressfield.dns-hijackaccepts a couple of special forms:any:53matches both TCP and UDP port 53.- Prefix with
tcp://orudp://to scope. - Bare
IP:portfor specific upstream resolvers.
auto-routeandauto-redirectare mutually exclusive. Pick one based on your kernel: NFTables-capable kernels prefer auto-redirect for performance.- The
recvmsgx/sendmsgxflags are macOS-only optimizations that use the per-syscall batching variants. Enable them on macOS for throughput. disable-icmp-forwardingis mihomo-specific — useful when you have a separate ICMP path (e.g. a routing-table-based pinger) and don't want TUN to capture pings.
Cross-core notes
- Xray-core has a minimal TUN inbound. See TUN — Xray-core.
- sing-box has the same feature set under
type: "tun"listed ininbounds[]with snake_case names. See TUN — sing-box.
Source: config/config.go:268-321 · v1.19.27 (5184081)
