Skip to content

Commit 41c84bf

Browse files
committed
Export dialer
1 parent 0a3e81c commit 41c84bf

File tree

13 files changed

+79
-19
lines changed

13 files changed

+79
-19
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ require (
4242
github.com/prometheus/common v0.55.0
4343
github.com/safchain/ethtool v0.3.0
4444
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3
45+
github.com/sagernet/sing v0.6.1
4546
github.com/sagernet/wireguard-go v0.0.1-beta.4
4647
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e
4748
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4
@@ -72,7 +73,6 @@ require (
7273
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
7374
github.com/google/go-cmp v0.6.0 // indirect
7475
github.com/gorilla/securecookie v1.1.2 // indirect
75-
github.com/sagernet/sing v0.5.1 // indirect
7676
github.com/vishvananda/netns v0.0.4 // indirect
7777
go.uber.org/goleak v1.3.0 // indirect
7878
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3 h1:RxEz7LhPNiF/gX/
124124
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3/go.mod h1:ehZwnT2UpmOWAHFL48XdBhnd4Qu4hN2O3Ji0us3ZHMw=
125125
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
126126
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
127+
github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA=
128+
github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
127129
github.com/sagernet/wireguard-go v0.0.1-beta.4 h1:8uyM5fxfEXdu4RH05uOK+v25i3lTNdCYMPSAUJ14FnI=
128130
github.com/sagernet/wireguard-go v0.0.1-beta.4/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
129131
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=

ipn/ipnlocal/local.go

+1
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
492492
captiveCtx: captiveCtx,
493493
captiveCancel: nil, // so that we start checkCaptivePortalLoop when Running
494494
needsCaptiveDetection: make(chan bool),
495+
lookupHook: lookupHook,
495496
}
496497
mConn.SetNetInfoCallback(b.setNetInfo)
497498

ipn/ipnserver/server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) {
194194
defer onDone()
195195

196196
if strings.HasPrefix(r.URL.Path, "/localapi/") {
197-
lah := localapi.NewHandler(lb, s.logf, s.backendLogID)
197+
lah := localapi.NewHandler(lb, s.logf, s.backendLogID, s.netMon.Dialer())
198198
if actor, ok := ci.(*actor); ok {
199199
lah.PermitRead, lah.PermitWrite = actor.Permissions(lb.OperatorUserID())
200200
lah.PermitCert = actor.CanFetchCerts()

ipn/localapi/localapi.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"encoding/json"
1414
"errors"
1515
"fmt"
16+
N "github.com/sagernet/sing/common/network"
1617
"io"
1718
"maps"
1819
"mime"
@@ -171,8 +172,8 @@ var (
171172

172173
// NewHandler creates a new LocalAPI HTTP handler. All parameters except netMon
173174
// are required (if non-nil it's used to do faster interface lookups).
174-
func NewHandler(b *ipnlocal.LocalBackend, logf logger.Logf, logID logid.PublicID) *Handler {
175-
return &Handler{b: b, logf: logf, backendLogID: logID, clock: tstime.StdClock{}}
175+
func NewHandler(b *ipnlocal.LocalBackend, logf logger.Logf, logID logid.PublicID, dialer N.Dialer) *Handler {
176+
return &Handler{b: b, logf: logf, backendLogID: logID, clock: tstime.StdClock{}, dialer: dialer}
176177
}
177178

178179
type Handler struct {
@@ -201,6 +202,8 @@ type Handler struct {
201202
logf logger.Logf
202203
backendLogID logid.PublicID
203204
clock tstime.Clock
205+
206+
dialer N.Dialer
204207
}
205208

206209
func (h *Handler) LocalBackend() *ipnlocal.LocalBackend {
@@ -835,7 +838,7 @@ func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
835838
})
836839
defer c.Close()
837840

838-
netMon, err := netmon.New(logger.WithPrefix(logf, "monitor: "))
841+
netMon, err := netmon.New(logger.WithPrefix(logf, "monitor: "), h.dialer)
839842
if err != nil {
840843
logf("error creating monitor: %v", err)
841844
return

net/dnscache/dnscache.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,19 @@ func (r *Resolver) lookupIP(ctx context.Context, host string) (ip, ip6 netip.Add
285285

286286
lookupCtx, lookupCancel := context.WithTimeout(ctx, r.lookupTimeoutForHost(host))
287287
defer lookupCancel()
288-
ips, err := r.fwd().LookupNetIP(lookupCtx, "ip", host)
288+
var ips []netip.Addr
289+
if r.LookupHook != nil {
290+
ips, err = r.LookupHook(lookupCtx, host)
291+
} else {
292+
ips, err = r.fwd().LookupNetIP(lookupCtx, "ip", host)
293+
}
289294
if err != nil || len(ips) == 0 {
290295
if resolver, ok := r.cloudHostResolver(); ok {
291296
r.dlogf("resolving %q via cloud resolver", host)
292297
ips, err = resolver.LookupNetIP(lookupCtx, "ip", host)
293298
}
294299
}
295-
if (err != nil || len(ips) == 0) && r.LookupIPFallback != nil {
300+
if (err != nil || len(ips) == 0) && r.LookupIPFallback != nil && r.LookupHook == nil {
296301
lookupCtx, lookupCancel := context.WithTimeout(ctx, 30*time.Second)
297302
defer lookupCancel()
298303
if err != nil {

net/netmon/export.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package netmon
2+
3+
import (
4+
N "github.com/sagernet/sing/common/network"
5+
)
6+
7+
func (m *Monitor) Dialer() N.Dialer {
8+
return m.dialer
9+
}

net/netmon/netmon.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package netmon
99
import (
1010
"encoding/json"
1111
"errors"
12+
N "github.com/sagernet/sing/common/network"
1213
"net/netip"
1314
"runtime"
1415
"sync"
@@ -73,6 +74,7 @@ type Monitor struct {
7374
wallTimer *time.Timer // nil until Started; re-armed AfterFunc per tick
7475
lastWall time.Time
7576
timeJumped bool // whether we need to send a changed=true after a big time jump
77+
dialer N.Dialer
7678
}
7779

7880
// ChangeFunc is a callback function registered with Monitor that's called when the
@@ -114,13 +116,14 @@ type ChangeDelta struct {
114116
// New instantiates and starts a monitoring instance.
115117
// The returned monitor is inactive until it's started by the Start method.
116118
// Use RegisterChangeCallback to get notified of network changes.
117-
func New(logf logger.Logf) (*Monitor, error) {
119+
func New(logf logger.Logf, dialer N.Dialer) (*Monitor, error) {
118120
logf = logger.WithPrefix(logf, "monitor: ")
119121
m := &Monitor{
120122
logf: logf,
121123
change: make(chan bool, 1),
122124
stop: make(chan struct{}),
123125
lastWall: wallTime(),
126+
dialer: dialer,
124127
}
125128
st, err := m.interfaceStateUncached()
126129
if err != nil {

net/netns/export.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package netns
2+
3+
import (
4+
"context"
5+
M "github.com/sagernet/sing/common/metadata"
6+
N "github.com/sagernet/sing/common/network"
7+
"net"
8+
)
9+
10+
type dialerWrapper struct {
11+
N.Dialer
12+
}
13+
14+
func (d dialerWrapper) Dial(network, address string) (net.Conn, error) {
15+
return d.DialContext(context.Background(), network, address)
16+
}
17+
18+
func (d dialerWrapper) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
19+
return d.Dialer.DialContext(ctx, network, M.ParseSocksaddr(address))
20+
}

net/netns/netns.go

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ func FromDialer(logf logger.Logf, netMon *netmon.Monitor, d *net.Dialer) Dialer
8787
if netMon == nil {
8888
panic("netns.FromDialer called with nil netMon")
8989
}
90+
if dialer := netMon.Dialer(); dialer != nil {
91+
return dialerWrapper{dialer}
92+
}
9093
if disabled.Load() {
9194
return d
9295
}

net/tsdial/tsdial.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"context"
99
"errors"
1010
"fmt"
11+
M "github.com/sagernet/sing/common/metadata"
12+
N "github.com/sagernet/sing/common/network"
1113
"net"
1214
"net/http"
1315
"net/netip"
@@ -63,6 +65,8 @@ type Dialer struct {
6365
// If nil, it's not used.
6466
NetstackDialUDP func(context.Context, netip.AddrPort) (net.Conn, error)
6567

68+
Dialer N.Dialer
69+
6670
peerClientOnce sync.Once
6771
peerClient *http.Client
6872

@@ -184,6 +188,7 @@ func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
184188
}
185189
d.netMon = netMon
186190
d.netMonUnregister = d.netMon.RegisterChangeCallback(d.linkChanged)
191+
d.Dialer = netMon.Dialer()
187192
}
188193

189194
// NetMon returns the Dialer's network monitor.
@@ -379,11 +384,18 @@ func (d *Dialer) SystemDial(ctx context.Context, network, addr string) (net.Conn
379384
if closed {
380385
return nil, net.ErrClosed
381386
}
382-
383-
d.netnsDialerOnce.Do(func() {
384-
d.netnsDialer = netns.NewDialer(d.logf, d.netMon)
385-
})
386-
c, err := d.netnsDialer.DialContext(ctx, network, addr)
387+
var (
388+
c net.Conn
389+
err error
390+
)
391+
if d.Dialer != nil {
392+
c, err = d.Dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
393+
} else {
394+
d.netnsDialerOnce.Do(func() {
395+
d.netnsDialer = netns.NewDialer(d.logf, d.netMon)
396+
})
397+
c, err = d.netnsDialer.DialContext(ctx, network, addr)
398+
}
387399
if err != nil {
388400
return nil, err
389401
}

tsnet/tsnet.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"encoding/hex"
1212
"errors"
1313
"fmt"
14+
N "github.com/sagernet/sing/common/network"
1415
"github.com/sagernet/tailscale/net/dnscache"
1516
"io"
1617
"log"
@@ -122,7 +123,8 @@ type Server struct {
122123
// field at zero unless you know what you are doing.
123124
Port uint16
124125

125-
LookupHook dnscache.LookupHookFunc
126+
Dialer N.Dialer
127+
LookupHook dnscache.LookupHookFunc
126128

127129
getCertForTesting func(*tls.ClientHelloInfo) (*tls.Certificate, error)
128130

@@ -274,7 +276,7 @@ func (s *Server) Loopback() (addr string, proxyCred, localAPICred string, err er
274276
// out the CONNECT code from tailscaled/proxy.go that uses
275277
// httputil.ReverseProxy and adding auth support.
276278
go func() {
277-
lah := localapi.NewHandler(s.lb, s.logf, s.logid)
279+
lah := localapi.NewHandler(s.lb, s.logf, s.logid, s.netMon.Dialer())
278280
lah.PermitWrite = true
279281
lah.PermitRead = true
280282
lah.RequiredPassword = s.localAPICred
@@ -557,13 +559,13 @@ func (s *Server) start() (reterr error) {
557559
return err
558560
}
559561

560-
s.netMon, err = netmon.New(tsLogf)
562+
s.netMon, err = netmon.New(tsLogf, s.Dialer)
561563
if err != nil {
562564
return err
563565
}
564566
closePool.add(s.netMon)
565567

566-
s.dialer = &tsdial.Dialer{Logf: tsLogf} // mutated below (before used)
568+
s.dialer = &tsdial.Dialer{Logf: tsLogf, Dialer: s.Dialer} // mutated below (before used)
567569
eng, err := wgengine.NewUserspaceEngine(tsLogf, wgengine.Config{
568570
ListenPort: s.Port,
569571
NetMon: s.netMon,
@@ -668,7 +670,7 @@ func (s *Server) start() (reterr error) {
668670
//go s.printAuthURLLoop()
669671

670672
// Run the localapi handler, to allow fetching LetsEncrypt certs.
671-
lah := localapi.NewHandler(lb, tsLogf, s.logid)
673+
lah := localapi.NewHandler(lb, tsLogf, s.logid, s.netMon.Dialer())
672674
lah.PermitWrite = true
673675
lah.PermitRead = true
674676

wgengine/userspace.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
357357
if conf.NetMon != nil {
358358
e.netMon = conf.NetMon
359359
} else {
360-
mon, err := netmon.New(logf)
360+
mon, err := netmon.New(logf, nil)
361361
if err != nil {
362362
return nil, err
363363
}

0 commit comments

Comments
 (0)