Compare commits

..

22 Commits

Author SHA1 Message Date
世界
2978c4aee1
Add proxy support for ICMP echo request 2025-08-25 22:21:46 +08:00
世界
0636a87db0
Fix resolve using resolved 2025-08-25 19:57:52 +08:00
世界
fb4de45bbe
documentation: Bump version 2025-08-25 19:57:45 +08:00
世界
f9c5da2e57
Fix wireguard crash 2025-08-25 19:57:45 +08:00
世界
438b1b383b
documentation: Update behavior of local DNS server on darwin 2025-08-25 19:57:41 +08:00
世界
8c0e899e37
Stop using DHCP on iOS and tvOS
We do not have the `com.apple.developer.networking.multicast` entitlement and are unable to obtain it for non-technical reasons.
2025-08-25 19:57:40 +08:00
世界
addc385f83
Remove use of ldflags -checklinkname=0 on darwin 2025-08-25 19:57:38 +08:00
世界
8a7cd246bc
Fix local DNS server on darwin
We mistakenly believed that `libresolv`'s `search` function worked correctly in NetworkExtension, but it seems only `getaddrinfo` does.

This commit changes the behavior of the `local` DNS server in NetworkExtension to prefer DHCP, falling back to `getaddrinfo` if DHCP servers are unavailable.

It's worth noting that `prefer_go` does not disable DHCP since it respects Dial Fields, but `getaddrinfo` does the opposite. The new behavior only applies to NetworkExtension, not to all scenarios (primarily command-line binaries) as it did previously.

In addition, this commit also improves the DHCP DNS server to use the same robust query logic as `local`.
2025-08-25 19:57:35 +08:00
世界
bcd0cd5d94
Fix legacy DNS config 2025-08-25 19:57:32 +08:00
世界
caf39fa141
Fix rule-set format 2025-08-25 19:57:30 +08:00
世界
a9f9ce92bb
documentation: Remove outdated icons 2025-08-25 19:57:27 +08:00
世界
06e588d9b8
documentation: Improve local DNS server 2025-08-25 19:57:27 +08:00
世界
5442e05bba
Use libresolv in local DNS server on darwin 2025-08-25 19:57:24 +08:00
世界
49bf5fac99
Use resolved in local DNS server if available 2025-08-25 19:57:21 +08:00
xchacha20-poly1305
b5ba2ed1f0
Fix rule set version 2025-08-25 19:57:17 +08:00
世界
f6bee821e3
documentation: Add preferred_by route rule item 2025-08-25 19:57:15 +08:00
世界
a514f203a3
Add preferred_by route rule item 2025-08-25 19:57:13 +08:00
世界
345341fc05
documentation: Add interface address rule items 2025-08-25 19:57:10 +08:00
世界
97113801e4
Add interface address rule items 2025-08-25 19:57:08 +08:00
neletor
c994065f74
Add support for ech retry configs 2025-08-25 19:57:08 +08:00
Zephyruso
3328a20a9b
Add /dns/flush-clash meta api 2025-08-25 19:57:08 +08:00
世界
031f25c1c1
Deprecate common/atomic 2025-08-25 19:49:12 +08:00
29 changed files with 136 additions and 71 deletions

View File

