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 <bradfitz@tailscale.com>
pull/2262/head
Brad Fitzpatrick 3 years ago
parent 194d5b8412
commit 10d7c2583c

@ -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/control/controlclient from tailscale.com/ipn/ipnlocal+
tailscale.com/derp from tailscale.com/derp/derphttp+ tailscale.com/derp from tailscale.com/derp/derphttp+
tailscale.com/derp/derphttp from tailscale.com/net/netcheck+ 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/disco from tailscale.com/derp+
tailscale.com/health from tailscale.com/control/controlclient+ tailscale.com/health from tailscale.com/control/controlclient+
tailscale.com/hostinfo 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/elf from rsc.io/goversion/version
debug/macho from rsc.io/goversion/version debug/macho from rsc.io/goversion/version
debug/pe 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 from encoding/json+
encoding/asn1 from crypto/x509+ encoding/asn1 from crypto/x509+
encoding/base64 from encoding/json+ encoding/base64 from encoding/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"
}
]
}
}
}

@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:generate go run update-dns-fallbacks.go
// Package dnsfallback contains a DNS fallback mechanism // Package dnsfallback contains a DNS fallback mechanism
// for starting up Tailscale when the system DNS is broken or otherwise unavailable. // for starting up Tailscale when the system DNS is broken or otherwise unavailable.
package dnsfallback package dnsfallback
import ( import (
"context" "context"
_ "embed"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -19,9 +22,9 @@ import (
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/derp/derpmap"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/tshttpproxy" "tailscale.com/net/tshttpproxy"
"tailscale.com/tailcfg"
) )
func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) { 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 ip netaddr.IP
} }
dm := derpmap.Prod() dm := getDERPMap()
var cands4, cands6 []nameIP var cands4, cands6 []nameIP
for _, dr := range dm.Regions { for _, dr := range dm.Regions {
for _, n := range dr.Nodes { 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: // dnsMap is the JSON type returned by the DERP /bootstrap-dns handler:
// https://derp10.tailscale.com/bootstrap-dns // https://derp10.tailscale.com/bootstrap-dns
type dnsMap map[string][]netaddr.IP 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

@ -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")
}
}

@ -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)
}
}
Loading…
Cancel
Save