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
|
package origin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -10,9 +16,25 @@ const (
|
||||||
srvService = "warp"
|
srvService = "warp"
|
||||||
srvProto = "tcp"
|
srvProto = "tcp"
|
||||||
srvName = "cloudflarewarp.com"
|
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 {
|
if len(addresses) > 0 {
|
||||||
var tcpAddrs []*net.TCPAddr
|
var tcpAddrs []*net.TCPAddr
|
||||||
for _, address := range addresses {
|
for _, address := range addresses {
|
||||||
|
@ -28,7 +50,30 @@ func ResolveEdgeIPs(addresses []string) ([]*net.TCPAddr, error) {
|
||||||
// HA service discovery lookup
|
// HA service discovery lookup
|
||||||
_, addrs, err := net.LookupSRV(srvService, srvProto, srvName)
|
_, addrs, err := net.LookupSRV(srvService, srvProto, srvName)
|
||||||
if err != nil {
|
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 resolvedIPsPerCNAME [][]*net.TCPAddr
|
||||||
var lookupErr error
|
var lookupErr error
|
||||||
|
@ -80,3 +125,19 @@ func FlattenServiceIPs(ipsByService [][]*net.TCPAddr) []*net.TCPAddr {
|
||||||
}
|
}
|
||||||
return result
|
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 {
|
func (s *Supervisor) initialize(ctx context.Context, connectedSignal *signal.Signal, u uuid.UUID) error {
|
||||||
logger := s.config.Logger
|
logger := s.config.Logger
|
||||||
edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs)
|
edgeIPs, err := ResolveEdgeIPs(logger, s.config.EdgeAddrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Infof("ResolveEdgeIPs err")
|
logger.Infof("ResolveEdgeIPs err")
|
||||||
return err
|
return err
|
||||||
|
@ -223,7 +223,7 @@ func (s *Supervisor) refreshEdgeIPs() {
|
||||||
}
|
}
|
||||||
s.resolverC = make(chan resolveResult)
|
s.resolverC = make(chan resolveResult)
|
||||||
go func() {
|
go func() {
|
||||||
edgeIPs, err := ResolveEdgeIPs(s.config.EdgeAddrs)
|
edgeIPs, err := ResolveEdgeIPs(s.config.Logger, s.config.EdgeAddrs)
|
||||||
s.resolverC <- resolveResult{edgeIPs: edgeIPs, err: err}
|
s.resolverC <- resolveResult{edgeIPs: edgeIPs, err: err}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ func StartTunnelDaemon(config *TunnelConfig, shutdownC <-chan struct{}, connecte
|
||||||
if config.HAConnections > 1 {
|
if config.HAConnections > 1 {
|
||||||
return NewSupervisor(config).Run(ctx, connectedSignal, u)
|
return NewSupervisor(config).Run(ctx, connectedSignal, u)
|
||||||
} else {
|
} else {
|
||||||
addrs, err := ResolveEdgeIPs(config.EdgeAddrs)
|
addrs, err := ResolveEdgeIPs(config.Logger, config.EdgeAddrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue