Skip to content

Commit 8ed6bb3

Browse files
committed
ipn/ipnlocal: move vipServiceHash etc to serve.go, out of local.go
Updates tailscale#12614 Change-Id: I3c16b94fcb997088ff18d5a21355e0279845ed7e Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
1 parent e0e8731 commit 8ed6bb3

File tree

3 files changed

+75
-51
lines changed

3 files changed

+75
-51
lines changed

ipn/ipnlocal/local.go

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"context"
1111
"crypto/sha256"
1212
"encoding/binary"
13-
"encoding/hex"
1413
"encoding/json"
1514
"errors"
1615
"fmt"
@@ -5487,20 +5486,9 @@ func (b *LocalBackend) applyPrefsToHostinfoLocked(hi *tailcfg.Hostinfo, prefs ip
54875486
}
54885487
hi.SSH_HostKeys = sshHostKeys
54895488

5490-
hi.ServicesHash = b.vipServiceHash(b.vipServicesFromPrefsLocked(prefs))
5491-
5492-
// The Hostinfo.IngressEnabled field is used to communicate to control whether
5493-
// the node has funnel enabled.
5494-
hi.IngressEnabled = b.hasIngressEnabledLocked()
5495-
// The Hostinfo.WantIngress field tells control whether the user intends
5496-
// to use funnel with this node even though it is not currently enabled.
5497-
// This is an optimization to control- Funnel requires creation of DNS
5498-
// records and because DNS propagation can take time, we want to ensure
5499-
// that the records exist for any node that intends to use funnel even
5500-
// if it's not enabled. If hi.IngressEnabled is true, control knows that
5501-
// DNS records are needed, so we can save bandwidth and not send
5502-
// WireIngress.
5503-
hi.WireIngress = b.shouldWireInactiveIngressLocked()
5489+
for _, f := range hookMaybeMutateHostinfoLocked {
5490+
f(b, hi, prefs)
5491+
}
55045492

55055493
if buildfeatures.HasAppConnectors {
55065494
hi.AppConnector.Set(prefs.AppConnector().Advertise)
@@ -6284,36 +6272,34 @@ func (b *LocalBackend) setTCPPortsInterceptedFromNetmapAndPrefsLocked(prefs ipn.
62846272
}
62856273

62866274
// Update funnel and service hash info in hostinfo and kick off control update if needed.
6287-
b.updateIngressAndServiceHashLocked(prefs)
6275+
b.maybeSentHostinfoIfChangedLocked(prefs)
62886276
b.setTCPPortsIntercepted(handlePorts)
62896277
}
62906278