@ -3,6 +3,7 @@ package adapter
import ( import (
"context" "context"
"net/netip" "net/netip"
"time"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -28,7 +29,7 @@ type OutboundWithPreferredRoutes interface {
type DirectRouteOutbound interface { type DirectRouteOutbound interface {
Outbound Outbound
NewDirectRouteConnection(metadata InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) NewDirectRouteConnection(metadata InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error)
} }
type OutboundRegistry interface { type OutboundRegistry interface {

View File

@ -6,6 +6,7 @@ import (
"net" "net"
"net/http" "net/http"
"sync" "sync"
"time"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
@ -20,7 +21,7 @@ import (
type Router interface { type Router interface {
Lifecycle Lifecycle
ConnectionRouter ConnectionRouter
PreMatch(metadata InboundContext, context tun.DirectRouteContext) (tun.DirectRouteDestination, error) PreMatch(metadata InboundContext, context tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error)
ConnectionRouterEx ConnectionRouterEx
RuleSet(tag string) (RuleSet, bool) RuleSet(tag string) (RuleSet, bool)
NeedWIFIState() bool NeedWIFIState() bool

View File

@ -15,7 +15,6 @@ import (
"github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
@ -43,7 +42,7 @@ type DefaultDialer struct {
networkType []C.InterfaceType networkType []C.InterfaceType
fallbackNetworkType []C.InterfaceType fallbackNetworkType []C.InterfaceType
networkFallbackDelay time.Duration networkFallbackDelay time.Duration
networkLastFallback atomic.TypedValue[time.Time] networkLastFallback common.TypedValue[time.Time]
} }
func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) { func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) {
@ -318,8 +317,8 @@ func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksadd
} }
} }
func (d *DefaultDialer) DialerForICMPNetwork(network string) net.Dialer { func (d *DefaultDialer) DialerForICMPDestination(destination netip.Addr) net.Dialer {
if network == N.NetworkICMPv6 { if !destination.Is6() {
return dialerFromTCPDialer(d.dialer6) return dialerFromTCPDialer(d.dialer6)
} else { } else {
return dialerFromTCPDialer(d.dialer4) return dialerFromTCPDialer(d.dialer4)

View File

@ -8,10 +8,10 @@ import (
"net" "net"
"os" "os"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"

View File

@ -5,12 +5,12 @@ import (
"errors" "errors"
"os" "os"
"sync" "sync"
"sync/atomic"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/service/resolved" "github.com/sagernet/sing-box/service/resolved"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"

View File

@ -3,12 +3,12 @@ package trafficontrol
import ( import (
"runtime" "runtime"
"sync" "sync"
"sync/atomic"
"time" "time"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/clashapi/compatible" "github.com/sagernet/sing-box/experimental/clashapi/compatible"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/x/list" "github.com/sagernet/sing/common/x/list"

View File

@ -2,11 +2,11 @@ package trafficontrol
import ( import (
"net" "net"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"

View File

@ -7,11 +7,11 @@ import (
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"

4
go.mod
View File

@ -27,13 +27,13 @@ require (
github.com/sagernet/gomobile v0.1.8 github.com/sagernet/gomobile v0.1.8
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237
github.com/sagernet/quic-go v0.52.0-beta.1 github.com/sagernet/quic-go v0.52.0-beta.1
github.com/sagernet/sing v0.7.6-0.20250823024003-88f1880f43af github.com/sagernet/sing v0.7.6-0.20250825141840-811aa328e57b
github.com/sagernet/sing-mux v0.3.3 github.com/sagernet/sing-mux v0.3.3
github.com/sagernet/sing-quic v0.5.0 github.com/sagernet/sing-quic v0.5.0
github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250824024715-dd18aa2b8633 github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250825142028-0386fcb66a72
github.com/sagernet/sing-vmess v0.2.7 github.com/sagernet/sing-vmess v0.2.7
github.com/sagernet/smux v1.5.34-mod.2 github.com/sagernet/smux v1.5.34-mod.2
github.com/sagernet/tailscale v1.80.3-mod.6 github.com/sagernet/tailscale v1.80.3-mod.6

8
go.sum
View File

@ -167,8 +167,8 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs= github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.6-0.20250823024003-88f1880f43af h1:/1H30c/+j7Q9BBPuJuX6eHyzKpbGWrr7S/4DcdtNIfw= github.com/sagernet/sing v0.7.6-0.20250825141840-811aa328e57b h1:RCfo1Q6VDAXfumNupRyqTomKzDODhASswkxVCqM8l2M=
github.com/sagernet/sing v0.7.6-0.20250823024003-88f1880f43af/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.7.6-0.20250825141840-811aa328e57b/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
github.com/sagernet/sing-quic v0.5.0 h1:jNLIyVk24lFPvu8A4x+ZNEnZdI+Tg1rp7eCJ6v0Csak= github.com/sagernet/sing-quic v0.5.0 h1:jNLIyVk24lFPvu8A4x+ZNEnZdI+Tg1rp7eCJ6v0Csak=
@ -179,8 +179,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250824024715-dd18aa2b8633 h1:cqm3Gd253bpnQV5qQvvrFEcO0dzUrfsiOQRTtSFM8cs= github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250825142028-0386fcb66a72 h1:8UFMs1xVFIq+z+HVwe4NUjxqFfhbmomorH08SS1JjqE=
github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250824024715-dd18aa2b8633/go.mod h1:z1lkiAE5ex5gHBzh5+G9TFsyM9grOaSsRx33mVfWfVI= github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250825142028-0386fcb66a72/go.mod h1:1fyZW3WhK6rg0REkeJ2LIuK/v+Q7X/gQU/FyQMza7LM=
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=

View File

@ -62,7 +62,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
return nil, err return nil, err
} }
outbound := &Outbound{ outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMPv4, N.NetworkICMPv6}, options.DialerOptions), Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
ctx: ctx, ctx: ctx,
logger: logger, logger: logger,
//nolint:staticcheck //nolint:staticcheck
@ -151,9 +151,9 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
return conn, nil return conn, nil
} }
func (h *Outbound) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (h *Outbound) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
ctx := log.ContextWithNewID(h.ctx) ctx := log.ContextWithNewID(h.ctx)
destination, err := ping.ConnectDestination(ctx, h.logger, common.MustCast[*dialer.DefaultDialer](h.dialer).DialerForICMPNetwork(metadata.Network).Control, metadata.Destination.Addr, routeContext) destination, err := ping.ConnectDestination(ctx, h.logger, common.MustCast[*dialer.DefaultDialer](h.dialer).DialerForICMPDestination(metadata.Destination.Addr).Control, metadata.Destination.Addr, routeContext, timeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -10,7 +10,7 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/atomic" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
@ -37,7 +37,7 @@ type Selector struct {
tags []string tags []string
defaultTag string defaultTag string
outbounds map[string]adapter.Outbound outbounds map[string]adapter.Outbound
selected atomic.TypedValue[adapter.Outbound] selected common.TypedValue[adapter.Outbound]
interruptGroup *interrupt.Group interruptGroup *interrupt.Group
interruptExternalConnections bool interruptExternalConnections bool
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"net" "net"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@ -14,7 +15,6 @@ import (
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/batch" "github.com/sagernet/sing/common/batch"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
@ -192,7 +192,7 @@ type URLTestGroup struct {
ticker *time.Ticker ticker *time.Ticker
close chan struct{} close chan struct{}
started bool started bool
lastActive atomic.TypedValue[time.Time] lastActive common.TypedValue[time.Time]
} }
func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManager, logger log.Logger, outbounds []adapter.Outbound, link string, interval time.Duration, tolerance uint16, idleTimeout time.Duration, interruptExternalConnections bool) (*URLTestGroup, error) { func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManager, logger log.Logger, outbounds []adapter.Outbound, link string, interval time.Duration, tolerance uint16, idleTimeout time.Duration, interruptExternalConnections bool) (*URLTestGroup, error) {

View File

@ -13,6 +13,7 @@ import (
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
"sync/atomic"
"syscall" "syscall"
"time" "time"
@ -30,10 +31,10 @@ import (
"github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/route/rule"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing-tun/ping" "github.com/sagernet/sing-tun/ping"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@ -87,7 +88,7 @@ type Endpoint struct {
cfg *wgcfg.Config cfg *wgcfg.Config
dnsCfg *tsDNS.Config dnsCfg *tsDNS.Config
routeDomains atomic.TypedValue[map[string]bool] routeDomains common.TypedValue[map[string]bool]
routePrefixes atomic.Pointer[netipx.IPSet] routePrefixes atomic.Pointer[netipx.IPSet]
acceptRoutes bool acceptRoutes bool
@ -181,7 +182,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
}, },
} }
return &Endpoint{ return &Endpoint{
Adapter: endpoint.NewAdapter(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMPv4, N.NetworkICMPv6}, nil), Adapter: endpoint.NewAdapter(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
ctx: ctx, ctx: ctx,
router: router, router: router,
logger: logger, logger: logger,
@ -272,7 +273,7 @@ func (t *Endpoint) Start(stage adapter.StartStage) error {
if err != nil { if err != nil {
return E.Cause(err, "update prefs") return E.Cause(err, "update prefs")
} }
t.filter = atomic.PointerForm(localBackend.ExportFilter()) t.filter = localBackend.ExportFilter()
go t.watchState() go t.watchState()
return nil return nil
} }
@ -424,7 +425,7 @@ func (t *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
return udpConn, nil return udpConn, nil
} }
func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
tsFilter := t.filter.Load() tsFilter := t.filter.Load()
if tsFilter != nil { if tsFilter != nil {
var ipProto ipproto.Proto var ipProto ipproto.Proto
@ -433,6 +434,12 @@ func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destina
ipProto = ipproto.TCP ipProto = ipproto.TCP
case N.NetworkUDP: case N.NetworkUDP:
ipProto = ipproto.UDP ipProto = ipproto.UDP
case N.NetworkICMP:
if !destination.IsIPv6() {
ipProto = ipproto.ICMPv4
} else {
ipProto = ipproto.ICMPv6
}
} }
response := tsFilter.Check(source.Addr, destination.Addr, destination.Port, ipProto) response := tsFilter.Check(source.Addr, destination.Addr, destination.Port, ipProto)
switch response { switch response {
@ -442,13 +449,26 @@ func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destina
return nil, tun.ErrDrop return nil, tun.ErrDrop
} }
} }
return t.router.PreMatch(adapter.InboundContext{ var ipVersion uint8
if !destination.IsIPv6() {
ipVersion = 4
} else {
ipVersion = 6
}
routeDestination, err := t.router.PreMatch(adapter.InboundContext{
Inbound: t.Tag(), Inbound: t.Tag(),
InboundType: t.Type(), InboundType: t.Type(),
IPVersion: ipVersion,
Network: network, Network: network,
Source: source, Source: source,
Destination: destination, Destination: destination,
}, routeContext) }, routeContext, timeout)
if err != nil {
if !rule.IsRejected(err) {
t.logger.Warn(E.Cause(err, "link ", network, " connection from ", source.AddrString(), " to ", destination.AddrString()))
}
}
return routeDestination, err
} }
func (t *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { func (t *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
@ -491,7 +511,7 @@ func (t *Endpoint) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
t.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose) t.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose)
} }
func (t *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (t *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
inet4Address, inet6Address := t.server.TailscaleIPs() inet4Address, inet6Address := t.server.TailscaleIPs()
if metadata.Destination.Addr.Is4() && !inet4Address.IsValid() || metadata.Destination.Addr.Is6() && !inet6Address.IsValid() { if metadata.Destination.Addr.Is4() && !inet4Address.IsValid() || metadata.Destination.Addr.Is6() && !inet6Address.IsValid() {
return nil, E.New("Tailscale is not ready yet") return nil, E.New("Tailscale is not ready yet")
@ -503,6 +523,7 @@ func (t *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, rou
routeContext, routeContext,
t.stack, t.stack,
inet4Address, inet6Address, inet4Address, inet6Address,
timeout,
) )
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -8,7 +8,6 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@ -19,6 +18,7 @@ import (
"github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/route/rule"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@ -455,18 +455,25 @@ func (t *Inbound) Close() error {
) )
} }
func (t *Inbound) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (t *Inbound) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
var ipVersion uint8
if !destination.IsIPv6() {
ipVersion = 4
} else {
ipVersion = 6
}
routeDestination, err := t.router.PreMatch(adapter.InboundContext{ routeDestination, err := t.router.PreMatch(adapter.InboundContext{
Inbound: t.tag, Inbound: t.tag,
InboundType: C.TypeTun, InboundType: C.TypeTun,
IPVersion: ipVersion,
Network: network, Network: network,
Source: source, Source: source,
Destination: destination, Destination: destination,
InboundOptions: t.inboundOptions, InboundOptions: t.inboundOptions,
}, routeContext) }, routeContext, timeout)
if err != nil { if err != nil {
if !E.IsMulti(err, tun.ErrDrop, syscall.ECONNREFUSED) { if !rule.IsRejected(err) {
t.logger.Warn(E.Cause(err, "link ", network, " connection from ", source, " to ", destination)) t.logger.Warn(E.Cause(err, "link ", network, " connection from ", source.AddrString(), " to ", destination.AddrString()))
} }
} }
return routeDestination, err return routeDestination, err

View File

@ -12,6 +12,7 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/route/rule"
"github.com/sagernet/sing-box/transport/wireguard" "github.com/sagernet/sing-box/transport/wireguard"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
@ -41,7 +42,7 @@ type Endpoint struct {
func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardEndpointOptions) (adapter.Endpoint, error) { func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardEndpointOptions) (adapter.Endpoint, error) {
ep := &Endpoint{ ep := &Endpoint{
Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMPv4, N.NetworkICMPv6}, options.DialerOptions), Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
ctx: ctx, ctx: ctx,
router: router, router: router,
dnsRouter: service.FromContext[adapter.DNSRouter](ctx), dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
@ -125,14 +126,27 @@ func (w *Endpoint) Close() error {
return w.endpoint.Close() return w.endpoint.Close()
} }
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, context tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
return w.router.PreMatch(adapter.InboundContext{ var ipVersion uint8
if !destination.IsIPv6() {
ipVersion = 4
} else {
ipVersion = 6
}
routeDestination, err := w.router.PreMatch(adapter.InboundContext{
Inbound: w.Tag(), Inbound: w.Tag(),
InboundType: w.Type(), InboundType: w.Type(),
IPVersion: ipVersion,
Network: network, Network: network,
Source: source, Source: source,
Destination: destination, Destination: destination,
}, context) }, routeContext, timeout)
if err != nil {
if !rule.IsRejected(err) {
w.logger.Warn(E.Cause(err, "link ", network, " connection from ", source.AddrString(), " to ", destination.AddrString()))
}
}
return routeDestination, err
} }
func (w *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) { func (w *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
@ -222,11 +236,6 @@ func (w *Endpoint) PreferredAddress(address netip.Addr) bool {
return w.endpoint.Lookup(address) != nil return w.endpoint.Lookup(address) != nil
} }
func (w *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (w *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
destination, err := w.endpoint.NewDirectRouteConnection(metadata, routeContext) return w.endpoint.NewDirectRouteConnection(metadata, routeContext, timeout)
if err != nil {
return nil, err
}
w.logger.Info("linked ", metadata.Network, " connection to ", metadata.Destination.AddrString())
return destination, nil
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"net" "net"
"net/netip" "net/netip"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/outbound" "github.com/sagernet/sing-box/adapter/outbound"
@ -13,6 +14,7 @@ import (
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/wireguard" "github.com/sagernet/sing-box/transport/wireguard"
tun "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
@ -42,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
deprecated.Report(ctx, deprecated.OptionWireGuardGSO) deprecated.Report(ctx, deprecated.OptionWireGuardGSO)
} }
outbound := &Outbound{ outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), Adapter: outbound.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
ctx: ctx, ctx: ctx,
dnsRouter: service.FromContext[adapter.DNSRouter](ctx), dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
logger: logger, logger: logger,
@ -168,3 +170,7 @@ func (o *Outbound) PreferredDomain(domain string) bool {
func (o *Outbound) PreferredAddress(address netip.Addr) bool { func (o *Outbound) PreferredAddress(address netip.Addr) bool {
return o.endpoint.Lookup(address) != nil return o.endpoint.Lookup(address) != nil
} }
func (o *Outbound) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
return o.endpoint.NewDirectRouteConnection(metadata, routeContext, timeout)
}

View File

@ -19,7 +19,6 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
@ -37,7 +36,7 @@ var _ adapter.NetworkManager = (*NetworkManager)(nil)
type NetworkManager struct { type NetworkManager struct {
logger logger.ContextLogger logger logger.ContextLogger
interfaceFinder *control.DefaultInterfaceFinder interfaceFinder *control.DefaultInterfaceFinder
networkInterfaces atomic.TypedValue[[]adapter.NetworkInterface] networkInterfaces common.TypedValue[[]adapter.NetworkInterface]
autoDetectInterface bool autoDetectInterface bool
defaultOptions adapter.NetworkOptions defaultOptions adapter.NetworkOptions

View File

@ -259,7 +259,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
return nil return nil
} }
func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
selectedRule, _, _, _, err := r.matchRule(r.ctx, &metadata, true, nil, nil) selectedRule, _, _, _, err := r.matchRule(r.ctx, &metadata, true, nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -279,17 +279,17 @@ func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.Dire
if !common.Contains(outbound.Network(), metadata.Network) { if !common.Contains(outbound.Network(), metadata.Network) {
return nil, E.New(metadata.Network, " is not supported by outbound: ", action.Outbound) return nil, E.New(metadata.Network, " is not supported by outbound: ", action.Outbound)
} }
return outbound.(adapter.DirectRouteOutbound).NewDirectRouteConnection(metadata, routeContext) return outbound.(adapter.DirectRouteOutbound).NewDirectRouteConnection(metadata, routeContext, timeout)
} }
} }
if metadata.Network != N.NetworkICMPv4 && metadata.Network != N.NetworkICMPv6 { if selectedRule != nil || metadata.Network != N.NetworkICMP {
return nil, nil return nil, nil
} }
defaultOutbound := r.outbound.Default() defaultOutbound := r.outbound.Default()
if !common.Contains(defaultOutbound.Network(), metadata.Network) { if !common.Contains(defaultOutbound.Network(), metadata.Network) {
return nil, E.New(metadata.Network, " is not supported by default outbound: ", defaultOutbound.Tag()) return nil, E.New(metadata.Network, " is not supported by default outbound: ", defaultOutbound.Tag())
} }
return defaultOutbound.(adapter.DirectRouteOutbound).NewDirectRouteConnection(metadata, routeContext) return defaultOutbound.(adapter.DirectRouteOutbound).NewDirectRouteConnection(metadata, routeContext, timeout)
} }
func (r *Router) matchRule( func (r *Router) matchRule(

View File

@ -6,6 +6,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"github.com/sagernet/fswatch" "github.com/sagernet/fswatch"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@ -13,7 +14,6 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"

View File

@ -10,6 +10,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@ -17,7 +18,6 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"

View File

@ -5,8 +5,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"sync/atomic"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badjson"
"github.com/sagernet/sing/service/filemanager" "github.com/sagernet/sing/service/filemanager"

View File

@ -3,9 +3,9 @@ package ssmapi
import ( import (
"net" "net"
"sync" "sync"
"sync/atomic"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )

View File

@ -15,7 +15,6 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-quic" "github.com/sagernet/sing-quic"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
@ -30,7 +29,7 @@ type Client struct {
tlsConfig tls.Config tlsConfig tls.Config
quicConfig *quic.Config quicConfig *quic.Config
connAccess sync.Mutex connAccess sync.Mutex
conn atomic.TypedValue[quic.Connection] conn common.TypedValue[quic.Connection]
rawConn net.Conn rawConn net.Conn
} }

View File

@ -47,5 +47,5 @@ func NewDevice(options DeviceOptions) (Device, error) {
type NatDevice interface { type NatDevice interface {
Device Device
CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error)
} }

View File

@ -1,26 +1,36 @@
package wireguard package wireguard
import ( import (
"context"
"sync/atomic"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
"github.com/sagernet/sing-tun/ping" "github.com/sagernet/sing-tun/ping"
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/logger"
) )
var _ Device = (*natDeviceWrapper)(nil) var _ Device = (*natDeviceWrapper)(nil)
type natDeviceWrapper struct { type natDeviceWrapper struct {
Device Device
ctx context.Context
logger logger.ContextLogger
packetOutbound chan *buf.Buffer packetOutbound chan *buf.Buffer
rewriter *ping.Rewriter rewriter *ping.Rewriter
buffer [][]byte buffer [][]byte
} }
func NewNATDevice(upstream Device) NatDevice { func NewNATDevice(ctx context.Context, logger logger.ContextLogger, upstream Device) NatDevice {
wrapper := &natDeviceWrapper{ wrapper := &natDeviceWrapper{
Device: upstream, Device: upstream,
ctx: ctx,
logger: logger,
packetOutbound: make(chan *buf.Buffer, 256), packetOutbound: make(chan *buf.Buffer, 256),
rewriter: ping.NewRewriter(upstream.Inet4Address(), upstream.Inet6Address()), rewriter: ping.NewRewriter(ctx, logger, upstream.Inet4Address(), upstream.Inet6Address()),
} }
return wrapper return wrapper
} }
@ -57,13 +67,15 @@ func (d *natDeviceWrapper) Write(bufs [][]byte, offset int) (int, error) {
return 0, nil return 0, nil
} }
func (d *natDeviceWrapper) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (d *natDeviceWrapper) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
ctx := log.ContextWithNewID(d.ctx)
session := tun.DirectRouteSession{ session := tun.DirectRouteSession{
Source: metadata.Source.Addr, Source: metadata.Source.Addr,
Destination: metadata.Destination.Addr, Destination: metadata.Destination.Addr,
} }
d.rewriter.CreateSession(session, routeContext) d.rewriter.CreateSession(session, routeContext)
return &natDestination{d, session}, nil d.logger.InfoContext(ctx, "linked ", metadata.Network, " connection from ", metadata.Source.AddrString(), " to ", metadata.Destination.AddrString())
return &natDestination{device: d, session: session}, nil
} }
var _ tun.DirectRouteDestination = (*natDestination)(nil) var _ tun.DirectRouteDestination = (*natDestination)(nil)
@ -71,6 +83,7 @@ var _ tun.DirectRouteDestination = (*natDestination)(nil)
type natDestination struct { type natDestination struct {
device *natDeviceWrapper device *natDeviceWrapper
session tun.DirectRouteSession session tun.DirectRouteSession
closed atomic.Bool
} }
func (d *natDestination) WritePacket(buffer *buf.Buffer) error { func (d *natDestination) WritePacket(buffer *buf.Buffer) error {
@ -80,6 +93,11 @@ func (d *natDestination) WritePacket(buffer *buf.Buffer) error {
} }
func (d *natDestination) Close() error { func (d *natDestination) Close() error {
d.closed.Store(true)
d.device.rewriter.DeleteSession(d.session) d.device.rewriter.DeleteSession(d.session)
return nil return nil
} }
func (d *natDestination) IsClosed() bool {
return d.closed.Load()
}

View File

@ -7,6 +7,7 @@ import (
"net" "net"
"net/netip" "net/netip"
"os" "os"
"time"
"github.com/sagernet/gvisor/pkg/buffer" "github.com/sagernet/gvisor/pkg/buffer"
"github.com/sagernet/gvisor/pkg/tcpip" "github.com/sagernet/gvisor/pkg/tcpip"
@ -251,7 +252,7 @@ func (w *stackDevice) BatchSize() int {
return 1 return 1
} }
func (w *stackDevice) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (w *stackDevice) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
ctx := log.ContextWithNewID(w.ctx) ctx := log.ContextWithNewID(w.ctx)
destination, err := ping.ConnectGVisor( destination, err := ping.ConnectGVisor(
ctx, w.logger, ctx, w.logger,
@ -259,6 +260,7 @@ func (w *stackDevice) CreateDestination(metadata adapter.InboundContext, routeCo
routeContext, routeContext,
w.stack, w.stack,
w.inet4Address, w.inet6Address, w.inet4Address, w.inet6Address,
timeout,
) )
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -5,6 +5,7 @@ package wireguard
import ( import (
"context" "context"
"net/netip" "net/netip"
"time"
"github.com/sagernet/gvisor/pkg/buffer" "github.com/sagernet/gvisor/pkg/buffer"
"github.com/sagernet/gvisor/pkg/tcpip" "github.com/sagernet/gvisor/pkg/tcpip"
@ -159,7 +160,7 @@ func (w *systemStackDevice) writeStack(packet []byte) bool {
return true return true
} }
func (w *systemStackDevice) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (w *systemStackDevice) CreateDestination(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
ctx := log.ContextWithNewID(w.ctx) ctx := log.ContextWithNewID(w.ctx)
destination, err := ping.ConnectGVisor( destination, err := ping.ConnectGVisor(
ctx, w.logger, ctx, w.logger,
@ -167,6 +168,7 @@ func (w *systemStackDevice) CreateDestination(metadata adapter.InboundContext, r
routeContext, routeContext,
w.stack, w.stack,
w.inet4Address, w.inet6Address, w.inet4Address, w.inet6Address,
timeout,
) )
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -10,6 +10,7 @@ import (
"os" "os"
"reflect" "reflect"
"strings" "strings"
"time"
"unsafe" "unsafe"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@ -119,7 +120,7 @@ func NewEndpoint(options EndpointOptions) (*Endpoint, error) {
} }
natDevice, isNatDevice := tunDevice.(NatDevice) natDevice, isNatDevice := tunDevice.(NatDevice)
if !isNatDevice { if !isNatDevice {
natDevice = NewNATDevice(tunDevice) natDevice = NewNATDevice(options.Context, options.Logger, tunDevice)
} }
return &Endpoint{ return &Endpoint{
options: options, options: options,
@ -243,11 +244,11 @@ func (e *Endpoint) Lookup(address netip.Addr) *device.Peer {
return e.allowedIPs.Lookup(address.AsSlice()) return e.allowedIPs.Lookup(address.AsSlice())
} }
func (e *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) { func (e *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
if e.natDevice == nil { if e.natDevice == nil {
return nil, os.ErrInvalid return nil, os.ErrInvalid
} }
return e.natDevice.CreateDestination(metadata, routeContext) return e.natDevice.CreateDestination(metadata, routeContext, timeout)
} }
func (e *Endpoint) onPauseUpdated(event int) { func (e *Endpoint) onPauseUpdated(event int) {