Compare commits

..

23 Commits

Author SHA1 Message Date
世界
3145f8c54c
Implement ping support for WireGuard and Tailscale 2025-08-24 11:24:14 +08:00
世界
29862d8cce
Implement full ping client for direct outbound 2025-08-23 16:52:16 +08:00
世界
c002b8321e
Add ping support for direct outbound 2025-08-22 14:22:35 +08:00
世界
1d72a6b30e
Fix resolve using resolved 2025-08-21 16:25:13 +08:00
世界
c54eb3381f
documentation: Bump version 2025-08-21 16:23:42 +08:00
世界
6ede2d9ea7
Fix wireguard crash 2025-08-21 16:23:42 +08:00
世界
30903e19fa
documentation: Update behavior of local DNS server on darwin 2025-08-21 16:23:42 +08:00
世界
211aea73df
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-21 16:23:42 +08:00
世界
0ed86db4ee
Remove use of ldflags -checklinkname=0 on darwin 2025-08-21 09:44:16 +08:00
世界
3de913c420
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-21 09:44:15 +08:00
世界
d35e71bee6
Fix legacy DNS config 2025-08-21 09:44:15 +08:00
世界
c79fc86c36
Fix rule-set format 2025-08-21 09:44:15 +08:00
世界
e398e01269
documentation: Remove outdated icons 2025-08-21 09:44:15 +08:00
世界
a6a34c1968
documentation: Improve local DNS server 2025-08-21 09:44:14 +08:00
世界
25b9ae17c4
Use libresolv in local DNS server on darwin 2025-08-21 09:44:14 +08:00
世界
354cfe9899
Use resolved in local DNS server if available 2025-08-21 09:44:13 +08:00
xchacha20-poly1305
ca6575b582
Fix rule set version 2025-08-21 09:44:13 +08:00
世界
897c18b3e0
documentation: Add preferred_by route rule item 2025-08-21 09:44:13 +08:00
世界
67d1ab760f
Add preferred_by route rule item 2025-08-21 09:44:13 +08:00
世界
1d91ec5c50
documentation: Add interface address rule items 2025-08-21 09:44:12 +08:00
世界
884144c522
Add interface address rule items 2025-08-21 09:44:12 +08:00
neletor
2413c7caef
Add support for ech retry configs 2025-08-21 09:44:12 +08:00
Zephyruso
d53947be2a
Add /dns/flush-clash meta api 2025-08-21 09:44:12 +08:00
29 changed files with 71 additions and 136 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,11 +7,11 @@ import (
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
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/gvisor v0.0.0-20250822052253-5558536cf237
github.com/sagernet/quic-go v0.52.0-beta.1
github.com/sagernet/sing v0.7.6-0.20250825141840-811aa328e57b
github.com/sagernet/sing v0.7.6-0.20250823024003-88f1880f43af
github.com/sagernet/sing-mux v0.3.3
github.com/sagernet/sing-quic v0.5.0
github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250825142028-0386fcb66a72
github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250824024715-dd18aa2b8633
github.com/sagernet/sing-vmess v0.2.7
github.com/sagernet/smux v1.5.34-mod.2
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/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.6-0.20250825141840-811aa328e57b h1:RCfo1Q6VDAXfumNupRyqTomKzDODhASswkxVCqM8l2M=
github.com/sagernet/sing v0.7.6-0.20250825141840-811aa328e57b/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.20250823024003-88f1880f43af/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/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
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-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-tun v0.7.0-beta.1.0.20250825142028-0386fcb66a72 h1:8UFMs1xVFIq+z+HVwe4NUjxqFfhbmomorH08SS1JjqE=
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-tun v0.7.0-beta.1.0.20250824024715-dd18aa2b8633 h1:cqm3Gd253bpnQV5qQvvrFEcO0dzUrfsiOQRTtSFM8cs=
github.com/sagernet/sing-tun v0.7.0-beta.1.0.20250824024715-dd18aa2b8633/go.mod h1:z1lkiAE5ex5gHBzh5+G9TFsyM9grOaSsRx33mVfWfVI=
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/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
}
outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMPv4, N.NetworkICMPv6}, options.DialerOptions),
ctx: ctx,
logger: logger,
//nolint:staticcheck
@ -151,9 +151,9 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
return conn, nil
}
func (h *Outbound) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
func (h *Outbound) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext) (tun.DirectRouteDestination, error) {
ctx := log.ContextWithNewID(h.ctx)
destination, err := ping.ConnectDestination(ctx, h.logger, common.MustCast[*dialer.DefaultDialer](h.dialer).DialerForICMPDestination(metadata.Destination.Addr).Control, metadata.Destination.Addr, routeContext, timeout)
destination, err := ping.ConnectDestination(ctx, h.logger, common.MustCast[*dialer.DefaultDialer](h.dialer).DialerForICMPNetwork(metadata.Network).Control, metadata.Destination.Addr, routeContext)
if err != nil {
return nil, err
}

View File

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

View File

@ -4,7 +4,6 @@ import (
"context"
"net"
"sync"
"sync/atomic"
"time"
"github.com/sagernet/sing-box/adapter"
@ -15,6 +14,7 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/batch"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
@ -192,7 +192,7 @@ type URLTestGroup struct {
ticker *time.Ticker
close chan struct{}
started bool
lastActive common.TypedValue[time.Time]
lastActive atomic.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) {

View File

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

View File

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

View File

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

View File

@ -4,7 +4,6 @@ import (
"context"
"net"
"net/netip"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/outbound"
@ -14,7 +13,6 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/wireguard"
tun "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
@ -44,7 +42,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
deprecated.Report(ctx, deprecated.OptionWireGuardGSO)
}
outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeWireGuard, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
ctx: ctx,
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
logger: logger,
@ -170,7 +168,3 @@ func (o *Outbound) PreferredDomain(domain string) bool {
func (o *Outbound) PreferredAddress(address netip.Addr) bool {
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,6 +19,7 @@ import (
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
@ -36,7 +37,7 @@ var _ adapter.NetworkManager = (*NetworkManager)(nil)
type NetworkManager struct {
logger logger.ContextLogger
interfaceFinder *control.DefaultInterfaceFinder
networkInterfaces common.TypedValue[[]adapter.NetworkInterface]
networkInterfaces atomic.TypedValue[[]adapter.NetworkInterface]
autoDetectInterface bool
defaultOptions adapter.NetworkOptions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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