2023-05-31 15:59:37 +08:00
|
|
|
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(
|
2023-09-24 19:42:05 +08:00
|
|
|
nodes types.Nodes,
|
2023-09-29 03:33:53 +08:00
|
|
|
capVer tailcfg.CapabilityVersion,
|
2023-05-31 15:59:37 +08:00
|
|
|
pol *policy.ACLPolicy,
|
2024-02-23 17:59:24 +08:00
|
|
|
cfg *types.Config,
|
2023-05-31 15:59:37 +08:00
|
|
|
) ([]*tailcfg.Node, error) {
|
2023-09-24 19:42:05 +08:00
|
|
|
tNodes := make([]*tailcfg.Node, len(nodes))
|
2023-05-31 15:59:37 +08:00
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
for index, node := range nodes {
|
2023-05-31 15:59:37 +08:00
|
|
|
node, err := tailNode(
|
2023-09-24 19:42:05 +08:00
|
|
|
node,
|
2023-09-29 03:33:53 +08:00
|
|
|
capVer,
|
2023-05-31 15:59:37 +08:00
|
|
|
pol,
|
2024-02-23 17:59:24 +08:00
|
|
|
cfg,
|
2023-05-31 15:59:37 +08:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
tNodes[index] = node
|
2023-05-31 15:59:37 +08:00
|
|
|
}
|
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
return tNodes, nil
|
2023-05-31 15:59:37 +08:00
|
|
|
}
|
|
|
|
|
2024-08-19 17:41:05 +08:00
|
|
|
// tailNode converts a Node into a Tailscale Node.
|
2023-05-31 15:59:37 +08:00
|
|
|
func tailNode(
|
2023-09-24 19:42:05 +08:00
|
|
|
node *types.Node,
|
2023-09-29 03:33:53 +08:00
|
|
|
capVer tailcfg.CapabilityVersion,
|
2023-05-31 15:59:37 +08:00
|
|
|
pol *policy.ACLPolicy,
|
2024-02-23 17:59:24 +08:00
|
|
|
cfg *types.Config,
|
2023-05-31 15:59:37 +08:00
|
|
|
) (*tailcfg.Node, error) {
|
2024-04-17 13:03:06 +08:00
|
|
|
addrs := node.Prefixes()
|
2023-05-31 15:59:37 +08:00
|
|
|
|
|
|
|
allowedIPs := append(
|
|
|
|
[]netip.Prefix{},
|
|
|
|
addrs...) // we append the node own IP, as it is required by the clients
|
|
|
|
|
|
|
|
primaryPrefixes := []netip.Prefix{}
|
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
for _, route := range node.Routes {
|
2023-05-31 15:59:37 +08:00
|
|
|
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 string
|
2024-02-09 00:28:19 +08:00
|
|
|
if node.Hostinfo != nil && node.Hostinfo.NetInfo != nil {
|
2023-11-22 01:20:06 +08:00
|
|
|
derp = fmt.Sprintf("127.3.3.40:%d", node.Hostinfo.NetInfo.PreferredDERP)
|
2023-05-31 15:59:37 +08:00
|
|
|
} else {
|
|
|
|
derp = "127.3.3.40:0" // Zero means disconnected or unknown.
|
|
|
|
}
|
|
|
|
|
|
|
|
var keyExpiry time.Time
|
2023-09-24 19:42:05 +08:00
|
|
|
if node.Expiry != nil {
|
|
|
|
keyExpiry = *node.Expiry
|
2023-05-31 15:59:37 +08:00
|
|
|
} else {
|
|
|
|
keyExpiry = time.Time{}
|
|
|
|
}
|
|
|
|
|
2024-06-26 19:44:40 +08:00
|
|
|
hostname, err := node.GetFQDN(cfg, cfg.BaseDomain)
|
2023-05-31 15:59:37 +08:00
|
|
|
if err != nil {
|
2023-12-10 01:09:24 +08:00
|
|
|
return nil, fmt.Errorf("tailNode, failed to create FQDN: %s", err)
|
2023-05-31 15:59:37 +08:00
|
|
|
}
|
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
tags, _ := pol.TagsOfNode(node)
|
|
|
|
tags = lo.Uniq(append(tags, node.ForcedTags...))
|
2023-05-31 15:59:37 +08:00
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
tNode := tailcfg.Node{
|
2024-02-23 17:59:24 +08:00
|
|
|
ID: tailcfg.NodeID(node.ID), // this is the actual ID
|
|
|
|
StableID: node.ID.StableID(),
|
|
|
|
Name: hostname,
|
|
|
|
Cap: capVer,
|
2023-05-31 15:59:37 +08:00
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
User: tailcfg.UserID(node.UserID),
|
2023-05-31 15:59:37 +08:00
|
|
|
|
2023-11-20 05:37:04 +08:00
|
|
|
Key: node.NodeKey,
|
2024-09-03 15:22:17 +08:00
|
|
|
KeyExpiry: keyExpiry.UTC(),
|
2023-05-31 15:59:37 +08:00
|
|
|
|
2023-11-20 05:37:04 +08:00
|
|
|
Machine: node.MachineKey,
|
|
|
|
DiscoKey: node.DiscoKey,
|
2023-05-31 15:59:37 +08:00
|
|
|
Addresses: addrs,
|
|
|
|
AllowedIPs: allowedIPs,
|
2023-11-22 01:20:06 +08:00
|
|
|
Endpoints: node.Endpoints,
|
2023-05-31 15:59:37 +08:00
|
|
|
DERP: derp,
|
2023-11-22 01:20:06 +08:00
|
|
|
Hostinfo: node.Hostinfo.View(),
|
2024-09-03 15:22:17 +08:00
|
|
|
Created: node.CreatedAt.UTC(),
|
2023-05-31 15:59:37 +08:00
|
|
|
|
2023-12-10 01:09:24 +08:00
|
|
|
Online: node.IsOnline,
|
|
|
|
|
2023-05-31 15:59:37 +08:00
|
|
|
Tags: tags,
|
|
|
|
|
|
|
|
PrimaryRoutes: primaryPrefixes,
|
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
MachineAuthorized: !node.IsExpired(),
|
2023-12-10 01:09:24 +08:00
|
|
|
Expired: node.IsExpired(),
|
2023-09-29 03:33:53 +08:00
|
|
|
}
|
|
|
|
|
2024-09-25 00:34:20 +08:00
|
|
|
tNode.CapMap = tailcfg.NodeCapMap{
|
|
|
|
tailcfg.CapabilityFileSharing: []tailcfg.RawMessage{},
|
|
|
|
tailcfg.CapabilityAdmin: []tailcfg.RawMessage{},
|
|
|
|
tailcfg.CapabilitySSH: []tailcfg.RawMessage{},
|
2023-09-29 03:33:53 +08:00
|
|
|
}
|
|
|
|
|
2024-09-25 00:34:20 +08:00
|
|
|
if cfg.RandomizeClientPort {
|
|
|
|
tNode.CapMap[tailcfg.NodeAttrRandomizeClientPort] = []tailcfg.RawMessage{}
|
2023-05-31 15:59:37 +08:00
|
|
|
}
|
|
|
|
|
2023-12-10 01:09:24 +08:00
|
|
|
if node.IsOnline == nil || !*node.IsOnline {
|
|
|
|
// LastSeen is only set when node is
|
|
|
|
// not connected to the control server.
|
|
|
|
tNode.LastSeen = node.LastSeen
|
|
|
|
}
|
|
|
|
|
2023-09-24 19:42:05 +08:00
|
|
|
return &tNode, nil
|
2023-05-31 15:59:37 +08:00
|
|
|
}
|