mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-27 10:47:35 +00:00
all: start groundwork for using capver for localapi & peerapi
Updates #7015 Change-Id: I3d4c11b42a727a62eaac3262a879f29bb4ce82dd Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
c129bf1da1
commit
6edf357b96
@ -114,6 +114,7 @@ func (lc *LocalClient) defaultDialer(ctx context.Context, network, addr string)
|
|||||||
//
|
//
|
||||||
// DoLocalRequest may mutate the request to add Authorization headers.
|
// DoLocalRequest may mutate the request to add Authorization headers.
|
||||||
func (lc *LocalClient) DoLocalRequest(req *http.Request) (*http.Response, error) {
|
func (lc *LocalClient) DoLocalRequest(req *http.Request) (*http.Response, error) {
|
||||||
|
req.Header.Set("Tailscale-Cap", strconv.Itoa(int(tailcfg.CurrentCapabilityVersion)))
|
||||||
lc.tsClientOnce.Do(func() {
|
lc.tsClientOnce.Do(func() {
|
||||||
lc.tsClient = &http.Client{
|
lc.tsClient = &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
|
@ -310,6 +310,9 @@ func undeltaPeers(mapRes *tailcfg.MapResponse, prev []*tailcfg.Node) {
|
|||||||
if ec.DERPRegion != 0 {
|
if ec.DERPRegion != 0 {
|
||||||
n.DERP = fmt.Sprintf("%s:%v", tailcfg.DerpMagicIP, ec.DERPRegion)
|
n.DERP = fmt.Sprintf("%s:%v", tailcfg.DerpMagicIP, ec.DERPRegion)
|
||||||
}
|
}
|
||||||
|
if ec.Cap != 0 {
|
||||||
|
n.Cap = ec.Cap
|
||||||
|
}
|
||||||
if ec.Endpoints != nil {
|
if ec.Endpoints != nil {
|
||||||
n.Endpoints = ec.Endpoints
|
n.Endpoints = ec.Endpoints
|
||||||
}
|
}
|
||||||
|
@ -4348,20 +4348,32 @@ func exitNodeCanProxyDNS(nm *netmap.NetworkMap, exitNodeID tailcfg.StableNodeID)
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
if p.StableID != exitNodeID {
|
if p.StableID == exitNodeID && peerCanProxyDNS(p) {
|
||||||
continue
|
return peerAPIBase(nm, p) + "/dns-query", true
|
||||||
}
|
|
||||||
services := p.Hostinfo.Services()
|
|
||||||
for i, n := 0, services.Len(); i < n; i++ {
|
|
||||||
s := services.At(i)
|
|
||||||
if s.Proto == tailcfg.PeerAPIDNS && s.Port >= 1 {
|
|
||||||
return peerAPIBase(nm, p) + "/dns-query", true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func peerCanProxyDNS(p *tailcfg.Node) bool {
|
||||||
|
if p.Cap >= 26 {
|
||||||
|
// Actually added at 25
|
||||||
|
// (https://github.com/tailscale/tailscale/blob/3ae6f898cfdb58fd0e30937147dd6ce28c6808dd/tailcfg/tailcfg.go#L51)
|
||||||
|
// so anything >= 26 can do it.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If p.Cap is not populated (e.g. older control server), then do the old
|
||||||
|
// thing of searching through services.
|
||||||
|
services := p.Hostinfo.Services()
|
||||||
|
for i, n := 0, services.Len(); i < n; i++ {
|
||||||
|
s := services.At(i)
|
||||||
|
if s.Proto == tailcfg.PeerAPIDNS && s.Port >= 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) DebugRebind() error {
|
func (b *LocalBackend) DebugRebind() error {
|
||||||
mc, err := b.magicConn()
|
mc, err := b.magicConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -155,6 +155,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Tailscale-Version", version.Long)
|
w.Header().Set("Tailscale-Version", version.Long)
|
||||||
|
w.Header().Set("Tailscale-Cap", strconv.Itoa(int(tailcfg.CurrentCapabilityVersion)))
|
||||||
w.Header().Set("Content-Security-Policy", `default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'`)
|
w.Header().Set("Content-Security-Policy", `default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'`)
|
||||||
w.Header().Set("X-Frame-Options", "DENY")
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
@ -29,7 +29,8 @@ import (
|
|||||||
// single monotonically increasing integer, rather than the relatively
|
// single monotonically increasing integer, rather than the relatively
|
||||||
// complex x.y.z-xxxxx semver+hash(es). Whenever the client gains a
|
// complex x.y.z-xxxxx semver+hash(es). Whenever the client gains a
|
||||||
// capability or wants to negotiate a change in semantics with the
|
// capability or wants to negotiate a change in semantics with the
|
||||||
// server (control plane), bump this number and document what's new.
|
// server (control plane), peers (over PeerAPI), or frontend (over
|
||||||
|
// LocalAPI), bump this number and document what's new.
|
||||||
//
|
//
|
||||||
// Previously (prior to 2022-03-06), it was known as the "MapRequest
|
// Previously (prior to 2022-03-06), it was known as the "MapRequest
|
||||||
// version" or "mapVer" or "map cap" and that name and usage persists
|
// version" or "mapVer" or "map cap" and that name and usage persists
|
||||||
@ -90,7 +91,8 @@ type CapabilityVersion int
|
|||||||
// - 51: 2022-11-30: Client understands CapabilityTailnetLockAlpha
|
// - 51: 2022-11-30: Client understands CapabilityTailnetLockAlpha
|
||||||
// - 52: 2023-01-05: client can handle c2n POST /logtail/flush
|
// - 52: 2023-01-05: client can handle c2n POST /logtail/flush
|
||||||
// - 53: 2023-01-18: client respects explicit Node.Expired + auto-sets based on Node.KeyExpiry
|
// - 53: 2023-01-18: client respects explicit Node.Expired + auto-sets based on Node.KeyExpiry
|
||||||
const CurrentCapabilityVersion CapabilityVersion = 53
|
// - 54: 2023-01-19: Node.Cap added, PeersChangedPatch.Cap, uses Node.Cap for ExitDNS before Hostinfo.Services fallback
|
||||||
|
const CurrentCapabilityVersion CapabilityVersion = 54
|
||||||
|
|
||||||
type StableID string
|
type StableID string
|
||||||
|
|
||||||
@ -199,6 +201,7 @@ type Node struct {
|
|||||||
DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
|
DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
|
||||||
Hostinfo HostinfoView
|
Hostinfo HostinfoView
|
||||||
Created time.Time
|
Created time.Time
|
||||||
|
Cap CapabilityVersion `json:",omitempty"` // if non-zero, the node's capability version; old servers might not send
|
||||||
|
|
||||||
// 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
|
||||||
@ -1627,6 +1630,7 @@ func (n *Node) Equal(n2 *Node) bool {
|
|||||||
eqCIDRs(n.PrimaryRoutes, n2.PrimaryRoutes) &&
|
eqCIDRs(n.PrimaryRoutes, n2.PrimaryRoutes) &&
|
||||||
eqStrings(n.Endpoints, n2.Endpoints) &&
|
eqStrings(n.Endpoints, n2.Endpoints) &&
|
||||||
n.DERP == n2.DERP &&
|
n.DERP == n2.DERP &&
|
||||||
|
n.Cap == n2.Cap &&
|
||||||
n.Hostinfo.Equal(n2.Hostinfo) &&
|
n.Hostinfo.Equal(n2.Hostinfo) &&
|
||||||
n.Created.Equal(n2.Created) &&
|
n.Created.Equal(n2.Created) &&
|
||||||
eqTimePtr(n.LastSeen, n2.LastSeen) &&
|
eqTimePtr(n.LastSeen, n2.LastSeen) &&
|
||||||
@ -2001,6 +2005,9 @@ type PeerChange struct {
|
|||||||
// region ID is now this number.
|
// region ID is now this number.
|
||||||
DERPRegion int `json:",omitempty"`
|
DERPRegion int `json:",omitempty"`
|
||||||
|
|
||||||
|
// Cap, if non-zero, means that NodeID's capability version has changed.
|
||||||
|
Cap CapabilityVersion `json:",omitempty"`
|
||||||
|
|
||||||
// Endpoints, if non-empty, means that NodeID's UDP Endpoints
|
// Endpoints, if non-empty, means that NodeID's UDP Endpoints
|
||||||
// have changed to these.
|
// have changed to these.
|
||||||
Endpoints []string `json:",omitempty"`
|
Endpoints []string `json:",omitempty"`
|
||||||
|
@ -85,6 +85,7 @@ var _NodeCloneNeedsRegeneration = Node(struct {
|
|||||||
DERP string
|
DERP string
|
||||||
Hostinfo HostinfoView
|
Hostinfo HostinfoView
|
||||||
Created time.Time
|
Created time.Time
|
||||||
|
Cap CapabilityVersion
|
||||||
Tags []string
|
Tags []string
|
||||||
PrimaryRoutes []netip.Prefix
|
PrimaryRoutes []netip.Prefix
|
||||||
LastSeen *time.Time
|
LastSeen *time.Time
|
||||||
|
@ -329,7 +329,7 @@ func TestNodeEqual(t *testing.T) {
|
|||||||
"ID", "StableID", "Name", "User", "Sharer",
|
"ID", "StableID", "Name", "User", "Sharer",
|
||||||
"Key", "KeyExpiry", "KeySignature", "Machine", "DiscoKey",
|
"Key", "KeyExpiry", "KeySignature", "Machine", "DiscoKey",
|
||||||
"Addresses", "AllowedIPs", "Endpoints", "DERP", "Hostinfo",
|
"Addresses", "AllowedIPs", "Endpoints", "DERP", "Hostinfo",
|
||||||
"Created", "Tags", "PrimaryRoutes",
|
"Created", "Cap", "Tags", "PrimaryRoutes",
|
||||||
"LastSeen", "Online", "KeepAlive", "MachineAuthorized",
|
"LastSeen", "Online", "KeepAlive", "MachineAuthorized",
|
||||||
"Capabilities",
|
"Capabilities",
|
||||||
"UnsignedPeerAPIOnly",
|
"UnsignedPeerAPIOnly",
|
||||||
|
@ -148,6 +148,7 @@ func (v NodeView) Endpoints() views.Slice[string] { return views.SliceOf(v.ж.E
|
|||||||
func (v NodeView) DERP() string { return v.ж.DERP }
|
func (v NodeView) DERP() string { return v.ж.DERP }
|
||||||
func (v NodeView) Hostinfo() HostinfoView { return v.ж.Hostinfo }
|
func (v NodeView) Hostinfo() HostinfoView { return v.ж.Hostinfo }
|
||||||
func (v NodeView) Created() time.Time { return v.ж.Created }
|
func (v NodeView) Created() time.Time { return v.ж.Created }
|
||||||
|
func (v NodeView) Cap() CapabilityVersion { return v.ж.Cap }
|
||||||
func (v NodeView) Tags() views.Slice[string] { return views.SliceOf(v.ж.Tags) }
|
func (v NodeView) Tags() views.Slice[string] { return views.SliceOf(v.ж.Tags) }
|
||||||
func (v NodeView) PrimaryRoutes() views.IPPrefixSlice {
|
func (v NodeView) PrimaryRoutes() views.IPPrefixSlice {
|
||||||
return views.IPPrefixSliceOf(v.ж.PrimaryRoutes)
|
return views.IPPrefixSliceOf(v.ж.PrimaryRoutes)
|
||||||
@ -196,6 +197,7 @@ var _NodeViewNeedsRegeneration = Node(struct {
|
|||||||
DERP string
|
DERP string
|
||||||
Hostinfo HostinfoView
|
Hostinfo HostinfoView
|
||||||
Created time.Time
|
Created time.Time
|
||||||
|
Cap CapabilityVersion
|
||||||
Tags []string
|
Tags []string
|
||||||
PrimaryRoutes []netip.Prefix
|
PrimaryRoutes []netip.Prefix
|
||||||
LastSeen *time.Time
|
LastSeen *time.Time
|
||||||
|
@ -574,9 +574,10 @@ func TestGetTypeHasher(t *testing.T) {
|
|||||||
out: "\x01\x01\x00\x00\x00\x02\x00\x00\x00\x03\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\a\b\x00\x00\x00",
|
out: "\x01\x01\x00\x00\x00\x02\x00\x00\x00\x03\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\a\b\x00\x00\x00",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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\x00\tn\x88\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tn\x88\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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\x00\tn\x88\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tn\x88\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
|
out32: "\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\x00\tn\x88\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tn\x88\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user