6291-
// updateIngressAndServiceHashLocked updates the hostinfo.ServicesHash, hostinfo.WireIngress and
6279+
// hookMaybeMutateHostinfoLocked is a hook that allows conditional features
6280+
// to mutate the provided hostinfo before it is sent to control.
6281+
//
6282+
// The hook function should return true if it mutated the hostinfo.
6283+
//
6284+
// The LocalBackend's mutex is held while calling.
6285+
var hookMaybeMutateHostinfoLocked feature.Hooks[func(*LocalBackend, *tailcfg.Hostinfo, ipn.PrefsView) bool]
6286+
6287+
// maybeSentHostinfoIfChangedLocked updates the hostinfo.ServicesHash, hostinfo.WireIngress and
62926288
// hostinfo.IngressEnabled fields and kicks off a Hostinfo update if the values have changed.
62936289
//
62946290
// b.mu must be held.
6295-
func (b *LocalBackend) updateIngressAndServiceHashLocked(prefs ipn.PrefsView) {
6291+
func (b *LocalBackend) maybeSentHostinfoIfChangedLocked(prefs ipn.PrefsView) {
62966292
if b.hostinfo == nil {
62976293
return
62986294
}
6299-
hostInfoChanged := false
6300-
if ie := b.hasIngressEnabledLocked(); b.hostinfo.IngressEnabled != ie {
6301-
b.logf("Hostinfo.IngressEnabled changed to %v", ie)
6302-
b.hostinfo.IngressEnabled = ie
6303-
hostInfoChanged = true
6304-
}
6305-
if wire := b.shouldWireInactiveIngressLocked(); b.hostinfo.WireIngress != wire {
6306-
b.logf("Hostinfo.WireIngress changed to %v", wire)
6307-
b.hostinfo.WireIngress = wire
6308-
hostInfoChanged = true
6309-
}
6310-
latestHash := b.vipServiceHash(b.vipServicesFromPrefsLocked(prefs))
6311-
if b.hostinfo.ServicesHash != latestHash {
6312-
b.hostinfo.ServicesHash = latestHash
6313-
hostInfoChanged = true
6295+
changed := false
6296+
for _, f := range hookMaybeMutateHostinfoLocked {
6297+
if f(b, b.hostinfo, prefs) {
6298+
changed = true
6299+
}
63146300
}
63156301
// Kick off a Hostinfo update to control if ingress status has changed.
6316-
if hostInfoChanged {
6302+
if changed {
63176303
b.goTracker.Go(b.doSetHostinfoFilterServices)
63186304
}
63196305
}
@@ -7707,19 +7693,6 @@ func maybeUsernameOf(actor ipnauth.Actor) string {
77077693
return username
77087694
}
77097695

7710-
func (b *LocalBackend) vipServiceHash(services []*tailcfg.VIPService) string {
7711-
if len(services) == 0 {
7712-
return ""
7713-
}
7714-
buf, err := json.Marshal(services)
7715-
if err != nil {
7716-
b.logf("vipServiceHashLocked: %v", err)
7717-
return ""
7718-
}
7719-
hash := sha256.Sum256(buf)
7720-
return hex.EncodeToString(hash[:])
7721-
}
7722-
77237696
var (
77247697
metricCurrentWatchIPNBus = clientmetric.NewGauge("localbackend_current_watch_ipn_bus")
77257698
)

ipn/ipnlocal/local_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6745,7 +6745,7 @@ func TestUpdateIngressAndServiceHashLocked(t *testing.T) {
67456745
if tt.hasPreviousSC {
67466746
b.mu.Lock()
67476747
b.serveConfig = previousSC.View()
6748-
b.hostinfo.ServicesHash = b.vipServiceHash(b.vipServicesFromPrefsLocked(prefs))
6748+
b.hostinfo.ServicesHash = vipServiceHash(b.logf, b.vipServicesFromPrefsLocked(prefs))
67496749
b.mu.Unlock()
67506750
}
67516751
b.serveConfig = tt.sc.View()
@@ -6763,7 +6763,7 @@ func TestUpdateIngressAndServiceHashLocked(t *testing.T) {
67636763
})()
67646764

67656765
was := b.goTracker.StartedGoroutines()
6766-
b.updateIngressAndServiceHashLocked(prefs)
6766+
b.maybeSentHostinfoIfChangedLocked(prefs)
67676767

67686768
if tt.hi != nil {
67696769
if tt.hi.IngressEnabled != tt.wantIngress {
@@ -6773,7 +6773,7 @@ func TestUpdateIngressAndServiceHashLocked(t *testing.T) {
67736773
t.Errorf("WireIngress = %v, want %v", tt.hi.WireIngress, tt.wantWireIngress)
67746774
}
67756775
b.mu.Lock()
6776-
svcHash := b.vipServiceHash(b.vipServicesFromPrefsLocked(prefs))
6776+
svcHash := vipServiceHash(b.logf, b.vipServicesFromPrefsLocked(prefs))
67776777
b.mu.Unlock()
67786778
if tt.hi.ServicesHash != svcHash {
67796779
t.Errorf("ServicesHash = %v, want %v", tt.hi.ServicesHash, svcHash)

ipn/ipnlocal/serve.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ func init() {
5959
b.setVIPServicesTCPPortsInterceptedLocked(nil)
6060
})
6161

62+
hookMaybeMutateHostinfoLocked.Add(maybeUpdateHostinfoServicesHashLocked)
63+
hookMaybeMutateHostinfoLocked.Add(maybeUpdateHostinfoFunnelLocked)
64+
6265
RegisterC2N("GET /vip-services", handleC2NVIPServicesGet)
6366
}
6467

@@ -1227,7 +1230,7 @@ func handleC2NVIPServicesGet(b *LocalBackend, w http.ResponseWriter, r *http.Req
12271230
b.logf("c2n: GET /vip-services received")
12281231
var res tailcfg.C2NVIPServicesResponse
12291232
res.VIPServices = b.VIPServices()
1230-
res.ServicesHash = b.vipServiceHash(res.VIPServices)
1233+
res.ServicesHash = vipServiceHash(b.logf, res.VIPServices)
12311234

12321235
w.Header().Set("Content-Type", "application/json")
12331236
json.NewEncoder(w).Encode(res)
@@ -1443,3 +1446,51 @@ func (b *LocalBackend) setVIPServicesTCPPortsInterceptedLocked(svcPorts map[tail
14431446

14441447
b.shouldInterceptVIPServicesTCPPortAtomic.Store(generateInterceptVIPServicesTCPPortFunc(svcAddrPorts))
14451448
}
1449+
1450+
func maybeUpdateHostinfoServicesHashLocked(b *LocalBackend, hi *tailcfg.Hostinfo, prefs ipn.PrefsView) bool {
1451+
latestHash := vipServiceHash(b.logf, b.vipServicesFromPrefsLocked(prefs))
1452+
if hi.ServicesHash != latestHash {
1453+
hi.ServicesHash = latestHash
1454+
return true
1455+
}
1456+
return false
1457+
}
1458+
1459+
func maybeUpdateHostinfoFunnelLocked(b *LocalBackend, hi *tailcfg.Hostinfo, prefs ipn.PrefsView) (changed bool) {
1460+
// The Hostinfo.IngressEnabled field is used to communicate to control whether
1461+
// the node has funnel enabled.
1462+
if ie := b.hasIngressEnabledLocked(); hi.IngressEnabled != ie {
1463+
b.logf("Hostinfo.IngressEnabled changed to %v", ie)
1464+
hi.IngressEnabled = ie
1465+
changed = true
1466+
}
1467+
// The Hostinfo.WireIngress field tells control whether the user intends
1468+
// to use funnel with this node even though it is not currently enabled.
1469+
// This is an optimization to control- Funnel requires creation of DNS
1470+
// records and because DNS propagation can take time, we want to ensure
1471+
// that the records exist for any node that intends to use funnel even
1472+
// if it's not enabled. If hi.IngressEnabled is true, control knows that
1473+
// DNS records are needed, so we can save bandwidth and not send
1474+
// WireIngress.
1475+
if wire := b.shouldWireInactiveIngressLocked(); hi.WireIngress != wire {
1476+
b.logf("Hostinfo.WireIngress changed to %v", wire)
1477+
hi.WireIngress = wire
1478+
changed = true
1479+
}
1480+
return changed
1481+
}
1482+
1483+
func vipServiceHash(logf logger.Logf, services []*tailcfg.VIPService) string {
1484+
if len(services) == 0 {
1485+
return ""
1486+
}
1487+
h := sha256.New()
1488+
jh := json.NewEncoder(h)
1489+
if err := jh.Encode(services); err != nil {
1490+
logf("vipServiceHashLocked: %v", err)
1491+
return ""
1492+
}
1493+
var buf [sha256.Size]byte
1494+
h.Sum(buf[:0])
1495+
return hex.EncodeToString(buf[:])
1496+
}

0 commit comments

Comments
 (0)