From cf60f7656263dfdeaea5405b02243a36aa88f462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 20 Jun 2026 23:32:03 +0800 Subject: [PATCH] Fix Cloudflared edge discovery ignoring configured resolver --- go.mod | 2 +- go.sum | 4 +-- protocol/cloudflare/inbound.go | 30 ++++++++++------- protocol/cloudflare/resolver.go | 57 +++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 protocol/cloudflare/resolver.go diff --git a/go.mod b/go.mod index 8ff011615..fb00ea9f0 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 github.com/sagernet/sing v0.8.11-0.20260514110501-905ad103a4df - github.com/sagernet/sing-cloudflared v0.1.0 + github.com/sagernet/sing-cloudflared v0.1.1-0.20260620151903-a1d6358fe953 github.com/sagernet/sing-mux v0.3.5 github.com/sagernet/sing-quic v0.6.2-0.20260525051024-9467ede27fb7 github.com/sagernet/sing-shadowsocks v0.2.8 diff --git a/go.sum b/go.sum index 3bc39f27c..7ff96cf04 100644 --- a/go.sum +++ b/go.sum @@ -254,8 +254,8 @@ github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgj github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= github.com/sagernet/sing v0.8.11-0.20260514110501-905ad103a4df h1:zSDw1g1JhIEqE/XPC3hW1wMdFPzbVgVJZiV86FAJoNQ= github.com/sagernet/sing v0.8.11-0.20260514110501-905ad103a4df/go.mod h1:olXxWQNqRW/l2Q6JI3b2Qmz8iQnIFlOeeH8bx6JhgUA= -github.com/sagernet/sing-cloudflared v0.1.0 h1:to+2fcCx8zu4X/DirRw9Ihc+FrEZ7oEyIqeCoJiwIpw= -github.com/sagernet/sing-cloudflared v0.1.0/go.mod h1:bH2NKX+NpDTY1Zkxfboxw6MXB/ZywaNLmrDJYgKMJ2Y= +github.com/sagernet/sing-cloudflared v0.1.1-0.20260620151903-a1d6358fe953 h1:bqZWzc7mVO+V6Z07PAwav1TnlAlNltr/e1J2z8sZn4o= +github.com/sagernet/sing-cloudflared v0.1.1-0.20260620151903-a1d6358fe953/go.mod h1:bH2NKX+NpDTY1Zkxfboxw6MXB/ZywaNLmrDJYgKMJ2Y= github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI= github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-quic v0.6.2-0.20260525051024-9467ede27fb7 h1:hFLPJ21uNZSbRnzhOKz4Zv0b4F93mpDorWyN93BeRcM= diff --git a/protocol/cloudflare/inbound.go b/protocol/cloudflare/inbound.go index f445ab956..2ad3fb296 100644 --- a/protocol/cloudflare/inbound.go +++ b/protocol/cloudflare/inbound.go @@ -9,18 +9,19 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter/inbound" - boxDialer "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/dialer" 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" - cloudflared "github.com/sagernet/sing-cloudflared" - tun "github.com/sagernet/sing-tun" + "github.com/sagernet/sing-cloudflared" + "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/pipe" + "github.com/sagernet/sing/service" ) func RegisterInbound(registry *inbound.Registry) { @@ -28,28 +29,35 @@ func RegisterInbound(registry *inbound.Registry) { } func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CloudflaredInboundOptions) (adapter.Inbound, error) { - controlDialer, err := boxDialer.NewWithOptions(boxDialer.Options{ - Context: ctx, - Options: options.ControlDialer, - RemoteIsDomain: true, + controlDialer, err := dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.ControlDialer, + RemoteIsDomain: true, + ResolverOnDetour: true, }) if err != nil { return nil, E.Cause(err, "build cloudflared control dialer") } - tunnelDialer, err := boxDialer.NewWithOptions(boxDialer.Options{ - Context: ctx, - Options: options.TunnelDialer, - RemoteIsDomain: true, + tunnelDialer, err := dialer.NewWithOptions(dialer.Options{ + Context: ctx, + Options: options.TunnelDialer, + RemoteIsDomain: true, + ResolverOnDetour: true, }) if err != nil { return nil, E.Cause(err, "build cloudflared tunnel dialer") } + dnsRouter := service.FromContext[adapter.DNSRouter](ctx) + controlResolver := newRouterResolver(dnsRouter, controlDialer.(dialer.ResolveDialer).QueryOptions()) + tunnelResolver := newRouterResolver(dnsRouter, tunnelDialer.(dialer.ResolveDialer).QueryOptions()) service, err := cloudflared.NewService(cloudflared.ServiceOptions{ Logger: logger, ConnectionDialer: &routerDialer{router: router, tag: tag}, ControlDialer: controlDialer, TunnelDialer: tunnelDialer, + ControlResolver: controlResolver, + TunnelResolver: tunnelResolver, ICMPHandler: &icmpRouterHandler{router: router, logger: logger, tag: tag}, ConnContext: func(connCtx context.Context) context.Context { return adapter.WithContext(connCtx, &adapter.InboundContext{ diff --git a/protocol/cloudflare/resolver.go b/protocol/cloudflare/resolver.go new file mode 100644 index 000000000..7253d030d --- /dev/null +++ b/protocol/cloudflare/resolver.go @@ -0,0 +1,57 @@ +//go:build with_cloudflared + +package cloudflare + +import ( + "context" + "net" + "net/netip" + "sort" + "strings" + + "github.com/sagernet/sing-box/adapter" + + mDNS "github.com/miekg/dns" +) + +type routerResolver struct { + dnsRouter adapter.DNSRouter + queryOptions adapter.DNSQueryOptions +} + +func newRouterResolver(dnsRouter adapter.DNSRouter, queryOptions adapter.DNSQueryOptions) *routerResolver { + return &routerResolver{dnsRouter: dnsRouter, queryOptions: queryOptions} +} + +func (r *routerResolver) LookupNetIP(ctx context.Context, host string) ([]netip.Addr, error) { + return r.dnsRouter.Lookup(ctx, strings.TrimSuffix(host, "."), r.queryOptions) +} + +func (r *routerResolver) LookupSRV(ctx context.Context, service, proto, name string) ([]*net.SRV, error) { + message := &mDNS.Msg{} + message.SetQuestion(mDNS.Fqdn("_"+service+"._"+proto+"."+name), mDNS.TypeSRV) + response, err := r.dnsRouter.Exchange(ctx, message, r.queryOptions) + if err != nil { + return nil, err + } + var records []*net.SRV + for _, answer := range response.Answer { + record, isSRV := answer.(*mDNS.SRV) + if !isSRV { + continue + } + records = append(records, &net.SRV{ + Target: record.Target, + Port: record.Port, + Priority: record.Priority, + Weight: record.Weight, + }) + } + sort.SliceStable(records, func(i, j int) bool { + if records[i].Priority != records[j].Priority { + return records[i].Priority < records[j].Priority + } + return records[i].Weight > records[j].Weight + }) + return records, nil +}