control/controlclient,tailcfg: [capver 40] create KeySignature field in tailcfg.Node

We calve out a space to put the node-key signature (used on tailnets where network lock is enabled).

Signed-off-by: Tom DNetto <tom@tailscale.com>
This commit is contained in:
Tom DNetto 2022-08-12 12:34:25 -07:00 committed by Tom
parent 5d559141d5
commit 18edd79421
9 changed files with 48 additions and 15 deletions

View File

@ -61,7 +61,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
tailscale.com/types/persist from tailscale.com/ipn
tailscale.com/types/preftype from tailscale.com/ipn
tailscale.com/types/structs from tailscale.com/ipn+
tailscale.com/types/tkatype from tailscale.com/types/key
tailscale.com/types/tkatype from tailscale.com/types/key+
tailscale.com/types/views from tailscale.com/ipn/ipnstate+
tailscale.com/util/cloudenv from tailscale.com/hostinfo+
W tailscale.com/util/cmpver from tailscale.com/net/tshttpproxy

View File

@ -84,7 +84,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/types/persist from tailscale.com/ipn
tailscale.com/types/preftype from tailscale.com/cmd/tailscale/cli+
tailscale.com/types/structs from tailscale.com/ipn+
tailscale.com/types/tkatype from tailscale.com/types/key
tailscale.com/types/tkatype from tailscale.com/types/key+
tailscale.com/types/views from tailscale.com/tailcfg+
tailscale.com/util/clientmetric from tailscale.com/net/netcheck+
tailscale.com/util/cloudenv from tailscale.com/net/dnscache+

View File

@ -310,6 +310,9 @@ func undeltaPeers(mapRes *tailcfg.MapResponse, prev []*tailcfg.Node) {
if v := ec.Capabilities; v != nil {
n.Capabilities = *v
}
if v := ec.KeySignature; v != nil {
n.KeySignature = v
}
}
}
}

View File

