From 10d7c2583ca5615145fc53d634d22cebd617f31b Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 27 Jun 2021 20:40:24 -0700 Subject: [PATCH] net/dnsfallback: don't depend on derpmap.Prod Move derpmap.Prod to a static JSON file (go:generate'd) instead, to make its role explicit. And add a TODO about making dnsfallback use an update-over-time DERP map file instead of a baked-in one. Updates #1264 Signed-off-by: Brad Fitzpatrick --- cmd/tailscaled/depaware.txt | 4 +- net/dnsfallback/dns-fallback-servers.json | 179 ++++++++++++++++++++++ net/dnsfallback/dnsfallback.go | 26 +++- net/dnsfallback/dnsfallback_test.go | 17 ++ net/dnsfallback/update-dns-fallbacks.go | 47 ++++++ 5 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 net/dnsfallback/dns-fallback-servers.json create mode 100644 net/dnsfallback/dnsfallback_test.go create mode 100644 net/dnsfallback/update-dns-fallbacks.go diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 8df69157c..e9631c21d 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -81,7 +81,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/control/controlclient from tailscale.com/ipn/ipnlocal+ tailscale.com/derp from tailscale.com/derp/derphttp+ tailscale.com/derp/derphttp from tailscale.com/net/netcheck+ - tailscale.com/derp/derpmap from tailscale.com/cmd/tailscaled+ + tailscale.com/derp/derpmap from tailscale.com/cmd/tailscaled tailscale.com/disco from tailscale.com/derp+ tailscale.com/health from tailscale.com/control/controlclient+ tailscale.com/hostinfo from tailscale.com/control/controlclient+ @@ -228,7 +228,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de debug/elf from rsc.io/goversion/version debug/macho from rsc.io/goversion/version debug/pe from rsc.io/goversion/version - L embed from tailscale.com/net/dns + embed from tailscale.com/net/dns+ encoding from encoding/json+ encoding/asn1 from crypto/x509+ encoding/base64 from encoding/json+ diff --git a/net/dnsfallback/dns-fallback-servers.json b/net/dnsfallback/dns-fallback-servers.json new file mode 100644 index 000000000..6df4c7c8a --- /dev/null +++ b/net/dnsfallback/dns-fallback-servers.json @@ -0,0 +1,179 @@ +{ + "Regions": { + "1": { + "RegionID": 1, + "RegionCode": "r1", + "RegionName": "r1", + "Nodes": [ + { + "Name": "1a", + "RegionID": 1, + "HostName": "derp1.tailscale.com", + "IPv4": "159.89.225.99", + "IPv6": "2604:a880:400:d1::828:b001" + }, + { + "Name": "1b", + "RegionID": 1, + "HostName": "derp1b.tailscale.com", + "IPv4": "45.55.35.93", + "IPv6": "2604:a880:800:a1::f:2001" + } + ] + }, + "10": { + "RegionID": 10, + "RegionCode": "r10", + "RegionName": "r10", + "Nodes": [ + { + "Name": "10a", + "RegionID": 10, + "HostName": "derp10.tailscale.com", + "IPv4": "137.220.36.168", + "IPv6": "2001:19f0:8001:2d9:5400:2ff:feef:bbb1" + } + ] + }, + "11": { + "RegionID": 11, + "RegionCode": "r11", + "RegionName": "r11", + "Nodes": [ + { + "Name": "11a", + "RegionID": 11, + "HostName": "derp11.tailscale.com", + "IPv4": "18.230.97.74", + "IPv6": "2600:1f1e:ee4:5611:ec5c:1736:d43b:a454" + } + ] + }, + "2": { + "RegionID": 2, + "RegionCode": "r2", + "RegionName": "r2", + "Nodes": [ + { + "Name": "2a", + "RegionID": 2, + "HostName": "derp2.tailscale.com", + "IPv4": "167.172.206.31", + "IPv6": "2604:a880:2:d1::c5:7001" + }, + { + "Name": "2b", + "RegionID": 2, + "HostName": "derp2b.tailscale.com", + "IPv4": "64.227.106.23", + "IPv6": "2604:a880:4:1d0::29:9000" + } + ] + }, + "3": { + "RegionID": 3, + "RegionCode": "r3", + "RegionName": "r3", + "Nodes": [ + { + "Name": "3a", + "RegionID": 3, + "HostName": "derp3.tailscale.com", + "IPv4": "68.183.179.66", + "IPv6": "2400:6180:0:d1::67d:8001" + } + ] + }, + "4": { + "RegionID": 4, + "RegionCode": "r4", + "RegionName": "r4", + "Nodes": [ + { + "Name": "4a", + "RegionID": 4, + "HostName": "derp4.tailscale.com", + "IPv4": "167.172.182.26", + "IPv6": "2a03:b0c0:3:e0::36e:9001" + }, + { + "Name": "4b", + "RegionID": 4, + "HostName": "derp4b.tailscale.com", + "IPv4": "157.230.25.0", + "IPv6": "2a03:b0c0:3:e0::58f:3001" + } + ] + }, + "5": { + "RegionID": 5, + "RegionCode": "r5", + "RegionName": "r5", + "Nodes": [ + { + "Name": "5a", + "RegionID": 5, + "HostName": "derp5.tailscale.com", + "IPv4": "103.43.75.49", + "IPv6": "2001:19f0:5801:10b7:5400:2ff:feaa:284c" + } + ] + }, + "6": { + "RegionID": 6, + "RegionCode": "r6", + "RegionName": "r6", + "Nodes": [ + { + "Name": "6a", + "RegionID": 6, + "HostName": "derp6.tailscale.com", + "IPv4": "68.183.90.120", + "IPv6": "2400:6180:100:d0::982:d001" + } + ] + }, + "7": { + "RegionID": 7, + "RegionCode": "r7", + "RegionName": "r7", + "Nodes": [ + { + "Name": "7a", + "RegionID": 7, + "HostName": "derp7.tailscale.com", + "IPv4": "167.179.89.145", + "IPv6": "2401:c080:1000:467f:5400:2ff:feee:22aa" + } + ] + }, + "8": { + "RegionID": 8, + "RegionCode": "r8", + "RegionName": "r8", + "Nodes": [ + { + "Name": "8a", + "RegionID": 8, + "HostName": "derp8.tailscale.com", + "IPv4": "167.71.139.179", + "IPv6": "2a03:b0c0:1:e0::3cc:e001" + } + ] + }, + "9": { + "RegionID": 9, + "RegionCode": "r9", + "RegionName": "r9", + "Nodes": [ + { + "Name": "9a", + "RegionID": 9, + "HostName": "derp9.tailscale.com", + "IPv4": "207.148.3.137", + "IPv6": "2001:19f0:6401:1d9c:5400:2ff:feef:bb82" + } + ] + } + } +} \ No newline at end of file diff --git a/net/dnsfallback/dnsfallback.go b/net/dnsfallback/dnsfallback.go index c71cb16ba..ec20279aa 100644 --- a/net/dnsfallback/dnsfallback.go +++ b/net/dnsfallback/dnsfallback.go @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go run update-dns-fallbacks.go + // Package dnsfallback contains a DNS fallback mechanism // for starting up Tailscale when the system DNS is broken or otherwise unavailable. package dnsfallback import ( "context" + _ "embed" "encoding/json" "errors" "fmt" @@ -19,9 +22,9 @@ import ( "time" "inet.af/netaddr" - "tailscale.com/derp/derpmap" "tailscale.com/net/netns" "tailscale.com/net/tshttpproxy" + "tailscale.com/tailcfg" ) func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) { @@ -30,7 +33,7 @@ func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) { ip netaddr.IP } - dm := derpmap.Prod() + dm := getDERPMap() var cands4, cands6 []nameIP for _, dr := range dm.Regions { for _, n := range dr.Nodes { @@ -115,3 +118,22 @@ func bootstrapDNSMap(ctx context.Context, serverName string, serverIP netaddr.IP // dnsMap is the JSON type returned by the DERP /bootstrap-dns handler: // https://derp10.tailscale.com/bootstrap-dns type dnsMap map[string][]netaddr.IP + +// getDERPMap returns some DERP map. The DERP servers also run a fallback +// DNS server. +func getDERPMap() *tailcfg.DERPMap { + // TODO(bradfitz): try to read the last known DERP map from disk, + // at say /var/lib/tailscale/derpmap.txt and write it when it changes, + // and read it here. + // But ultimately the fallback will be to use a copy baked into the binary, + // which is this part: + + dm := new(tailcfg.DERPMap) + if err := json.Unmarshal(staticDERPMapJSON, dm); err != nil { + panic(err) + } + return dm +} + +//go:embed dns-fallback-servers.json +var staticDERPMapJSON []byte diff --git a/net/dnsfallback/dnsfallback_test.go b/net/dnsfallback/dnsfallback_test.go new file mode 100644 index 000000000..4878489f1 --- /dev/null +++ b/net/dnsfallback/dnsfallback_test.go @@ -0,0 +1,17 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dnsfallback + +import "testing" + +func TestGetDERPMap(t *testing.T) { + dm := getDERPMap() + if dm == nil { + t.Fatal("nil") + } + if len(dm.Regions) == 0 { + t.Fatal("no regions") + } +} diff --git a/net/dnsfallback/update-dns-fallbacks.go b/net/dnsfallback/update-dns-fallbacks.go new file mode 100644 index 000000000..c24d967bd --- /dev/null +++ b/net/dnsfallback/update-dns-fallbacks.go @@ -0,0 +1,47 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + + "tailscale.com/tailcfg" +) + +func main() { + res, err := http.Get("https://login.tailscale.com/derpmap/default") + if err != nil { + log.Fatal(err) + } + if res.StatusCode != 200 { + res.Write(os.Stderr) + os.Exit(1) + } + dm := new(tailcfg.DERPMap) + if err := json.NewDecoder(res.Body).Decode(dm); err != nil { + log.Fatal(err) + } + for rid, r := range dm.Regions { + // Names misleading to check into git, as this is a + // static snapshot and doesn't reflect the live DERP + // map. + r.RegionCode = fmt.Sprintf("r%d", rid) + r.RegionName = r.RegionCode + } + out, err := json.MarshalIndent(dm, "", "\t") + if err != nil { + log.Fatal(err) + } + if err := ioutil.WriteFile("dns-fallback-servers.json", out, 0644); err != nil { + log.Fatal(err) + } +}