Skip to content

Commit 953541d

Browse files
committed
Improve DERP server
1 parent 866887f commit 953541d

File tree

5 files changed

+76
-83
lines changed

5 files changed

+76
-83
lines changed

derp/derp_server.go

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"errors"
1919
"expvar"
2020
"fmt"
21+
E "github.com/sagernet/sing/common/exceptions"
2122
"io"
2223
"log"
2324
"math"
@@ -174,9 +175,10 @@ type Server struct {
174175
// server if the clientKey is a known peer in the network, as specified by a
175176
// running tailscaled's client's LocalAPI.
176177
verifyClientsLocalTailscaled bool
177-
178-
verifyClientsURL string
179-
verifyClientsURLFailOpen bool
178+
verifyClientLocalClient []*tailscale.LocalClient
179+
verifyClientHTTPClient *http.Client
180+
verifyClientsURL []string
181+
verifyClientsURLFailOpen bool
180182

181183
mu sync.Mutex
182184
closed bool
@@ -471,10 +473,18 @@ func (s *Server) SetVerifyClient(v bool) {
471473
s.verifyClientsLocalTailscaled = v
472474
}
473475

476+
func (s *Server) SetVerifyClientLocalClient(localClient []*tailscale.LocalClient) {
477+
s.verifyClientLocalClient = localClient
478+
}
479+
480+
func (s *Server) SetVerifyClientHTTPClient(httpClient *http.Client) {
481+
s.verifyClientHTTPClient = httpClient
482+
}
483+
474484
// SetVerifyClientURL sets the admission controller URL to use for verifying clients.
475485
// If empty, all clients are accepted (unless restricted by SetVerifyClient checking
476486
// against tailscaled).
477-
func (s *Server) SetVerifyClientURL(v string) {
487+
func (s *Server) SetVerifyClientURL(v []string) {
478488
s.verifyClientsURL = v
479489
}
480490

@@ -1352,42 +1362,72 @@ func (s *Server) verifyClient(ctx context.Context, clientKey key.NodePublic, inf
13521362
}
13531363
}
13541364

1365+
var errors []error
1366+
if len(s.verifyClientLocalClient) > 0 {
1367+
for _, verifyClient := range s.verifyClientLocalClient {
1368+
_, err := verifyClient.WhoIsNodeKey(ctx, clientKey)
1369+
if err == tailscale.ErrPeerNotFound {
1370+
errors = append(errors, fmt.Errorf("peer %v not authorized (not found in local tailscaled)", clientKey))
1371+
continue
1372+
}
1373+
if err != nil {
1374+
if strings.Contains(err.Error(), "invalid 'addr' parameter") {
1375+
// Issue 12617
1376+
errors = append(errors, E.New("tailscaled version is too old (out of sync with derper binary)"))
1377+
continue
1378+
}
1379+
errors = append(errors, fmt.Errorf("failed to query local tailscaled status for %v: %w", clientKey, err))
1380+
continue
1381+
}
1382+
return nil
1383+
}
1384+
}
13551385
// admission controller-based verification:
1356-
if s.verifyClientsURL != "" {
1357-
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
1358-
defer cancel()
1359-
1386+
if len(s.verifyClientsURL) > 0 {
13601387
jreq, err := json.Marshal(&tailcfg.DERPAdmitClientRequest{
13611388
NodePublic: clientKey,
13621389
Source: clientIP,
13631390
})
13641391
if err != nil {
13651392
return err
13661393
}
1367-
req, err := http.NewRequestWithContext(ctx, "POST", s.verifyClientsURL, bytes.NewReader(jreq))
1368-
if err != nil {
1369-
return err
1370-
}
1371-
res, err := http.DefaultClient.Do(req)
1372-
if err != nil {
1373-
if s.verifyClientsURLFailOpen {
1374-
s.logf("admission controller unreachable; allowing client %v", clientKey)
1375-
return nil
1394+
1395+
for _, verifyClientsURL := range s.verifyClientsURL {
1396+
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
1397+
defer cancel()
1398+
req, err := http.NewRequestWithContext(ctx, "POST", verifyClientsURL, bytes.NewReader(jreq))
1399+
if err != nil {
1400+
return err
13761401
}
1377-
return err
1378-
}
1379-
defer res.Body.Close()
1380-
if res.StatusCode != 200 {
1381-
return fmt.Errorf("admission controller: %v", res.Status)
1382-
}
1383-
var jres tailcfg.DERPAdmitClientResponse
1384-
if err := json.NewDecoder(io.LimitReader(res.Body, 4<<10)).Decode(&jres); err != nil {
1385-
return err
1386-
}
1387-
if !jres.Allow {
1388-
return fmt.Errorf("admission controller: %v/%v not allowed", clientKey, clientIP)
1402+
res, err := s.verifyClientHTTPClient.Do(req)
1403+
if err != nil {
1404+
if s.verifyClientsURLFailOpen {
1405+
s.logf("admission controller unreachable; allowing client %v", clientKey)
1406+
continue
1407+
}
1408+
errors = append(errors, err)
1409+
continue
1410+
}
1411+
defer res.Body.Close()
1412+
if res.StatusCode != 200 {
1413+
errors = append(errors, fmt.Errorf("admission controller: %v", res.Status))
1414+
continue
1415+
}
1416+
var jres tailcfg.DERPAdmitClientResponse
1417+
if err := json.NewDecoder(io.LimitReader(res.Body, 4<<10)).Decode(&jres); err != nil {
1418+
errors = append(errors, err)
1419+
continue
1420+
}
1421+
if !jres.Allow {
1422+
errors = append(errors, fmt.Errorf("admission controller: %v/%v not allowed", clientKey, clientIP))
1423+
continue
1424+
}
1425+
// TODO(bradfitz): add policy for configurable bandwidth rate per client?
1426+
return nil
13891427
}
1390-
// TODO(bradfitz): add policy for configurable bandwidth rate per client?
1428+
}
1429+
if len(errors) > 0 {
1430+
return E.Errors(errors...)
13911431
}
13921432
return nil
13931433
}

derp/derphttp/derphttp_client.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,12 @@ func (c *Client) dialRegion(ctx context.Context, reg *tailcfg.DERPRegion) (net.C
645645
}
646646

647647
func (c *Client) tlsClient(nc net.Conn, node *tailcfg.DERPNode) *tls.Conn {
648-
tlsConf := tlsdial.Config(c.tlsServerName(node), c.HealthTracker, c.TLSConfig)
648+
var tlsConf *tls.Config
649+
if c.TLSConfig != nil {
650+
tlsConf = c.TLSConfig
651+
} else {
652+
tlsConf = tlsdial.Config(c.tlsServerName(node), c.HealthTracker, &tls.Config{})
653+
}
649654
if node != nil {
650655
if node.InsecureForTests {
651656
tlsConf.InsecureSkipVerify = true

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP
122122
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
123123
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3 h1:RxEz7LhPNiF/gX/Hg+OXr5lqsM9iVAgmaK1L1vzlDRM=
124124
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3/go.mod h1:ehZwnT2UpmOWAHFL48XdBhnd4Qu4hN2O3Ji0us3ZHMw=
125-
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
126-
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
127125
github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA=
128126
github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
129127
github.com/sagernet/wireguard-go v0.0.1-beta.4 h1:8uyM5fxfEXdu4RH05uOK+v25i3lTNdCYMPSAUJ14FnI=

tsweb/debug.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"os"
1515
"runtime"
1616

17-
"github.com/sagernet/tailscale/tsweb/promvarz"
1817
"github.com/sagernet/tailscale/tsweb/varz"
1918
"github.com/sagernet/tailscale/version"
2019
)
@@ -51,7 +50,6 @@ func Debugger(mux *http.ServeMux) *DebugHandler {
5150
ret.KVFunc("Uptime", func() any { return varz.Uptime() })
5251
ret.KV("Version", version.Long())
5352
ret.Handle("vars", "Metrics (Go)", expvar.Handler())
54-
ret.Handle("varz", "Metrics (Prometheus)", http.HandlerFunc(promvarz.Handler))
5553

5654
// pprof.Index serves everything that runtime/pprof.Lookup finds:
5755
// goroutine, threadcreate, heap, allocs, block, mutex

tsweb/promvarz/promvarz.go

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)