Browse Source

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 <[email protected]>
Brad Fitzpatrick 4 years ago
parent
commit
10d7c2583c

+ 2 - 2
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+

+ 179 - 0
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"
+				}
+			]
+		}
+	}
+}

+ 24 - 2
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

+ 17 - 0
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")
+	}
+}

+ 47 - 0
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)
+	}
+}