Skip to content

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

FieldTypeDefaultAllowed valuesDescription
enableboolfalsetrue | falseMaster switch. When false the rest of the block is ignored.
devicestring(auto)<interface name>TUN device name.
stackC.TUNStackmixedsystem | gvisor | mixedSame 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-routeboolfalsetrue | falseAuto-install OS routes.
auto-detect-interfaceboolfalsetrue | falseAuto-discover the default outbound interface — used for excluding TUN-bound traffic from re-entering TUN.
mtuuint320 (auto)<bytes>Device MTU. 0 picks a sensible default (9000 on most platforms).
gsoboolfalsetrue | falseGeneric Segmentation Offload (Linux). Improves throughput when the kernel supports it.
gso-max-sizeuint3265536<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-indexint2022<int>Linux iproute2 table index.
iproute2-rule-indexint9000<int>Linux iproute2 rule index.
auto-redirectboolfalsetrue | falseLinux NFTables auto-redirect (faster than auto-route on hot paths).
auto-redirect-input-markuint320<uint32>fwmark on TUN-bound packets.
auto-redirect-output-markuint320<uint32>fwmark on TUN-egress packets.
auto-redirect-iproute2-fallback-rule-indexint0<int>Fallback rule index when auto-redirect can't install.
loopback-address[]netip.Addr[]<IP>Addresses treated as loopback.
strict-routeboolfalsetrue | falseBlock 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-natboolfalsetrue | falseEnable endpoint-independent NAT for UDP. Required by some games / VoIP apps.
udp-timeoutint64300<seconds>UDP idle timeout in seconds.
disable-icmp-forwardingboolfalsetrue | falseDrop ICMP packets at the TUN layer (mihomo-specific).
file-descriptorint0<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
recvmsgxboolfalsetrue | falseDarwin only — use the recvmsg_x syscall for batching.
sendmsgxboolfalsetrue | falseDarwin 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:

yaml
tun:
  enable: true
  dns-hijack:
    - any:53          # All UDP/53 traffic
    - tcp://any:53    # And TCP/53
    - 8.8.8.8:53      # Specific server only

This 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:

yaml
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/8

Linux NFTables auto-redirect:

yaml
tun:
  enable: true
  device: utun0
  stack: system
  dns-hijack: [any:53]
  auto-redirect: true
  auto-redirect-input-mark: 0x100
  auto-redirect-output-mark: 0x200

Android app split — proxy only specific apps:

yaml
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.gms

Notes

  • inet4-address is 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 explicit inet6-address field.
  • dns-hijack accepts a couple of special forms:
    • any:53 matches both TCP and UDP port 53.
    • Prefix with tcp:// or udp:// to scope.
    • Bare IP:port for specific upstream resolvers.
  • auto-route and auto-redirect are mutually exclusive. Pick one based on your kernel: NFTables-capable kernels prefer auto-redirect for performance.
  • The recvmsgx / sendmsgx flags are macOS-only optimizations that use the per-syscall batching variants. Enable them on macOS for throughput.
  • disable-icmp-forwarding is 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 in inbounds[] with snake_case names. See TUN — sing-box.

Source: config/config.go:268-321 · v1.19.27 (5184081)

Core Tutorial by Argsment