Don't use distinct pointers for UDP and TCP relay addresses

This commit is contained in:
Frank Denis 2020-12-12 21:18:32 +01:00
parent ab8ebead34
commit 7f46f4820c
4 changed files with 53 additions and 41 deletions

View file

@ -100,7 +100,7 @@ func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string)
if proto == "udp" && serverInfo.knownBugs.fragmentsBlocked {
paddedLength = MaxDNSUDPSafePacketSize
}
if serverInfo.RelayUDPAddr != nil && proto == "tcp" {
if serverInfo.Relay != nil && proto == "tcp" {
paddedLength = MaxDNSPacketSize
}
if QueryOverhead+len(packet)+1 > paddedLength {

View file

@ -21,7 +21,7 @@ type CertInfo struct {
ForwardSecurity bool
}
func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk ed25519.PublicKey, serverAddress string, providerName string, isNew bool, relayUDPAddr *net.UDPAddr, relayTCPAddr *net.TCPAddr, knownBugs ServerBugs) (CertInfo, int, bool, error) {
func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk ed25519.PublicKey, serverAddress string, providerName string, isNew bool, relay *DNSCryptRelay, knownBugs ServerBugs) (CertInfo, int, bool, error) {
if len(pk) != ed25519.PublicKeySize {
return CertInfo{}, 0, false, errors.New("Invalid public key length")
}
@ -34,18 +34,18 @@ func FetchCurrentDNSCryptCert(proxy *Proxy, serverName *string, proto string, pk
query := dns.Msg{}
query.SetQuestion(providerName, dns.TypeTXT)
if !strings.HasPrefix(providerName, "2.dnscrypt-cert.") {
if relayUDPAddr != nil && !proxy.anonDirectCertFallback {
if relay != nil && !proxy.anonDirectCertFallback {
dlog.Warnf("[%v] uses a non-standard provider name, enable direct cert fallback to use with a relay ('%v' doesn't start with '2.dnscrypt-cert.')", *serverName, providerName)
} else {
dlog.Warnf("[%v] uses a non-standard provider name ('%v' doesn't start with '2.dnscrypt-cert.')", *serverName, providerName)
relayUDPAddr, relayTCPAddr = nil, nil
relay = nil
}
}
tryFragmentsSupport := true
if knownBugs.fragmentsBlocked {
tryFragmentsSupport = false
}
in, rtt, fragmentsBlocked, err := dnsExchange(proxy, proto, &query, serverAddress, relayUDPAddr, relayTCPAddr, serverName, tryFragmentsSupport)
in, rtt, fragmentsBlocked, err := dnsExchange(proxy, proto, &query, serverAddress, relay, serverName, tryFragmentsSupport)
if err != nil {
dlog.Noticef("[%s] TIMEOUT", *serverName)
return CertInfo{}, 0, fragmentsBlocked, err
@ -197,7 +197,7 @@ type dnsExchangeResponse struct {
err error
}
func dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress string, relayUDPAddr *net.UDPAddr, relayTCPAddr *net.TCPAddr, serverName *string, tryFragmentsSupport bool) (*dns.Msg, time.Duration, bool, error) {
func dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress string, relay *DNSCryptRelay, serverName *string, tryFragmentsSupport bool) (*dns.Msg, time.Duration, bool, error) {
for {
cancelChannel := make(chan struct{})
channel := make(chan dnsExchangeResponse)
@ -209,7 +209,7 @@ func dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress strin
queryCopy := query.Copy()
queryCopy.Id += uint16(options)
go func(query *dns.Msg, delay time.Duration) {
option := _dnsExchange(proxy, proto, query, serverAddress, relayUDPAddr, relayTCPAddr, 1500)
option := _dnsExchange(proxy, proto, query, serverAddress, relay, 1500)
option.fragmentsBlocked = false
option.priority = 0
channel <- option
@ -225,7 +225,7 @@ func dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress strin
queryCopy := query.Copy()
queryCopy.Id += uint16(options)
go func(query *dns.Msg, delay time.Duration) {
option := _dnsExchange(proxy, proto, query, serverAddress, relayUDPAddr, relayTCPAddr, 480)
option := _dnsExchange(proxy, proto, query, serverAddress, relay, 480)
option.fragmentsBlocked = true
option.priority = 1
channel <- option
@ -262,18 +262,18 @@ func dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress strin
return bestOption.response, bestOption.rtt, bestOption.fragmentsBlocked, nil
}
if relayUDPAddr == nil || !proxy.anonDirectCertFallback {
if relay == nil || !proxy.anonDirectCertFallback {
if err == nil {
err = errors.New("Unable to reach the server")
}
return nil, 0, false, err
}
dlog.Infof("Unable to get a certificate for [%v] via relay [%v], retrying over a direct connection", *serverName, relayUDPAddr.IP)
relayUDPAddr, relayTCPAddr = nil, nil
dlog.Infof("Unable to get a certificate for [%v] via relay [%v], retrying over a direct connection", *serverName, relay.RelayUDPAddr.IP)
relay = nil
}
}
func _dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress string, relayUDPAddr *net.UDPAddr, relayTCPAddr *net.TCPAddr, paddedLen int) dnsExchangeResponse {
func _dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress string, relay *DNSCryptRelay, paddedLen int) dnsExchangeResponse {
var packet []byte
var rtt time.Duration
@ -299,9 +299,9 @@ func _dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress stri
return dnsExchangeResponse{err: err}
}
upstreamAddr := udpAddr
if relayUDPAddr != nil {
if relay != nil {
proxy.prepareForRelay(udpAddr.IP, udpAddr.Port, &binQuery)
upstreamAddr = relayUDPAddr
upstreamAddr = relay.RelayUDPAddr
}
now := time.Now()
pc, err := net.DialUDP("udp", nil, upstreamAddr)
@ -332,9 +332,9 @@ func _dnsExchange(proxy *Proxy, proto string, query *dns.Msg, serverAddress stri
return dnsExchangeResponse{err: err}
}
upstreamAddr := tcpAddr
if relayTCPAddr != nil {
if relay != nil {
proxy.prepareForRelay(tcpAddr.IP, tcpAddr.Port, &binQuery)
upstreamAddr = relayTCPAddr
upstreamAddr = relay.RelayTCPAddr
}
now := time.Now()
var pc net.Conn

View file

@ -386,8 +386,8 @@ func (proxy *Proxy) prepareForRelay(ip net.IP, port int, encryptedQuery *[]byte)
func (proxy *Proxy) exchangeWithUDPServer(serverInfo *ServerInfo, sharedKey *[32]byte, encryptedQuery []byte, clientNonce []byte) ([]byte, error) {
upstreamAddr := serverInfo.UDPAddr
if serverInfo.RelayUDPAddr != nil {
upstreamAddr = serverInfo.RelayUDPAddr
if serverInfo.Relay != nil && serverInfo.Relay.Dnscrypt != nil {
upstreamAddr = serverInfo.Relay.Dnscrypt.RelayUDPAddr
}
var err error
var pc net.Conn
@ -404,7 +404,7 @@ func (proxy *Proxy) exchangeWithUDPServer(serverInfo *ServerInfo, sharedKey *[32
if err := pc.SetDeadline(time.Now().Add(serverInfo.Timeout)); err != nil {
return nil, err
}
if serverInfo.RelayUDPAddr != nil {
if serverInfo.Relay != nil && serverInfo.Relay.Dnscrypt != nil {
proxy.prepareForRelay(serverInfo.UDPAddr.IP, serverInfo.UDPAddr.Port, &encryptedQuery)
}
encryptedResponse := make([]byte, MaxDNSPacketSize)
@ -424,8 +424,8 @@ func (proxy *Proxy) exchangeWithUDPServer(serverInfo *ServerInfo, sharedKey *[32
func (proxy *Proxy) exchangeWithTCPServer(serverInfo *ServerInfo, sharedKey *[32]byte, encryptedQuery []byte, clientNonce []byte) ([]byte, error) {
upstreamAddr := serverInfo.TCPAddr
if serverInfo.RelayUDPAddr != nil {
upstreamAddr = serverInfo.RelayTCPAddr
if serverInfo.Relay != nil && serverInfo.Relay.Dnscrypt != nil {
upstreamAddr = serverInfo.Relay.Dnscrypt.RelayTCPAddr
}
var err error
var pc net.Conn
@ -442,7 +442,7 @@ func (proxy *Proxy) exchangeWithTCPServer(serverInfo *ServerInfo, sharedKey *[32
if err := pc.SetDeadline(time.Now().Add(serverInfo.Timeout)); err != nil {
return nil, err
}
if serverInfo.RelayTCPAddr != nil {
if serverInfo.Relay != nil && serverInfo.Relay.Dnscrypt != nil {
proxy.prepareForRelay(serverInfo.TCPAddr.IP, serverInfo.TCPAddr.Port, &encryptedQuery)
}
encryptedQuery, err = PrefixWithSize(encryptedQuery)

View file

@ -50,9 +50,8 @@ type ServerInfo struct {
HostName string
UDPAddr *net.UDPAddr
TCPAddr *net.TCPAddr
RelayUDPAddr *net.UDPAddr
Relay *Relay
URL *url.URL
RelayTCPAddr *net.TCPAddr
initialRtt int
Timeout time.Duration
CryptoConstruction CryptoConstruction
@ -100,6 +99,16 @@ func (LBStrategyRandom) getCandidate(serversCount int) int {
var DefaultLBStrategy = LBStrategyP2{}
type DNSCryptRelay struct {
RelayUDPAddr *net.UDPAddr
RelayTCPAddr *net.TCPAddr
}
type Relay struct {
Proto stamps.StampProtoType
Dnscrypt *DNSCryptRelay
}
type ServersInfo struct {
sync.RWMutex
inner []*ServerInfo
@ -252,17 +261,17 @@ func fetchServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isNew
return ServerInfo{}, errors.New(fmt.Sprintf("Unsupported protocol for [%s]: [%s]", name, stamp.Proto.String()))
}
func route(proxy *Proxy, name string) (*net.UDPAddr, *net.TCPAddr, error) {
func route(proxy *Proxy, name string) (*Relay, error) {
routes := proxy.routes
if routes == nil {
return nil, nil, nil
return nil, nil
}
relayNames, ok := (*routes)[name]
if !ok {
relayNames, ok = (*routes)["*"]
}
if !ok {
return nil, nil, nil
return nil, nil
}
var relayName string
if len(relayNames) > 0 {
@ -271,7 +280,7 @@ func route(proxy *Proxy, name string) (*net.UDPAddr, *net.TCPAddr, error) {
}
var relayCandidateStamp *stamps.ServerStamp
if len(relayName) == 0 {
return nil, nil, fmt.Errorf("Route declared for [%v] but the relay list is empty", name)
return nil, fmt.Errorf("Route declared for [%v] but the relay list is empty", name)
} else if relayStamp, err := stamps.NewServerStampFromString(relayName); err == nil {
relayCandidateStamp = &relayStamp
} else {
@ -289,21 +298,21 @@ func route(proxy *Proxy, name string) (*net.UDPAddr, *net.TCPAddr, error) {
}
}
if relayCandidateStamp == nil {
return nil, nil, fmt.Errorf("Undefined relay [%v] for server [%v]", relayName, name)
return nil, fmt.Errorf("Undefined relay [%v] for server [%v]", relayName, name)
}
if relayCandidateStamp.Proto == stamps.StampProtoTypeDNSCrypt ||
relayCandidateStamp.Proto == stamps.StampProtoTypeDNSCryptRelay {
switch relayCandidateStamp.Proto {
case stamps.StampProtoTypeDNSCrypt | stamps.StampProtoTypeDNSCryptRelay:
relayUDPAddr, err := net.ResolveUDPAddr("udp", relayCandidateStamp.ServerAddrStr)
if err != nil {
return nil, nil, err
return nil, err
}
relayTCPAddr, err := net.ResolveTCPAddr("tcp", relayCandidateStamp.ServerAddrStr)
if err != nil {
return nil, nil, err
return nil, err
}
return relayUDPAddr, relayTCPAddr, nil
return &Relay{Proto: stamps.StampProtoTypeDNSCryptRelay, Dnscrypt: &DNSCryptRelay{RelayUDPAddr: relayUDPAddr, RelayTCPAddr: relayTCPAddr}}, nil
}
return nil, nil, fmt.Errorf("Invalid relay [%v] for server [%v]", relayName, name)
return nil, fmt.Errorf("Invalid relay [%v] for server [%v]", relayName, name)
}
func fetchDNSCryptServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isNew bool) (ServerInfo, error) {
@ -323,17 +332,21 @@ func fetchDNSCryptServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp
break
}
}
relayUDPAddr, relayTCPAddr, err := route(proxy, name)
relay, err := route(proxy, name)
if err != nil {
return ServerInfo{}, err
}
certInfo, rtt, fragmentsBlocked, err := FetchCurrentDNSCryptCert(proxy, &name, proxy.mainProto, stamp.ServerPk, stamp.ServerAddrStr, stamp.ProviderName, isNew, relayUDPAddr, relayTCPAddr, knownBugs)
var dnscryptRelay *DNSCryptRelay
if relay != nil {
dnscryptRelay = relay.Dnscrypt
}
certInfo, rtt, fragmentsBlocked, err := FetchCurrentDNSCryptCert(proxy, &name, proxy.mainProto, stamp.ServerPk, stamp.ServerAddrStr, stamp.ProviderName, isNew, dnscryptRelay, knownBugs)
if !knownBugs.fragmentsBlocked && fragmentsBlocked {
dlog.Debugf("[%v] drops fragmented queries", name)
knownBugs.fragmentsBlocked = true
}
if knownBugs.fragmentsBlocked && (relayUDPAddr != nil || relayTCPAddr != nil) {
relayTCPAddr, relayUDPAddr = nil, nil
if knownBugs.fragmentsBlocked && relay != nil && relay.Dnscrypt != nil {
relay = nil
if proxy.skipAnonIncompatbibleResolvers {
dlog.Infof("[%v] is incompatible with anonymization, it will be ignored", name)
return ServerInfo{}, errors.New("Resolver is incompatible with anonymization")
@ -361,8 +374,7 @@ func fetchDNSCryptServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp
Timeout: proxy.timeout,
UDPAddr: remoteUDPAddr,
TCPAddr: remoteTCPAddr,
RelayUDPAddr: relayUDPAddr,
RelayTCPAddr: relayTCPAddr,
Relay: relay,
initialRtt: rtt,
knownBugs: knownBugs,
}, nil