Skip to content

Instantly share code, notes, and snippets.

@holmeszyx
Created September 27, 2025 10:29
Show Gist options
  • Select an option

  • Save holmeszyx/83f8edfd7bb683de00226a1e338227d8 to your computer and use it in GitHub Desktop.

Select an option

Save holmeszyx/83f8edfd7bb683de00226a1e338227d8 to your computer and use it in GitHub Desktop.
dump tailscale derp rule-set
import json
import urllib.error
import urllib.request
url = "https://login.tailscale.com/derpmap/default"
try:
with urllib.request.urlopen(url) as response:
charset = response.headers.get_content_charset()
if charset is None:
charset = "utf-8"
payload = response.read().decode(charset)
except urllib.error.URLError as e:
print(f"URLError: {e}")
raise e
data = json.loads(payload)
domains = []
seen_domains = set()
ipv4s = []
seen_ipv4s = set()
ipv6s = []
seen_ipv6s = set()
for region in data["Regions"].values():
for node in region["Nodes"]:
domain = node["HostName"]
if domain not in seen_domains:
domains.append(domain)
seen_domains.add(domain)
ipv4 = node["IPv4"]
if ipv4 not in seen_ipv4s:
ipv4s.append(ipv4)
seen_ipv4s.add(ipv4)
ipv6 = node["IPv6"]
if ipv6 not in seen_ipv6s:
ipv6s.append(ipv6)
seen_ipv6s.add(ipv6)
with open("./derp.json", "w", buffering=1, encoding="utf-8") as derp_json:
json.dump(data, derp_json, indent=2)
with open("./derp.list", "w", buffering=1, encoding="utf-8") as derp_file:
derp_file.write("# Rule list of tailscale derpers\n")
for domain in domains:
derp_file.write(f"DOMAIN,{domain}\n")
derp_file.write("# IPV4\n")
for ipv4 in ipv4s:
derp_file.write(f"IP-CIDR,{ipv4}/32,no-resolve\n")
derp_file.write("# IPV6\n")
for ipv6 in ipv6s:
derp_file.write(f"IP-CIDR6,{ipv6}/128,no-resolve\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment