Get a map of IP addresses for devices in my tailnet
Use tailscale status --json and filter the output using jq.
Here’s a jq snippet that prints the hostname and IP addresses of every device in my tailnet (or at least, every device my current machine can see):
$ tailscale status --json \
| jq '[.Self] + [.Peer[]]
| sort_by(.DNSName)
| map({(.DNSName): (.TailscaleIPs)})
| add'
{
"phaenna-mac-mini.tailfa84dd.ts.net.": [
"100.76.19.1",
"fd7a:115c:a1e0::fb01:1301"
],
…
}How it works:
[.Self] + [.Peer[]]combines the.Selfobject and.Peerarray into a single array.sort_by(.DNSName)sorts the array based on theDNSNamefield.map({(.DNSName): (.TailscaleIPs)})converts each entry in that array into a map where theDNSNameis the key, and theTailscaleIPsarray is the value. Now the output is an array of objects, each with a single key-value pair.addcombines all those objects into a single object.
Here’s a variant that keys the map by MagicDNS name:
$ tailscale status --json \
| jq '[.Self] + [.Peer[]]
| sort_by(.DNSName)
| map({(.DNSName | split(".")[0]): (.TailscaleIPs)})
| add'
{
"phaenna-mac-mini": [
"100.76.19.1",
"fd7a:115c:a1e0::fb01:1301"
],
…
}Another variant that just extracts the IPv4 address:
$ tailscale status --json \
| jq '[.Self] + [.Peer[]]
| sort_by(.DNSName)
| map({(.DNSName | split(".")[0]): (.TailscaleIPs[0])})
| add'
{
"linode-vps": "100.98.193.6",
"palaemon-macbook-air": "100.120.194.127",
"phaenna-mac-mini": "100.76.19.1",
…
}I paste this directly into the hosts section of my policy file.
If you have Mullvad nodes in your Tailnet, you can filter them out of this map with:
$ tailscale status --json \
| jq '[.Self] + [.Peer[]]
| map(select(.Tags == null or (.Tags | contains(["tag:mullvad-exit-node"]) | not)))
| sort_by(.DNSName)
| map({(.DNSName | split(".")[0]): (.TailscaleIPs[0])})
| add'
{
"linode-vps": "100.98.193.6",
"palaemon-macbook-air": "100.120.194.127",
"phaenna-mac-mini": "100.76.19.1",
…
}Tested with Tailscale 1.95.104. Disclaimer: At time of writing, I’m employed by Tailscale.