@ -209,6 +209,20 @@ func TestUndeltaPeers(t *testing.T) {
Key: key.NodePublicFromRaw32(mem.B(append(make([]byte, 31), 'A'))),
}),
},
{
name: "change_key_signature",
prev: peers(n(1, "foo")),
mapRes: &tailcfg.MapResponse{
PeersChangedPatch: []*tailcfg.PeerChange{{
NodeID: 1,
KeySignature: []byte{3, 4},
}},
}, want: peers(&tailcfg.Node{
ID: 1,
Name: "foo",
KeySignature: []byte{3, 4},
}),
},
{
name: "change_disco_key",
prev: peers(n(1, "foo")),

View File

@ -7,6 +7,7 @@
//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPRegion,DERPMap,DERPNode,SSHRule,SSHPrincipal --clonefunc
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
@ -19,6 +20,7 @@
"tailscale.com/types/key"
"tailscale.com/types/opt"
"tailscale.com/types/structs"
"tailscale.com/types/tkatype"
"tailscale.com/util/dnsname"
)
@ -74,7 +76,8 @@
// 37: 2022-08-09: added Debug.{SetForceBackgroundSTUN,SetRandomizeClientPort}; Debug are sticky
// 38: 2022-08-11: added PingRequest.URLIsNoise
// 39: 2022-08-15: clients can talk Noise over arbitrary HTTPS port
const CurrentCapabilityVersion CapabilityVersion = 39
// 40: 2022-08-22: added Node.KeySignature, PeersChangedPatch.KeySignature
const CurrentCapabilityVersion CapabilityVersion = 40
type StableID string
@ -172,16 +175,17 @@ type Node struct {
// Sharer, if non-zero, is the user who shared this node, if different than User.
Sharer UserID `json:",omitempty"`
Key key.NodePublic
KeyExpiry time.Time
Machine key.MachinePublic
DiscoKey key.DiscoPublic
Addresses []netip.Prefix // IP addresses of this Node directly
AllowedIPs []netip.Prefix // range of IP addresses to route to this node
Endpoints []string `json:",omitempty"` // IP+port (public via STUN, and local LANs)
DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
Hostinfo HostinfoView
Created time.Time
Key key.NodePublic
KeyExpiry time.Time
KeySignature tkatype.MarshaledSignature `json:",omitempty"`
Machine key.MachinePublic
DiscoKey key.DiscoPublic
Addresses []netip.Prefix // IP addresses of this Node directly
AllowedIPs []netip.Prefix // range of IP addresses to route to this node
Endpoints []string `json:",omitempty"` // IP+port (public via STUN, and local LANs)
DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
Hostinfo HostinfoView
Created time.Time
// Tags are the list of ACL tags applied to this node.
// Tags take the form of `tag:<value>` where value starts
@ -1439,6 +1443,7 @@ func (n *Node) Equal(n2 *Node) bool {
n.Sharer == n2.Sharer &&
n.Key == n2.Key &&
n.KeyExpiry.Equal(n2.KeyExpiry) &&
bytes.Equal(n.KeySignature, n2.KeySignature) &&
n.Machine == n2.Machine &&
n.DiscoKey == n2.DiscoKey &&
eqBoolPtr(n.Online, n2.Online) &&
@ -1799,6 +1804,10 @@ type PeerChange struct {
// Key, if non-nil, means that the NodeID's wireguard public key changed.
Key *key.NodePublic `json:",omitempty"`
// KeySignature, if non-nil, means that the signature of the wireguard
// public key has changed.
KeySignature tkatype.MarshaledSignature `json:",omitempty"`
// DiscoKey, if non-nil, means that the NodeID's discokey changed.
DiscoKey *key.DiscoPublic `json:",omitempty"`

View File

@ -14,6 +14,7 @@
"tailscale.com/types/key"
"tailscale.com/types/opt"
"tailscale.com/types/structs"
"tailscale.com/types/tkatype"
)
// Clone makes a deep copy of User.
@ -47,6 +48,7 @@ func (src *Node) Clone() *Node {
}
dst := new(Node)
*dst = *src
dst.KeySignature = append(src.KeySignature[:0:0], src.KeySignature...)
dst.Addresses = append(src.Addresses[:0:0], src.Addresses...)
dst.AllowedIPs = append(src.AllowedIPs[:0:0], src.AllowedIPs...)
dst.Endpoints = append(src.Endpoints[:0:0], src.Endpoints...)
@ -74,6 +76,7 @@ func (src *Node) Clone() *Node {
Sharer UserID
Key key.NodePublic
KeyExpiry time.Time
KeySignature tkatype.MarshaledSignature
Machine key.MachinePublic
DiscoKey key.DiscoPublic
Addresses []netip.Prefix

View File

@ -305,7 +305,7 @@ func TestHostinfoTailscaleSSHEnabled(t *testing.T) {
func TestNodeEqual(t *testing.T) {
nodeHandles := []string{
"ID", "StableID", "Name", "User", "Sharer",
"Key", "KeyExpiry", "Machine", "DiscoKey",
"Key", "KeyExpiry", "KeySignature", "Machine", "DiscoKey",
"Addresses", "AllowedIPs", "Endpoints", "DERP", "Hostinfo",
"Created", "Tags", "PrimaryRoutes",
"LastSeen", "Online", "KeepAlive", "MachineAuthorized",

View File

@ -12,10 +12,12 @@
"net/netip"
"time"
"go4.org/mem"
"tailscale.com/types/dnstype"
"tailscale.com/types/key"
"tailscale.com/types/opt"
"tailscale.com/types/structs"
"tailscale.com/types/tkatype"
"tailscale.com/types/views"
)
@ -137,6 +139,7 @@ func (v NodeView) User() UserID { return v.ж.User }
func (v NodeView) Sharer() UserID { return v.ж.Sharer }
func (v NodeView) Key() key.NodePublic { return v.ж.Key }
func (v NodeView) KeyExpiry() time.Time { return v.ж.KeyExpiry }
func (v NodeView) KeySignature() mem.RO { return mem.B(v.ж.KeySignature) }
func (v NodeView) Machine() key.MachinePublic { return v.ж.Machine }
func (v NodeView) DiscoKey() key.DiscoPublic { return v.ж.DiscoKey }
func (v NodeView) Addresses() views.IPPrefixSlice { return views.IPPrefixSliceOf(v.ж.Addresses) }
@ -181,6 +184,7 @@ func (v NodeView) Equal(v2 NodeView) bool { return v.ж.Equal(v2.ж)
Sharer UserID
Key key.NodePublic
KeyExpiry time.Time
KeySignature tkatype.MarshaledSignature
Machine key.MachinePublic
DiscoKey key.DiscoPublic
Addresses []netip.Prefix

View File

@ -559,7 +559,7 @@ func TestGetTypeHasher(t *testing.T) {
{
name: "tailcfg.Node",
val: &tailcfg.Node{},
out: "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + u64(uint64(time.Time{}.Unix())) + u32(0) + u32(0) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + u64(uint64(time.Time{}.Unix())) + u32(0) + u32(0) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
out: "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + u64(uint64(time.Time{}.Unix())) + u64(0) + u32(0) + u32(0) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + u64(uint64(time.Time{}.Unix())) + u32(0) + u32(0) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
},
}
for _, tt := range tests {