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/persist from tailscale.com/ipn
tailscale.com/types/preftype from tailscale.com/ipn tailscale.com/types/preftype from tailscale.com/ipn
tailscale.com/types/structs 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/types/views from tailscale.com/ipn/ipnstate+
tailscale.com/util/cloudenv from tailscale.com/hostinfo+ tailscale.com/util/cloudenv from tailscale.com/hostinfo+
W tailscale.com/util/cmpver from tailscale.com/net/tshttpproxy 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/persist from tailscale.com/ipn
tailscale.com/types/preftype from tailscale.com/cmd/tailscale/cli+ tailscale.com/types/preftype from tailscale.com/cmd/tailscale/cli+
tailscale.com/types/structs 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/tailcfg+ tailscale.com/types/views from tailscale.com/tailcfg+
tailscale.com/util/clientmetric from tailscale.com/net/netcheck+ tailscale.com/util/clientmetric from tailscale.com/net/netcheck+
tailscale.com/util/cloudenv from tailscale.com/net/dnscache+ 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 { if v := ec.Capabilities; v != nil {
n.Capabilities = *v 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'))), 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", name: "change_disco_key",
prev: peers(n(1, "foo")), 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 //go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPRegion,DERPMap,DERPNode,SSHRule,SSHPrincipal --clonefunc
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
@ -19,6 +20,7 @@
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/opt" "tailscale.com/types/opt"
"tailscale.com/types/structs" "tailscale.com/types/structs"
"tailscale.com/types/tkatype"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -74,7 +76,8 @@
// 37: 2022-08-09: added Debug.{SetForceBackgroundSTUN,SetRandomizeClientPort}; Debug are sticky // 37: 2022-08-09: added Debug.{SetForceBackgroundSTUN,SetRandomizeClientPort}; Debug are sticky
// 38: 2022-08-11: added PingRequest.URLIsNoise // 38: 2022-08-11: added PingRequest.URLIsNoise
// 39: 2022-08-15: clients can talk Noise over arbitrary HTTPS port // 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 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, if non-zero, is the user who shared this node, if different than User.
Sharer UserID `json:",omitempty"` Sharer UserID `json:",omitempty"`
Key key.NodePublic Key key.NodePublic
KeyExpiry time.Time KeyExpiry time.Time
Machine key.MachinePublic KeySignature tkatype.MarshaledSignature `json:",omitempty"`
DiscoKey key.DiscoPublic Machine key.MachinePublic
Addresses []netip.Prefix // IP addresses of this Node directly DiscoKey key.DiscoPublic
AllowedIPs []netip.Prefix // range of IP addresses to route to this node Addresses []netip.Prefix // IP addresses of this Node directly
Endpoints []string `json:",omitempty"` // IP+port (public via STUN, and local LANs) AllowedIPs []netip.Prefix // range of IP addresses to route to this node
DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint Endpoints []string `json:",omitempty"` // IP+port (public via STUN, and local LANs)
Hostinfo HostinfoView DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
Created time.Time Hostinfo HostinfoView
Created time.Time
// Tags are the list of ACL tags applied to this node. // Tags are the list of ACL tags applied to this node.
// Tags take the form of `tag:<value>` where value starts // 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.Sharer == n2.Sharer &&
n.Key == n2.Key && n.Key == n2.Key &&
n.KeyExpiry.Equal(n2.KeyExpiry) && n.KeyExpiry.Equal(n2.KeyExpiry) &&
bytes.Equal(n.KeySignature, n2.KeySignature) &&
n.Machine == n2.Machine && n.Machine == n2.Machine &&
n.DiscoKey == n2.DiscoKey && n.DiscoKey == n2.DiscoKey &&
eqBoolPtr(n.Online, n2.Online) && 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, if non-nil, means that the NodeID's wireguard public key changed.
Key *key.NodePublic `json:",omitempty"` 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, if non-nil, means that the NodeID's discokey changed.
DiscoKey *key.DiscoPublic `json:",omitempty"` DiscoKey *key.DiscoPublic `json:",omitempty"`

View File

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

View File

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

View File

@ -12,10 +12,12 @@
"net/netip" "net/netip"
"time" "time"
"go4.org/mem"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/opt" "tailscale.com/types/opt"
"tailscale.com/types/structs" "tailscale.com/types/structs"
"tailscale.com/types/tkatype"
"tailscale.com/types/views" "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) Sharer() UserID { return v.ж.Sharer }
func (v NodeView) Key() key.NodePublic { return v.ж.Key } func (v NodeView) Key() key.NodePublic { return v.ж.Key }
func (v NodeView) KeyExpiry() time.Time { return v.ж.KeyExpiry } 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) Machine() key.MachinePublic { return v.ж.Machine }
func (v NodeView) DiscoKey() key.DiscoPublic { return v.ж.DiscoKey } func (v NodeView) DiscoKey() key.DiscoPublic { return v.ж.DiscoKey }
func (v NodeView) Addresses() views.IPPrefixSlice { return views.IPPrefixSliceOf(v.ж.Addresses) } 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 Sharer UserID
Key key.NodePublic Key key.NodePublic
KeyExpiry time.Time KeyExpiry time.Time
KeySignature tkatype.MarshaledSignature
Machine key.MachinePublic Machine key.MachinePublic
DiscoKey key.DiscoPublic DiscoKey key.DiscoPublic
Addresses []netip.Prefix Addresses []netip.Prefix

View File

@ -559,7 +559,7 @@ func TestGetTypeHasher(t *testing.T) {
{ {
name: "tailcfg.Node", name: "tailcfg.Node",
val: &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 { for _, tt := range tests {