headscale/hscontrol/mapper/tail.go
Kristoffer Dalby 8b92c017ec
Some checks are pending
Build / build-cross (GOARCH=386 GOOS=linux) (push) Waiting to run
Build / build-cross (GOARCH=amd64 GOOS=darwin) (push) Waiting to run
Build / build-nix (push) Waiting to run
Build / build-cross (GOARCH=amd64 GOOS=linux) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=5) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=6) (push) Waiting to run
Build / build-cross (GOARCH=arm GOOS=linux GOARM=7) (push) Waiting to run
Build / build-cross (GOARCH=arm64 GOOS=darwin) (push) Waiting to run
Build / build-cross (GOARCH=arm64 GOOS=linux) (push) Waiting to run
Tests / test (push) Waiting to run
add 1.80 to capver and update deps (#2394)
2025-02-05 07:17:51 +01:00

140 lines
3.3 KiB
Go

package mapper
import (
"fmt"
"net/netip"
"time"
"github.com/juanfont/headscale/hscontrol/policy"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/samber/lo"
"tailscale.com/tailcfg"
)
func tailNodes(
nodes types.Nodes,
capVer tailcfg.CapabilityVersion,
polMan policy.PolicyManager,
cfg *types.Config,
) ([]*tailcfg.Node, error) {
tNodes := make([]*tailcfg.Node, len(nodes))
for index, node := range nodes {
node, err := tailNode(
node,
capVer,
polMan,
cfg,
)
if err != nil {
return nil, err
}
tNodes[index] = node
}
return tNodes, nil
}
// tailNode converts a Node into a Tailscale Node.
func tailNode(
node *types.Node,
capVer tailcfg.CapabilityVersion,
polMan policy.PolicyManager,
cfg *types.Config,
) (*tailcfg.Node, error) {
addrs := node.Prefixes()
allowedIPs := append(
[]netip.Prefix{},
addrs...) // we append the node own IP, as it is required by the clients
primaryPrefixes := []netip.Prefix{}
for _, route := range node.Routes {
if route.Enabled {
if route.IsPrimary {
allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix))
primaryPrefixes = append(primaryPrefixes, netip.Prefix(route.Prefix))
} else if route.IsExitRoute() {
allowedIPs = append(allowedIPs, netip.Prefix(route.Prefix))
}
}
}
var derp int
// TODO(kradalby): legacyDERP was removed in tailscale/tailscale@2fc4455e6dd9ab7f879d4e2f7cffc2be81f14077
// and should be removed after 111 is the minimum capver.
var legacyDERP string
if node.Hostinfo != nil && node.Hostinfo.NetInfo != nil {
legacyDERP = fmt.Sprintf("127.3.3.40:%d", node.Hostinfo.NetInfo.PreferredDERP)
derp = node.Hostinfo.NetInfo.PreferredDERP
} else {
legacyDERP = "127.3.3.40:0" // Zero means disconnected or unknown.
}
var keyExpiry time.Time
if node.Expiry != nil {
keyExpiry = *node.Expiry
} else {
keyExpiry = time.Time{}
}
hostname, err := node.GetFQDN(cfg.BaseDomain)
if err != nil {
return nil, fmt.Errorf("tailNode, failed to create FQDN: %s", err)
}
tags := polMan.Tags(node)
tags = lo.Uniq(append(tags, node.ForcedTags...))
tNode := tailcfg.Node{
ID: tailcfg.NodeID(node.ID), // this is the actual ID
StableID: node.ID.StableID(),
Name: hostname,
Cap: capVer,
User: tailcfg.UserID(node.UserID),
Key: node.NodeKey,
KeyExpiry: keyExpiry.UTC(),
Machine: node.MachineKey,
DiscoKey: node.DiscoKey,
Addresses: addrs,
AllowedIPs: allowedIPs,
Endpoints: node.Endpoints,
HomeDERP: derp,
LegacyDERPString: legacyDERP,
Hostinfo: node.Hostinfo.View(),
Created: node.CreatedAt.UTC(),
Online: node.IsOnline,
Tags: tags,
PrimaryRoutes: primaryPrefixes,
MachineAuthorized: !node.IsExpired(),
Expired: node.IsExpired(),
}
tNode.CapMap = tailcfg.NodeCapMap{
tailcfg.CapabilityFileSharing: []tailcfg.RawMessage{},
tailcfg.CapabilityAdmin: []tailcfg.RawMessage{},
tailcfg.CapabilitySSH: []tailcfg.RawMessage{},
}
if cfg.RandomizeClientPort {
tNode.CapMap[tailcfg.NodeAttrRandomizeClientPort] = []tailcfg.RawMessage{}
}
if node.IsOnline == nil || !*node.IsOnline {
// LastSeen is only set when node is
// not connected to the control server.
tNode.LastSeen = node.LastSeen
}
return &tNode, nil
}