TUN-1522: If we can't get SRV from default resolver, get them from 1.1.1.1 DoT
This commit is contained in:
parent
b02718f86b
commit
d22e214000
|
@ -1,8 +1,14 @@
|
|||
package origin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -10,9 +16,25 @@ const (
|
|||
srvService = "warp"
|
||||
srvProto = "tcp"
|
||||
srvName = "cloudflarewarp.com"
|
||||
|
||||
// Used to fallback to DoT when we can't use the default resolver to
|
||||
// discover HA Warp servers (GitHub issue #75).
|
||||
dotServerName = "cloudflare-dns.com"
|
||||
dotServerAddr = "1.1.1.1:853"
|
||||
dotTimeout = time.Duration(15 * time.Second)
|
||||
)
|
||||
|
||||
func ResolveEdgeIPs(addresses []string) ([]*net.TCPAddr, error) {
|
||||
var friendlyDNSErrorLines = []string{
|
||||
`Please try the following things to diagnose this issue:`,
|
||||
` 1. ensure that cloudflarewarp.com is returning "warp" service records.`,
|
||||
` Run your system's equivalent of: dig srv _warp._tcp.cloudflarewarp.com`,
|
||||
` 2. ensure that your DNS resolver is not returning compressed SRV records.`,
|
||||
` See GitHub issue https://github.com/golang/go/issues/27546`,
|
||||
` For example, you could use Cloudflare's 1.1.1.1 as your resolver:`,
|
||||
` https://developers.cloudflare.com/1.1.1.1/setting-up-1.1.1.1/`,
|
||||
}
|
||||
|
||||
func ResolveEdgeIPs(logger *log.Logger, addresses []string) ([]*net.TCPAddr, error) {
|
||||
if len(addresses) > 0 {
|
||||
var tcpAddrs []*net.TCPAddr
|
||||
for _, address := range addresses {
|
||||
|
@ -28,7 +50,30 @@ func ResolveEdgeIPs(addresses []string) ([]*net.TCPAddr, error) {
|
|||
// HA service discovery lookup
|
||||
_, addrs, err := net.LookupSRV(srvService, srvProto, srvName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Try to fall back to DoT from Cloudflare directly.
|
||||
//
|
||||
// Note: Instead of DoT, we could also have used DoH. Either of these:
|
||||
// - directly via the JSON API (https://1.1.1.1/dns-query?ct=application/dns-json&name=_warp._tcp.cloudflarewarp.com&type=srv)
|
||||
// - indirectly via `tunneldns.NewUpstreamHTTPS()`
|
||||
// But both of these cases miss out on a key feature from the stdlib:
|
||||
// "The returned records are sorted by priority and randomized by weight within a priority."
|
||||
// (https://golang.org/pkg/net/#Resolver.LookupSRV)
|
||||
// Does this matter? I don't know. It may someday. Let's use DoT so we don't need to worry about it.
|
||||
// See also: Go feature request for stdlib-supported DoH: https://github.com/golang/go/issues/27552
|
||||
r := fallbackResolver(dotServerName, dotServerAddr)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), dotTimeout)
|
||||
defer cancel()
|
||||
_, fallbackAddrs, fallbackErr := r.LookupSRV(ctx, srvService, srvProto, srvName)
|
||||
if fallbackErr != nil || len(fallbackAddrs) == 0 {
|
||||
// use the original DNS error `err` in messages, not `fallbackErr`
|
||||
logger.Errorln("Error looking up Cloudflare edge IPs: the DNS query failed:", err)
|
||||
for _, s := range friendlyDNSErrorLines {
|
||||
logger.Errorln(s)
|
||||
}
|
||||
return nil, errors.Wrap(err, "Could not lookup srv records on _warp._tcp.cloudflarewarp.com")
|
||||
}
|
||||
// Accept the fallback results and keep going
|
||||
addrs = fallbackAddrs
|
||||
}
|
||||
var resolvedIPsPerCNAME [][]*net.TCPAddr
|
||||
var lookupErr error
|
||||
|
@ -80,3 +125,19 @@ func FlattenServiceIPs(ipsByService [][]*net.TCPAddr) []*net.TCPAddr {
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Inspiration: https://github.com/artyom/dot/blob/master/dot.go
|
||||
func fallbackResolver(serverName, serverAddress string) *net.Resolver {
|
||||
return &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, _ string, _ string) (net.Conn, error) {
|
||||
var dialer net.Dialer
|
||||
conn, err := dialer.DialContext(ctx, "tcp", serverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig := &tls.Config{ServerName: serverName}
|
||||
return tls.Client(conn, tlsConfig), nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ func (s *Supervisor) Run(ctx context.Context, connectedSignal *signal.Signal, u
|
|||
|
||||
func (s *Supervisor) initialize(ctx context.Context, connectedSignal *signal.Signal, u uuid.UUID) error {
|
||||
logger := s.config.Logger
|
||||
edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs)
|
||||
edgeIPs, err := ResolveEdgeIPs(logger, s.config.EdgeAddrs)
|
||||
if err != nil {
|
||||
logger.Infof("ResolveEdgeIPs err")
|
||||
return err
|
||||
|
@ -223,7 +223,7 @@ func (s *Supervisor) refreshEdgeIPs() {
|
|||
}
|
||||
s.resolverC = make(chan resolveResult)
|
||||
go func() {
|
||||
edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs)
|
||||
edgeIPs, err := ResolveEdgeIPs(s.config.Logger, s.config.EdgeAddrs)
|
||||
s.resolverC <- resolveResult{edgeIPs: edgeIPs, err: err}
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ func StartTunnelDaemon(config *TunnelConfig, shutdownC <-chan struct{}, connecte
|
|||
if config.HAConnections > 1 {
|
||||
return NewSupervisor(config).Run(ctx, connectedSignal, u)
|
||||
} else {
|
||||
addrs, err := ResolveEdgeIPs(config.EdgeAddrs)
|
||||
addrs, err := ResolveEdgeIPs(config.Logger, config.EdgeAddrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue