2024-11-02 00:39:02 +08:00
package tun
2022-07-09 19:18:37 +08:00
import (
"context"
"net"
2024-06-07 15:55:21 +08:00
"net/netip"
"os"
"runtime"
2026-07-06 23:40:48 +08:00
"slices"
2022-07-09 19:18:37 +08:00
"strconv"
"strings"
2023-12-20 19:55:14 +08:00
"time"
2022-07-09 19:18:37 +08:00
"github.com/sagernet/sing-box/adapter"
2024-11-02 00:39:02 +08:00
"github.com/sagernet/sing-box/adapter/inbound"
2023-12-04 11:47:25 +08:00
"github.com/sagernet/sing-box/common/taskmonitor"
2022-07-09 19:18:37 +08:00
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
2022-07-11 18:44:59 +08:00
"github.com/sagernet/sing-tun"
2026-07-19 13:04:55 +08:00
"github.com/sagernet/sing-tun/gtcpip/header"
2022-07-13 19:01:20 +08:00
"github.com/sagernet/sing/common"
2022-07-09 19:18:37 +08:00
E "github.com/sagernet/sing/common/exceptions"
2024-11-18 18:55:34 +08:00
"github.com/sagernet/sing/common/json/badoption"
2022-07-09 19:18:37 +08:00
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
2022-08-15 00:25:49 +08:00
"github.com/sagernet/sing/common/ranges"
2024-06-07 15:55:21 +08:00
"github.com/sagernet/sing/common/x/list"
2024-11-02 00:39:02 +08:00
"github.com/sagernet/sing/service"
2024-06-07 15:55:21 +08:00
"go4.org/netipx"
2022-07-09 19:18:37 +08:00
)
2024-11-02 00:39:02 +08:00
func RegisterInbound ( registry * inbound . Registry ) {
inbound . Register [ option . TunInboundOptions ]( registry , C . TypeTun , NewInbound )
}
2022-07-09 19:18:37 +08:00
2024-11-02 00:39:02 +08:00
type Inbound struct {
2026-02-28 17:55:56 +08:00
tag string
ctx context . Context
router adapter . Router
networkManager adapter . NetworkManager
logger log . ContextLogger
2024-11-23 22:34:02 +08:00
tunOptions tun . Options
2024-10-21 23:38:34 +08:00
udpTimeout time . Duration
2026-07-16 21:35:01 +08:00
udpMapping tun . NATMapping
udpFiltering tun . NATFiltering
udpNATMax uint32
2026-05-02 18:36:58 +08:00
dnsHijackAddress [] netip . Addr
2024-06-07 15:55:21 +08:00
stack string
tunIf tun . Tun
tunStack tun . Stack
2025-10-07 15:40:11 +08:00
platformInterface adapter . PlatformInterface
2024-06-07 15:55:21 +08:00
platformOptions option . TunPlatformOptions
autoRedirect tun . AutoRedirect
routeRuleSet [] adapter . RuleSet
routeRuleSetCallback [] * list . Element [ adapter . RuleSetUpdateCallback ]
routeExcludeRuleSet [] adapter . RuleSet
routeExcludeRuleSetCallback [] * list . Element [ adapter . RuleSetUpdateCallback ]
routeAddressSet [] * netipx . IPSet
routeExcludeAddressSet [] * netipx . IPSet
2022-07-09 19:18:37 +08:00
}
2024-11-02 00:39:02 +08:00
func NewInbound ( ctx context . Context , router adapter . Router , logger log . ContextLogger , tag string , options option . TunInboundOptions ) ( adapter . Inbound , error ) {
2024-06-07 15:55:21 +08:00
//nolint:staticcheck
2026-02-28 17:55:56 +08:00
if len ( options . Inet4Address ) > 0 || len ( options . Inet6Address ) > 0 ||
len ( options . Inet4RouteAddress ) > 0 || len ( options . Inet6RouteAddress ) > 0 ||
len ( options . Inet4RouteExcludeAddress ) > 0 || len ( options . Inet6RouteExcludeAddress ) > 0 {
return nil , E . New ( "legacy tun address fields are deprecated in sing-box 1.10.0 and removed in sing-box 1.12.0" )
2024-06-07 15:55:21 +08:00
}
//nolint:staticcheck
2026-02-28 17:55:56 +08:00
if options . GSO {
return nil , E . New ( "GSO option in tun is deprecated in sing-box 1.11.0 and removed in sing-box 1.12.0" )
2024-06-07 15:55:21 +08:00
}
2026-03-21 17:09:34 +08:00
//nolint:staticcheck
if options . InboundOptions != ( option . InboundOptions {}) {
return nil , E . New ( "legacy inbound fields are deprecated in sing-box 1.11.0 and removed in sing-box 1.13.0, checkout migration: https://sing-box.sagernet.org/migration/#migrate-legacy-inbound-fields-to-rule-actions" )
}
2026-02-28 17:55:56 +08:00
address := options . Address
2024-06-07 15:55:21 +08:00
inet4Address := common . Filter ( address , func ( it netip . Prefix ) bool {
return it . Addr (). Is4 ()
})
inet6Address := common . Filter ( address , func ( it netip . Prefix ) bool {
return it . Addr (). Is6 ()
})
routeAddress := options . RouteAddress
inet4RouteAddress := common . Filter ( routeAddress , func ( it netip . Prefix ) bool {
return it . Addr (). Is4 ()
})
inet6RouteAddress := common . Filter ( routeAddress , func ( it netip . Prefix ) bool {
return it . Addr (). Is6 ()
})
routeExcludeAddress := options . RouteExcludeAddress
inet4RouteExcludeAddress := common . Filter ( routeExcludeAddress , func ( it netip . Prefix ) bool {
return it . Addr (). Is4 ()
})
inet6RouteExcludeAddress := common . Filter ( routeExcludeAddress , func ( it netip . Prefix ) bool {
return it . Addr (). Is6 ()
})
2025-10-07 15:40:11 +08:00
platformInterface := service . FromContext [ adapter . PlatformInterface ]( ctx )
2026-07-11 00:59:03 +08:00
if options . NetNs != "" && ! C . IsLinux {
return nil , E . New ( "`netns` is only supported on Linux" )
}
2022-07-10 09:15:01 +08:00
tunMTU := options . MTU
if tunMTU == 0 {
2025-07-02 19:22:23 +08:00
if platformInterface != nil && platformInterface . UnderNetworkExtension () {
2025-07-04 10:29:55 +08:00
// In Network Extension, when MTU exceeds 4064 (4096-UTUN_IF_HEADROOM_SIZE), the performance of tun will drop significantly, which may be a system bug.
tunMTU = 4064
2025-08-13 11:48:44 +08:00
} else if C . IsAndroid {
// Some Android devices report ENOBUFS when using MTU 65535
tunMTU = 9000
2025-07-02 19:22:23 +08:00
} else {
2025-07-12 14:47:27 +08:00
tunMTU = 65535
2025-07-02 19:22:23 +08:00
}
2022-07-10 09:15:01 +08:00
}
2026-07-06 14:26:32 +08:00
var enableGSO bool
if C . IsLinux && platformInterface == nil {
enableGSO = ( options . Stack == "gvisor" && tunMTU < 49152 )
}
2023-12-20 19:55:14 +08:00
var udpTimeout time . Duration
2022-07-26 19:21:56 +08:00
if options . UDPTimeout != 0 {
2023-12-20 19:55:14 +08:00
udpTimeout = time . Duration ( options . UDPTimeout )
2022-07-26 19:21:56 +08:00
} else {
2023-12-20 19:55:14 +08:00
udpTimeout = C . UDPTimeout
2022-07-26 19:21:56 +08:00
}
2024-06-07 15:55:21 +08:00
var err error
2022-08-15 00:25:49 +08:00
includeUID := uidToRange ( options . IncludeUID )
if len ( options . IncludeUIDRange ) > 0 {
includeUID , err = parseRange ( includeUID , options . IncludeUIDRange )
if err != nil {
return nil , E . Cause ( err , "parse include_uid_range" )
}
}
excludeUID := uidToRange ( options . ExcludeUID )
if len ( options . ExcludeUIDRange ) > 0 {
excludeUID , err = parseRange ( excludeUID , options . ExcludeUIDRange )
if err != nil {
return nil , E . Cause ( err , "parse exclude_uid_range" )
}
}
2024-06-07 15:55:21 +08:00
tableIndex := options . IPRoute2TableIndex
if tableIndex == 0 {
tableIndex = tun . DefaultIPRoute2TableIndex
}
ruleIndex := options . IPRoute2RuleIndex
if ruleIndex == 0 {
ruleIndex = tun . DefaultIPRoute2RuleIndex
}
2026-01-29 12:07:15 +08:00
autoRedirectFallbackRuleIndex := options . AutoRedirectFallbackRuleIndex
if autoRedirectFallbackRuleIndex == 0 {
autoRedirectFallbackRuleIndex = tun . DefaultIPRoute2AutoRedirectFallbackRuleIndex
}
2024-06-22 14:11:49 +08:00
inputMark := uint32 ( options . AutoRedirectInputMark )
2024-06-07 15:55:21 +08:00
if inputMark == 0 {
inputMark = tun . DefaultAutoRedirectInputMark
}
2024-06-22 14:11:49 +08:00
outputMark := uint32 ( options . AutoRedirectOutputMark )
2024-06-07 15:55:21 +08:00
if outputMark == 0 {
outputMark = tun . DefaultAutoRedirectOutputMark
}
2025-12-26 15:52:28 +08:00
resetMark := uint32 ( options . AutoRedirectResetMark )
if resetMark == 0 {
resetMark = tun . DefaultAutoRedirectResetMark
}
nfQueue := options . AutoRedirectNFQueue
if nfQueue == 0 {
nfQueue = tun . DefaultAutoRedirectNFQueue
}
2026-03-03 20:59:13 +08:00
var includeMACAddress [] net . HardwareAddr
for i , macString := range options . IncludeMACAddress {
mac , macErr := net . ParseMAC ( macString )
if macErr != nil {
return nil , E . Cause ( macErr , "parse include_mac_address[" , i , "]" )
}
includeMACAddress = append ( includeMACAddress , mac )
}
var excludeMACAddress [] net . HardwareAddr
for i , macString := range options . ExcludeMACAddress {
mac , macErr := net . ParseMAC ( macString )
if macErr != nil {
return nil , E . Cause ( macErr , "parse exclude_mac_address[" , i , "]" )
}
excludeMACAddress = append ( excludeMACAddress , mac )
}
2024-11-10 12:11:21 +08:00
networkManager := service . FromContext [ adapter . NetworkManager ]( ctx )
2026-07-06 14:26:32 +08:00
multiPendingPackets := C . IsDarwin && (( options . Stack == "gvisor" && tunMTU < 32768 ) || ( options . Stack != "gvisor" && tunMTU <= 9000 ))
2024-11-02 00:39:02 +08:00
inbound := & Inbound {
2022-08-15 00:25:49 +08:00
tag : tag ,
ctx : ctx ,
router : router ,
2024-11-10 12:11:21 +08:00
networkManager : networkManager ,
2022-08-15 00:25:49 +08:00
logger : logger ,
tunOptions : tun . Options {
2026-01-29 12:07:15 +08:00
Name : options . InterfaceName ,
2026-07-11 00:59:03 +08:00
NetNs : options . NetNs ,
2026-01-29 12:07:15 +08:00
MTU : tunMTU ,
GSO : enableGSO ,
Inet4Address : inet4Address ,
Inet6Address : inet6Address ,
2026-05-02 18:36:58 +08:00
DNSMode : options . DNSMode ,
DNSAddress : options . DNSAddress ,
2026-01-29 12:07:15 +08:00
AutoRoute : options . AutoRoute ,
IPRoute2TableIndex : tableIndex ,
IPRoute2RuleIndex : ruleIndex ,
IPRoute2AutoRedirectFallbackRuleIndex : autoRedirectFallbackRuleIndex ,
AutoRedirectInputMark : inputMark ,
AutoRedirectOutputMark : outputMark ,
AutoRedirectResetMark : resetMark ,
AutoRedirectNFQueue : nfQueue ,
ExcludeMPTCP : options . ExcludeMPTCP ,
Inet4LoopbackAddress : common . Filter ( options . LoopbackAddress , netip . Addr . Is4 ),
Inet6LoopbackAddress : common . Filter ( options . LoopbackAddress , netip . Addr . Is6 ),
StrictRoute : options . StrictRoute ,
IncludeInterface : options . IncludeInterface ,
ExcludeInterface : options . ExcludeInterface ,
Inet4RouteAddress : inet4RouteAddress ,
Inet6RouteAddress : inet6RouteAddress ,
Inet4RouteExcludeAddress : inet4RouteExcludeAddress ,
Inet6RouteExcludeAddress : inet6RouteExcludeAddress ,
IncludeUID : includeUID ,
ExcludeUID : excludeUID ,
IncludeAndroidUser : options . IncludeAndroidUser ,
IncludePackage : options . IncludePackage ,
ExcludePackage : options . ExcludePackage ,
2026-03-03 20:59:13 +08:00
IncludeMACAddress : includeMACAddress ,
ExcludeMACAddress : excludeMACAddress ,
2026-01-29 12:07:15 +08:00
InterfaceMonitor : networkManager . InterfaceMonitor (),
2026-07-09 22:13:03 +08:00
Logger : logger ,
2026-01-29 12:07:15 +08:00
EXP_MultiPendingPackets : multiPendingPackets ,
2022-08-15 00:25:49 +08:00
},
2024-11-23 22:34:02 +08:00
udpTimeout : udpTimeout ,
2026-07-16 21:35:01 +08:00
udpMapping : tun . NATMapping ( options . UDPMapping ),
udpFiltering : tun . NATFiltering ( options . UDPFiltering ),
udpNATMax : options . UDPNATMax ,
2024-11-23 22:34:02 +08:00
stack : options . Stack ,
2025-07-02 19:22:23 +08:00
platformInterface : platformInterface ,
2024-11-23 22:34:02 +08:00
platformOptions : common . PtrValueOrDefault ( options . Platform ),
2024-06-07 15:55:21 +08:00
}
2024-12-23 22:24:10 +08:00
for _ , routeAddressSet := range options . RouteAddressSet {
ruleSet , loaded := router . RuleSet ( routeAddressSet )
if ! loaded {
return nil , E . New ( "parse route_address_set: rule-set not found: " , routeAddressSet )
}
inbound . routeRuleSet = append ( inbound . routeRuleSet , ruleSet )
}
for _ , routeExcludeAddressSet := range options . RouteExcludeAddressSet {
ruleSet , loaded := router . RuleSet ( routeExcludeAddressSet )
if ! loaded {
return nil , E . New ( "parse route_exclude_address_set: rule-set not found: " , routeExcludeAddressSet )
}
inbound . routeExcludeRuleSet = append ( inbound . routeExcludeRuleSet , ruleSet )
}
2024-06-07 15:55:21 +08:00
if options . AutoRedirect {
if ! options . AutoRoute {
return nil , E . New ( "`auto_route` is required by `auto_redirect`" )
}
disableNFTables , dErr := strconv . ParseBool ( os . Getenv ( "DISABLE_NFTABLES" ))
inbound . autoRedirect , err = tun . NewAutoRedirect ( tun . AutoRedirectOptions {
TunOptions : & inbound . tunOptions ,
Context : ctx ,
2024-10-21 23:38:34 +08:00
Handler : ( * autoRedirectHandler )( inbound ),
2024-06-07 15:55:21 +08:00
Logger : logger ,
2024-11-10 12:11:21 +08:00
NetworkMonitor : networkManager . NetworkMonitor (),
InterfaceFinder : networkManager . InterfaceFinder (),
2024-06-07 15:55:21 +08:00
TableName : "sing-box" ,
DisableNFTables : dErr == nil && disableNFTables ,
RouteAddressSet : & inbound . routeAddressSet ,
RouteExcludeAddressSet : & inbound . routeExcludeAddressSet ,
})
if err != nil {
return nil , E . Cause ( err , "initialize auto-redirect" )
}
2025-04-02 13:44:39 +08:00
if ! C . IsAndroid {
2024-12-23 22:24:10 +08:00
inbound . tunOptions . AutoRedirectMarkMode = true
2026-07-11 00:59:03 +08:00
if options . NetNs == "" {
err = networkManager . RegisterAutoRedirectOutputMark ( inbound . tunOptions . AutoRedirectOutputMark )
if err != nil {
return nil , err
}
2024-06-07 15:55:21 +08:00
}
}
}
return inbound , nil
2022-07-09 19:18:37 +08:00
}
2024-11-18 18:55:34 +08:00
func uidToRange ( uidList badoption . Listable [ uint32 ]) [] ranges . Range [ uint32 ] {
2022-08-15 00:25:49 +08:00
return common . Map ( uidList , func ( uid uint32 ) ranges . Range [ uint32 ] {
return ranges . NewSingle ( uid )
})
}
func parseRange ( uidRanges [] ranges . Range [ uint32 ], rangeList [] string ) ([] ranges . Range [ uint32 ], error ) {
for _ , uidRange := range rangeList {
if ! strings . Contains ( uidRange , ":" ) {
return nil , E . New ( "missing ':' in range: " , uidRange )
}
subIndex := strings . Index ( uidRange , ":" )
if subIndex == 0 {
return nil , E . New ( "missing range start: " , uidRange )
} else if subIndex == len ( uidRange ) - 1 {
return nil , E . New ( "missing range end: " , uidRange )
}
var start , end uint64
var err error
2024-06-07 15:55:21 +08:00
start , err = strconv . ParseUint ( uidRange [: subIndex ], 0 , 32 )
2022-08-15 00:25:49 +08:00
if err != nil {
return nil , E . Cause ( err , "parse range start" )
}
2024-06-07 15:55:21 +08:00
end , err = strconv . ParseUint ( uidRange [ subIndex + 1 :], 0 , 32 )
2022-08-15 00:25:49 +08:00
if err != nil {
return nil , E . Cause ( err , "parse range end" )
}
uidRanges = append ( uidRanges , ranges . New ( uint32 ( start ), uint32 ( end )))
}
return uidRanges , nil
}
2024-11-02 00:39:02 +08:00
func ( t * Inbound ) Type () string {
2022-07-09 19:18:37 +08:00
return C . TypeTun
}
2024-11-02 00:39:02 +08:00
func ( t * Inbound ) Tag () string {
2022-07-09 19:18:37 +08:00
return t . tag
}
2024-11-21 18:10:41 +08:00
func ( t * Inbound ) Start ( stage adapter . StartStage ) error {
switch stage {
2026-05-02 18:36:58 +08:00
case adapter . StartStateInitialize :
if t . tunOptions . DNSModeOrDefault () != tun . DNSModeDisabled && len ( t . tunOptions . DNSAddress ) == 0 {
inet4DNSAddress , _ := t . tunOptions . Inet4DNSAddress ()
inet6DNSAddress , _ := t . tunOptions . Inet6DNSAddress ()
t . dnsHijackAddress = append ( inet4DNSAddress , inet6DNSAddress ... )
}
2024-11-21 18:10:41 +08:00
case adapter . StartStateStart :
2026-07-06 14:26:32 +08:00
if t . platformInterface == nil &&
(( C . IsLinux && ! t . tunOptions . GSO ) || ( C . IsDarwin && ! t . tunOptions . EXP_MultiPendingPackets )) {
2026-07-08 11:14:42 +08:00
outboundManager := service . FromContext [ adapter . OutboundManager ]( t . ctx )
2026-07-06 14:26:32 +08:00
endpointManager := service . FromContext [ adapter . EndpointManager ]( t . ctx )
2026-07-08 11:14:42 +08:00
for _ , outbound := range outboundManager . Outbounds () {
2026-07-14 13:08:48 +08:00
if _ , isFlowOutbound := outbound .( adapter . FlowOutbound ); isFlowOutbound && common . Contains ( outbound . Network (), N . NetworkTCP ) {
2026-07-08 11:14:42 +08:00
if C . IsLinux {
t . tunOptions . GSO = true
} else {
t . tunOptions . EXP_MultiPendingPackets = true
2026-07-06 14:26:32 +08:00
}
2026-07-08 11:14:42 +08:00
break
}
}
for _ , endpoint := range endpointManager . Endpoints () {
2026-07-14 13:08:48 +08:00
if _ , isFlowOutbound := endpoint .( adapter . FlowOutbound ); isFlowOutbound && common . Contains ( endpoint . Network (), N . NetworkTCP ) {
2026-07-08 11:14:42 +08:00
if C . IsLinux {
t . tunOptions . GSO = true
} else {
t . tunOptions . EXP_MultiPendingPackets = true
}
break
2026-07-06 14:26:32 +08:00
}
}
}
2024-11-21 18:10:41 +08:00
if C . IsAndroid && t . platformInterface == nil {
t . tunOptions . BuildAndroidRules ( t . networkManager . PackageManager ())
2024-06-07 15:55:21 +08:00
}
2024-11-21 18:10:41 +08:00
if t . tunOptions . Name == "" {
t . tunOptions . Name = tun . CalculateInterfaceName ( "" )
}
2026-07-11 00:59:03 +08:00
if t . tunOptions . NetNs != "" {
manager := service . FromContext [ adapter . NetworkNamespaceManager ]( t . ctx )
if manager != nil {
t . tunOptions . NetNs = manager . ResolvePath ( t . tunOptions . NetNs )
}
}
2026-07-13 19:12:05 +08:00
if t . platformInterface == nil || C . IsWindows {
2024-12-23 22:24:10 +08:00
for _ , routeRuleSet := range t . routeRuleSet {
ipSets := routeRuleSet . ExtractIPSet ()
if len ( ipSets ) == 0 {
t . logger . Warn ( "route_address_set: no destination IP CIDR rules found in rule-set: " , routeRuleSet . Name ())
}
2025-05-20 18:17:20 +08:00
routeRuleSet . IncRef ()
2024-12-23 22:24:10 +08:00
t . routeAddressSet = append ( t . routeAddressSet , ipSets ... )
2025-02-14 13:36:52 +08:00
if t . autoRedirect != nil {
t . routeRuleSetCallback = append ( t . routeRuleSetCallback , routeRuleSet . RegisterCallback ( t . updateRouteAddressSet ))
}
2024-12-23 22:24:10 +08:00
}
for _ , routeExcludeRuleSet := range t . routeExcludeRuleSet {
ipSets := routeExcludeRuleSet . ExtractIPSet ()
if len ( ipSets ) == 0 {
t . logger . Warn ( "route_address_set: no destination IP CIDR rules found in rule-set: " , routeExcludeRuleSet . Name ())
}
2025-05-20 18:17:20 +08:00
routeExcludeRuleSet . IncRef ()
2024-12-23 22:24:10 +08:00
t . routeExcludeAddressSet = append ( t . routeExcludeAddressSet , ipSets ... )
2025-02-14 13:36:52 +08:00
if t . autoRedirect != nil {
t . routeExcludeRuleSetCallback = append ( t . routeExcludeRuleSetCallback , routeExcludeRuleSet . RegisterCallback ( t . updateRouteAddressSet ))
}
2024-12-23 22:24:10 +08:00
}
}
2024-11-21 18:10:41 +08:00
var (
tunInterface tun . Tun
err error
)
monitor := taskmonitor . New ( t . logger , C . StartTimeout )
2024-12-23 22:24:10 +08:00
tunOptions := t . tunOptions
if t . autoRedirect == nil && !( runtime . GOOS == "android" && t . platformInterface != nil ) {
for _ , ipSet := range t . routeAddressSet {
for _ , prefix := range ipSet . Prefixes () {
if prefix . Addr (). Is4 () {
tunOptions . Inet4RouteAddress = append ( tunOptions . Inet4RouteAddress , prefix )
} else {
tunOptions . Inet6RouteAddress = append ( tunOptions . Inet6RouteAddress , prefix )
}
}
}
for _ , ipSet := range t . routeExcludeAddressSet {
for _ , prefix := range ipSet . Prefixes () {
if prefix . Addr (). Is4 () {
tunOptions . Inet4RouteExcludeAddress = append ( tunOptions . Inet4RouteExcludeAddress , prefix )
} else {
tunOptions . Inet6RouteExcludeAddress = append ( tunOptions . Inet6RouteExcludeAddress , prefix )
}
}
}
}
monitor . Start ( "open interface" )
2025-10-07 15:40:11 +08:00
if t . platformInterface != nil && t . platformInterface . UsePlatformInterface () {
tunInterface , err = t . platformInterface . OpenInterface ( & tunOptions , t . platformOptions )
2024-11-21 18:10:41 +08:00
} else {
2024-12-23 22:24:10 +08:00
tunInterface , err = tun . New ( tunOptions )
2024-06-07 15:55:21 +08:00
}
monitor . Finish ()
2024-12-23 22:24:10 +08:00
t . tunOptions . Name = tunOptions . Name
2024-06-07 15:55:21 +08:00
if err != nil {
2024-11-21 18:10:41 +08:00
return E . Cause ( err , "configure tun interface" )
2024-06-07 15:55:21 +08:00
}
2024-11-21 18:10:41 +08:00
t . logger . Trace ( "creating stack" )
t . tunIf = tunInterface
if t . platformInterface != nil {
2026-07-13 19:12:05 +08:00
err = t . platformInterface . ProcessPlatformOptions ( t . platformOptions )
if err != nil {
closeError := t . tunIf . Close ()
t . tunIf = nil
return E . Errors ( E . Cause ( err , "process platform options" ), closeError )
}
}
var includeAllNetworks bool
if t . platformInterface != nil && t . platformInterface . UnderNetworkExtension () {
2025-10-07 15:40:11 +08:00
includeAllNetworks = t . platformInterface . NetworkExtensionIncludeAllNetworks ()
2024-06-07 15:55:21 +08:00
}
2024-11-21 18:10:41 +08:00
tunStack , err := tun . NewStack ( t . stack , tun . StackOptions {
Context : t . ctx ,
Tun : tunInterface ,
TunOptions : t . tunOptions ,
UDPTimeout : t . udpTimeout ,
2026-06-01 17:51:02 +08:00
ICMPTimeout : C . ICMPTimeout ,
2026-07-16 21:35:01 +08:00
UDPMapping : t . udpMapping ,
UDPFiltering : t . udpFiltering ,
UDPNATMax : t . udpNATMax ,
2024-11-21 18:10:41 +08:00
Handler : t ,
Logger : t . logger ,
2026-07-13 19:12:05 +08:00
ForwarderBindInterface : C . IsDarwin ,
2024-11-21 18:10:41 +08:00
InterfaceFinder : t . networkManager . InterfaceFinder (),
IncludeAllNetworks : includeAllNetworks ,
})
if err != nil {
return err
}
t . tunStack = tunStack
t . logger . Info ( "started at " , t . tunOptions . Name )
case adapter . StartStatePostStart :
monitor := taskmonitor . New ( t . logger , C . StartTimeout )
monitor . Start ( "starting tun stack" )
err := t . tunStack . Start ()
monitor . Finish ()
if err != nil {
return E . Cause ( err , "starting tun stack" )
}
monitor . Start ( "starting tun interface" )
err = t . tunIf . Start ()
monitor . Finish ()
if err != nil {
return E . Cause ( err , "starting TUN interface" )
}
if t . autoRedirect != nil {
monitor . Start ( "initialize auto-redirect" )
err := t . autoRedirect . Start ()
monitor . Finish ()
if err != nil {
return E . Cause ( err , "auto-redirect" )
}
2024-06-07 15:55:21 +08:00
}
2024-12-23 22:24:10 +08:00
t . routeAddressSet = nil
t . routeExcludeAddressSet = nil
2024-06-07 15:55:21 +08:00
}
return nil
}
2024-11-02 00:39:02 +08:00
func ( t * Inbound ) updateRouteAddressSet ( it adapter . RuleSet ) {
2024-06-07 15:55:21 +08:00
t . routeAddressSet = common . FlatMap ( t . routeRuleSet , adapter . RuleSet . ExtractIPSet )
t . routeExcludeAddressSet = common . FlatMap ( t . routeExcludeRuleSet , adapter . RuleSet . ExtractIPSet )
2025-01-27 13:40:26 +08:00
t . autoRedirect . UpdateRouteAddressSet ()
2024-06-07 15:55:21 +08:00
t . routeAddressSet = nil
t . routeExcludeAddressSet = nil
}
2026-07-19 17:50:02 +08:00
func ( t * Inbound ) InterfaceUpdated () {
tunStack := t . tunStack
if tunStack != nil {
tunStack . ResetNetwork ()
}
}
2024-11-02 00:39:02 +08:00
func ( t * Inbound ) Close () error {
2022-07-13 19:01:20 +08:00
return common . Close (
t . tunStack ,
t . tunIf ,
2024-06-07 15:55:21 +08:00
t . autoRedirect ,
2022-07-09 19:18:37 +08:00
)
}
2026-07-06 23:40:48 +08:00
func ( t * Inbound ) JudgeFlow ( network uint8 , source netip . AddrPort , destination netip . AddrPort , firstPacket [] byte ) tun . FlowVerdict {
if slices . Contains ( t . dnsHijackAddress , destination . Addr ()) {
2026-07-19 13:04:55 +08:00
if network == uint8 ( header . UDPProtocolNumber ) {
return tun . FlowVerdict { Action : tun . ActionHijackDNS }
}
2026-07-06 23:40:48 +08:00
return tun . FlowVerdict { Action : tun . ActionAccept }
}
return adapter . JudgeFlow ( t . router , t . tag , C . TypeTun , network , source , destination , firstPacket )
2024-10-21 23:38:34 +08:00
}
2026-07-19 13:04:55 +08:00
func ( t * Inbound ) NewDNSPacket ( payload [] byte , source M . Socksaddr , destination M . Socksaddr , writer N . PacketWriter ) {
ctx := log . ContextWithNewID ( t . ctx )
var metadata adapter . InboundContext
metadata . Inbound = t . tag
metadata . InboundType = C . TypeTun
metadata . Network = N . NetworkUDP
metadata . Source = source
metadata . Destination = destination
metadata . Protocol = C . ProtocolDNS
t . logger . InfoContext ( ctx , "inbound DNS packet from " , source )
t . router . HijackDNSPacket ( ctx , payload , writer , metadata )
}
2024-11-02 00:39:02 +08:00
func ( t * Inbound ) NewConnectionEx ( ctx context . Context , conn net . Conn , source M . Socksaddr , destination M . Socksaddr , onClose N . CloseHandlerFunc ) {
2022-07-12 15:17:29 +08:00
ctx = log . ContextWithNewID ( ctx )
2022-07-09 19:18:37 +08:00
var metadata adapter . InboundContext
metadata . Inbound = t . tag
2022-07-19 22:16:49 +08:00
metadata . InboundType = C . TypeTun
2024-10-21 23:38:34 +08:00
metadata . Source = source
metadata . Destination = destination
2026-07-06 23:40:48 +08:00
if slices . Contains ( t . dnsHijackAddress , destination . Addr ) {
metadata . Protocol = C . ProtocolDNS
2026-05-02 18:36:58 +08:00
}
if metadata . Protocol == C . ProtocolDNS {
t . logger . InfoContext ( ctx , "inbound DNS connection from " , metadata . Source )
} else {
t . logger . InfoContext ( ctx , "inbound connection from " , metadata . Source )
t . logger . InfoContext ( ctx , "inbound connection to " , metadata . Destination )
}
2024-10-21 23:38:34 +08:00
t . router . RouteConnectionEx ( ctx , conn , metadata , onClose )
2022-07-09 19:18:37 +08:00
}
2024-11-02 00:39:02 +08:00
func ( t * Inbound ) NewPacketConnectionEx ( ctx context . Context , conn N . PacketConn , source M . Socksaddr , destination M . Socksaddr , onClose N . CloseHandlerFunc ) {
2022-07-12 15:17:29 +08:00
ctx = log . ContextWithNewID ( ctx )
2022-07-09 19:18:37 +08:00
var metadata adapter . InboundContext
metadata . Inbound = t . tag
2022-07-19 22:16:49 +08:00
metadata . InboundType = C . TypeTun
2024-10-21 23:38:34 +08:00
metadata . Source = source
metadata . Destination = destination
2026-05-02 18:36:58 +08:00
for _ , dnsHijackAddress := range t . dnsHijackAddress {
if destination . Addr == dnsHijackAddress {
metadata . Protocol = C . ProtocolDNS
}
}
if metadata . Protocol == C . ProtocolDNS {
t . logger . InfoContext ( ctx , "inbound DNS packet connection from " , metadata . Source )
} else {
t . logger . InfoContext ( ctx , "inbound packet connection from " , metadata . Source )
t . logger . InfoContext ( ctx , "inbound packet connection to " , metadata . Destination )
}
2024-10-21 23:38:34 +08:00
t . router . RoutePacketConnectionEx ( ctx , conn , metadata , onClose )
2022-07-09 19:18:37 +08:00
}
2024-11-02 00:39:02 +08:00
type autoRedirectHandler Inbound
2024-10-21 23:38:34 +08:00
2026-07-06 23:40:48 +08:00
func ( t * autoRedirectHandler ) JudgeFlow ( network uint8 , source netip . AddrPort , destination netip . AddrPort , firstPacket [] byte ) tun . FlowVerdict {
return ( * Inbound )( t ). JudgeFlow ( network , source , destination , firstPacket )
2025-12-26 15:52:28 +08:00
}
2024-10-21 23:38:34 +08:00
func ( t * autoRedirectHandler ) NewConnectionEx ( ctx context . Context , conn net . Conn , source M . Socksaddr , destination M . Socksaddr , onClose N . CloseHandlerFunc ) {
ctx = log . ContextWithNewID ( ctx )
var metadata adapter . InboundContext
metadata . Inbound = t . tag
metadata . InboundType = C . TypeTun
metadata . Source = source
metadata . Destination = destination
2026-05-02 18:36:58 +08:00
for _ , dnsHijackAddress := range t . dnsHijackAddress {
if destination . Addr == dnsHijackAddress {
metadata . Protocol = C . ProtocolDNS
}
}
if metadata . Protocol == C . ProtocolDNS {
t . logger . InfoContext ( ctx , "inbound redirect DNS connection from " , metadata . Source )
} else {
t . logger . InfoContext ( ctx , "inbound redirect connection from " , metadata . Source )
t . logger . InfoContext ( ctx , "inbound connection to " , metadata . Destination )
}
2024-10-21 23:38:34 +08:00
t . router . RouteConnectionEx ( ctx , conn , metadata , onClose )
2022-07-09 19:18:37 +08:00
}
2025-12-26 15:52:28 +08:00
func ( t * autoRedirectHandler ) NewPacketConnectionEx ( ctx context . Context , conn N . PacketConn , source M . Socksaddr , destination M . Socksaddr , onClose N . CloseHandlerFunc ) {
panic ( "unexcepted" )
}
2026-07-19 13:04:55 +08:00
func ( t * autoRedirectHandler ) NewDNSPacket ( payload [] byte , source M . Socksaddr , destination M . Socksaddr , writer N . PacketWriter ) {
( * Inbound )( t ). NewDNSPacket ( payload , source , destination , writer )
}