Fixes #153 Updates #162 Updates #163 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>main
parent
bd0e20f351
commit
39c0ae1dba
@ -0,0 +1,138 @@ |
||||
// Copyright (c) 2020 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 derpmap contains information about Tailscale.com's production DERP nodes.
|
||||
package derpmap |
||||
|
||||
import ( |
||||
"fmt" |
||||
) |
||||
|
||||
// World is a set of DERP server.
|
||||
type World struct { |
||||
servers []*Server |
||||
ids []int |
||||
byID map[int]*Server |
||||
stun4 []string |
||||
stun6 []string |
||||
} |
||||
|
||||
func (w *World) IDs() []int { return w.ids } |
||||
func (w *World) STUN4() []string { return w.stun4 } |
||||
func (w *World) STUN6() []string { return w.stun6 } |
||||
func (w *World) ServerByID(id int) *Server { return w.byID[id] } |
||||
|
||||
// LocationOfID returns the geographic name of a node, if present.
|
||||
func (w *World) LocationOfID(id int) string { |
||||
if s, ok := w.byID[id]; ok { |
||||
return s.Geo |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (w *World) NodeIDOfSTUNServer(server string) int { |
||||
// TODO: keep reverse map? Small enough to not matter for now.
|
||||
for _, s := range w.servers { |
||||
if s.STUN4 == server || s.STUN6 == server { |
||||
return s.ID |
||||
} |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// Prod returns the production DERP nodes.
|
||||
func Prod() *World { |
||||
return prod |
||||
} |
||||
|
||||
func NewTestWorld(stun ...string) *World { |
||||
w := &World{} |
||||
for i, s := range stun { |
||||
w.add(&Server{ |
||||
ID: i + 1, |
||||
Geo: fmt.Sprintf("Testopolis-%d", i+1), |
||||
STUN4: s, |
||||
}) |
||||
} |
||||
return w |
||||
} |
||||
|
||||
func NewTestWorldWith(servers ...*Server) *World { |
||||
w := &World{} |
||||
for _, s := range servers { |
||||
w.add(s) |
||||
} |
||||
return w |
||||
} |
||||
|
||||
var prod = new(World) // ... a dazzling place I never knew
|
||||
|
||||
func addProd(id int, geo string) { |
||||
prod.add(&Server{ |
||||
ID: id, |
||||
Geo: geo, |
||||
HostHTTPS: fmt.Sprintf("derp%v.tailscale.com", id), |
||||
STUN4: fmt.Sprintf("derp%v.tailscale.com:3478", id), |
||||
STUN6: fmt.Sprintf("derp%v-v6.tailscale.com:3478", id), |
||||
}) |
||||
} |
||||
|
||||
func (w *World) add(s *Server) { |
||||
if s.ID == 0 { |
||||
panic("ID required") |
||||
} |
||||
if _, dup := w.byID[s.ID]; dup { |
||||
panic("duplicate prod server") |
||||
} |
||||
if w.byID == nil { |
||||
w.byID = make(map[int]*Server) |
||||
} |
||||
w.byID[s.ID] = s |
||||
w.ids = append(w.ids, s.ID) |
||||
w.servers = append(w.servers, s) |
||||
if s.STUN4 != "" { |
||||
w.stun4 = append(w.stun4, s.STUN4) |
||||
} |
||||
if s.STUN6 != "" { |
||||
w.stun6 = append(w.stun6, s.STUN6) |
||||
} |
||||
} |
||||
|
||||
func init() { |
||||
addProd(1, "New York") |
||||
addProd(2, "San Francisco") |
||||
addProd(3, "Singapore") |
||||
addProd(4, "Frankfurt") |
||||
} |
||||
|
||||
// Server is configuration for a DERP server.
|
||||
type Server struct { |
||||
ID int |
||||
|
||||
// HostHTTPS is the HTTPS hostname.
|
||||
HostHTTPS string |
||||
|
||||
// STUN4 is the host:port of the IPv4 STUN server on this DERP
|
||||
// node. Required.
|
||||
STUN4 string |
||||
|
||||
// STUN6 optionally provides the IPv6 host:port of the STUN
|
||||
// server on the DERP node.
|
||||
// It should be an IPv6-only address for now. (We currently make lazy
|
||||
// assumptions that the server names are unique.)
|
||||
STUN6 string |
||||
|
||||
// Geo is a human-readable geographic region name of this server.
|
||||
Geo string |
||||
} |
||||
|
||||
func (s *Server) String() string { |
||||
if s == nil { |
||||
return "<nil *derpmap.Server>" |
||||
} |
||||
if s.Geo != "" { |
||||
return fmt.Sprintf("%v (%v)", s.HostHTTPS, s.Geo) |
||||
} |
||||
return s.HostHTTPS |
||||
} |
||||
@ -1,63 +0,0 @@ |
||||
// Copyright 2019 Tailscale & 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 magicsock |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net" |
||||
) |
||||
|
||||
// DerpMagicIP is a fake WireGuard endpoint IP address that means
|
||||
// to use DERP. When used, the port number of the WireGuard endpoint
|
||||
// is the DERP server number to use.
|
||||
//
|
||||
// Mnemonic: 3.3.40 are numbers above the keys D, E, R, P.
|
||||
const DerpMagicIP = "127.3.3.40" |
||||
|
||||
var derpMagicIP = net.ParseIP(DerpMagicIP).To4() |
||||
|
||||
var ( |
||||
derpHostOfIndex = map[int]string{} // node ID index (fake port number) -> hostname
|
||||
derpIndexOfHost = map[string]int{} // derpHostOfIndex reversed
|
||||
derpNodeID []int |
||||
) |
||||
|
||||
const ( |
||||
derpUSNY = 1 |
||||
derpUSSF = 2 |
||||
derpSG = 3 |
||||
derpDE = 4 |
||||
) |
||||
|
||||
func init() { |
||||
addDerper(derpUSNY, "derp1.tailscale.com") |
||||
addDerper(derpUSSF, "derp2.tailscale.com") |
||||
addDerper(derpSG, "derp3.tailscale.com") |
||||
addDerper(derpDE, "derp4.tailscale.com") |
||||
} |
||||
|
||||
func addDerper(i int, host string) { |
||||
if other, dup := derpHostOfIndex[i]; dup { |
||||
panic(fmt.Sprintf("duplicate DERP index %v (host %q and %q)", i, other, host)) |
||||
} |
||||
if other, dup := derpIndexOfHost[host]; dup { |
||||
panic(fmt.Sprintf("duplicate DERP host %q (index %v and %v)", host, other, i)) |
||||
} |
||||
derpHostOfIndex[i] = host |
||||
derpIndexOfHost[host] = i |
||||
derpNodeID = append(derpNodeID, i) |
||||
} |
||||
|
||||
// derpHost returns the hostname of a DERP server index (a fake port
|
||||
// number used with derpMagicIP).
|
||||
func derpHost(i int) string { |
||||
if h, ok := derpHostOfIndex[i]; ok { |
||||
return h |
||||
} |
||||
if 1 <= i && i <= 64<<10 { |
||||
return fmt.Sprintf("derp%v.tailscale.com", i) |
||||
} |
||||
return "" |
||||
} |
||||
Loading…
Reference in new issue