From 15b405b55252ed8b4ce203d4619ffa6342946ddd Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 16 Nov 2019 18:51:16 +0100 Subject: [PATCH] Support workarounds for ancient/broken implementations Fixes #984 --- dnscrypt-proxy/config.go | 88 ++++++++++++---------- dnscrypt-proxy/crypto.go | 14 ++-- dnscrypt-proxy/example-dnscrypt-proxy.toml | 16 ++++ dnscrypt-proxy/proxy.go | 1 + dnscrypt-proxy/serversInfo.go | 18 +++++ 5 files changed, 90 insertions(+), 47 deletions(-) diff --git a/dnscrypt-proxy/config.go b/dnscrypt-proxy/config.go index f05f12a1..f5acfef9 100644 --- a/dnscrypt-proxy/config.go +++ b/dnscrypt-proxy/config.go @@ -46,47 +46,48 @@ type Config struct { LBEstimator bool `toml:"lb_estimator"` BlockIPv6 bool `toml:"block_ipv6"` Cache bool - CacheSize int `toml:"cache_size"` - CacheNegTTL uint32 `toml:"cache_neg_ttl"` - CacheNegMinTTL uint32 `toml:"cache_neg_min_ttl"` - CacheNegMaxTTL uint32 `toml:"cache_neg_max_ttl"` - CacheMinTTL uint32 `toml:"cache_min_ttl"` - CacheMaxTTL uint32 `toml:"cache_max_ttl"` - RejectTTL uint32 `toml:"reject_ttl"` - CloakTTL uint32 `toml:"cloak_ttl"` - QueryLog QueryLogConfig `toml:"query_log"` - NxLog NxLogConfig `toml:"nx_log"` - BlockName BlockNameConfig `toml:"blacklist"` - WhitelistName WhitelistNameConfig `toml:"whitelist"` - BlockIP BlockIPConfig `toml:"ip_blacklist"` - ForwardFile string `toml:"forwarding_rules"` - CloakFile string `toml:"cloaking_rules"` - StaticsConfig map[string]StaticConfig `toml:"static"` - SourcesConfig map[string]SourceConfig `toml:"sources"` - SourceRequireDNSSEC bool `toml:"require_dnssec"` - SourceRequireNoLog bool `toml:"require_nolog"` - SourceRequireNoFilter bool `toml:"require_nofilter"` - SourceDNSCrypt bool `toml:"dnscrypt_servers"` - SourceDoH bool `toml:"doh_servers"` - SourceIPv4 bool `toml:"ipv4_servers"` - SourceIPv6 bool `toml:"ipv6_servers"` - MaxClients uint32 `toml:"max_clients"` - FallbackResolver string `toml:"fallback_resolver"` - IgnoreSystemDNS bool `toml:"ignore_system_dns"` - AllWeeklyRanges map[string]WeeklyRangesStr `toml:"schedules"` - LogMaxSize int `toml:"log_files_max_size"` - LogMaxAge int `toml:"log_files_max_age"` - LogMaxBackups int `toml:"log_files_max_backups"` - TLSDisableSessionTickets bool `toml:"tls_disable_session_tickets"` - TLSCipherSuite []uint16 `toml:"tls_cipher_suite"` - NetprobeAddress string `toml:"netprobe_address"` - NetprobeTimeout int `toml:"netprobe_timeout"` - OfflineMode bool `toml:"offline_mode"` - HTTPProxyURL string `toml:"http_proxy"` - RefusedCodeInResponses bool `toml:"refused_code_in_responses"` - BlockedQueryResponse string `toml:"blocked_query_response"` - QueryMeta []string `toml:"query_meta"` - AnonymizedDNS AnonymizedDNSConfig `toml:"anonymized_dns"` + CacheSize int `toml:"cache_size"` + CacheNegTTL uint32 `toml:"cache_neg_ttl"` + CacheNegMinTTL uint32 `toml:"cache_neg_min_ttl"` + CacheNegMaxTTL uint32 `toml:"cache_neg_max_ttl"` + CacheMinTTL uint32 `toml:"cache_min_ttl"` + CacheMaxTTL uint32 `toml:"cache_max_ttl"` + RejectTTL uint32 `toml:"reject_ttl"` + CloakTTL uint32 `toml:"cloak_ttl"` + QueryLog QueryLogConfig `toml:"query_log"` + NxLog NxLogConfig `toml:"nx_log"` + BlockName BlockNameConfig `toml:"blacklist"` + WhitelistName WhitelistNameConfig `toml:"whitelist"` + BlockIP BlockIPConfig `toml:"ip_blacklist"` + ForwardFile string `toml:"forwarding_rules"` + CloakFile string `toml:"cloaking_rules"` + StaticsConfig map[string]StaticConfig `toml:"static"` + SourcesConfig map[string]SourceConfig `toml:"sources"` + BrokenImplementations BrokenImplementationsConfig `toml:"broken_implementations"` + SourceRequireDNSSEC bool `toml:"require_dnssec"` + SourceRequireNoLog bool `toml:"require_nolog"` + SourceRequireNoFilter bool `toml:"require_nofilter"` + SourceDNSCrypt bool `toml:"dnscrypt_servers"` + SourceDoH bool `toml:"doh_servers"` + SourceIPv4 bool `toml:"ipv4_servers"` + SourceIPv6 bool `toml:"ipv6_servers"` + MaxClients uint32 `toml:"max_clients"` + FallbackResolver string `toml:"fallback_resolver"` + IgnoreSystemDNS bool `toml:"ignore_system_dns"` + AllWeeklyRanges map[string]WeeklyRangesStr `toml:"schedules"` + LogMaxSize int `toml:"log_files_max_size"` + LogMaxAge int `toml:"log_files_max_age"` + LogMaxBackups int `toml:"log_files_max_backups"` + TLSDisableSessionTickets bool `toml:"tls_disable_session_tickets"` + TLSCipherSuite []uint16 `toml:"tls_cipher_suite"` + NetprobeAddress string `toml:"netprobe_address"` + NetprobeTimeout int `toml:"netprobe_timeout"` + OfflineMode bool `toml:"offline_mode"` + HTTPProxyURL string `toml:"http_proxy"` + RefusedCodeInResponses bool `toml:"refused_code_in_responses"` + BlockedQueryResponse string `toml:"blocked_query_response"` + QueryMeta []string `toml:"query_meta"` + AnonymizedDNS AnonymizedDNSConfig `toml:"anonymized_dns"` } func newConfig() Config { @@ -181,6 +182,10 @@ type AnonymizedDNSConfig struct { Routes []AnonymizedDNSRouteConfig `toml:"routes"` } +type BrokenImplementationsConfig struct { + IncorrectPadding []string `toml:"incorrect_padding"` +} + type ServerSummary struct { Name string `json:"name"` Proto string `json:"proto"` @@ -436,6 +441,7 @@ func ConfigLoad(proxy *Proxy, flags *ConfigFlags) error { } proxy.routes = &routes } + proxy.serversWithIncorrectPadding = config.BrokenImplementations.IncorrectPadding if *flags.ListAll { config.ServerNames = nil diff --git a/dnscrypt-proxy/crypto.go b/dnscrypt-proxy/crypto.go index 912aeb22..22745d65 100644 --- a/dnscrypt-proxy/crypto.go +++ b/dnscrypt-proxy/crypto.go @@ -79,12 +79,14 @@ func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string) publicKey = &proxy.proxyPublicKey } minQuestionSize := QueryOverhead + len(packet) - if proto == "udp" { - minQuestionSize = Max(proxy.questionSizeEstimator.MinQuestionSize(), minQuestionSize) - } else { - var xpad [1]byte - rand.Read(xpad[:]) - minQuestionSize += int(xpad[0]) + if !serverInfo.knownBugs.incorrectPadding { + if proto == "udp" { + minQuestionSize = Max(proxy.questionSizeEstimator.MinQuestionSize(), minQuestionSize) + } else { + var xpad [1]byte + rand.Read(xpad[:]) + minQuestionSize += int(xpad[0]) + } } paddedLength := Min(MaxDNSUDPPacketSize, (Max(minQuestionSize, QueryOverhead)+63) & ^63) if serverInfo.RelayUDPAddr != nil && proto == "tcp" { diff --git a/dnscrypt-proxy/example-dnscrypt-proxy.toml b/dnscrypt-proxy/example-dnscrypt-proxy.toml index 52ae4324..0d7def74 100644 --- a/dnscrypt-proxy/example-dnscrypt-proxy.toml +++ b/dnscrypt-proxy/example-dnscrypt-proxy.toml @@ -567,6 +567,22 @@ cache_neg_max_ttl = 600 # minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' + + +######################################### +# Servers with known bugs # +######################################### + +[broken_implementations] + +# Cisco servers currently cannot handle queries larger than 1472 bytes. +# This prevents large DNSCrypt responses from being received, and breaks relaying. + +incorrect_padding = ['cisco', 'cisco-ipv6', 'cisco-familyshield'] + + + + ################################ # Anonymized DNS # ################################ diff --git a/dnscrypt-proxy/proxy.go b/dnscrypt-proxy/proxy.go index f32e8cb9..0bdd5374 100644 --- a/dnscrypt-proxy/proxy.go +++ b/dnscrypt-proxy/proxy.go @@ -71,6 +71,7 @@ type Proxy struct { blockedQueryResponse string queryMeta []string routes *map[string][]string + serversWithIncorrectPadding []string showCerts bool } diff --git a/dnscrypt-proxy/serversInfo.go b/dnscrypt-proxy/serversInfo.go index 046ff7b6..6e74e2d3 100644 --- a/dnscrypt-proxy/serversInfo.go +++ b/dnscrypt-proxy/serversInfo.go @@ -31,6 +31,10 @@ type RegisteredServer struct { description string } +type ServerBugs struct { + incorrectPadding bool +} + type ServerInfo struct { Proto stamps.StampProtoType MagicQuery [8]byte @@ -45,6 +49,7 @@ type ServerInfo struct { TCPAddr *net.TCPAddr RelayUDPAddr *net.UDPAddr RelayTCPAddr *net.TCPAddr + knownBugs ServerBugs lastActionTS time.Time rtt ewma.MovingAverage initialRtt int @@ -293,7 +298,19 @@ func fetchDNSCryptServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp dlog.Warnf("Public key [%s] shouldn't be hex-encoded any more", string(stamp.ServerPk)) stamp.ServerPk = serverPk } + knownBugs := ServerBugs{} + for _, buggyServerName := range proxy.serversWithIncorrectPadding { + if buggyServerName == name { + knownBugs.incorrectPadding = true + dlog.Infof("Known bug in [%v]: padding is not correctly implemented", name) + break + } + } relayUDPAddr, relayTCPAddr, err := route(proxy, name) + if knownBugs.incorrectPadding && (relayUDPAddr != nil || relayTCPAddr != nil) { + relayTCPAddr, relayUDPAddr = nil, nil + dlog.Warnf("[%v] is incompatible with anonymization", name) + } if err != nil { return ServerInfo{}, err } @@ -322,6 +339,7 @@ func fetchDNSCryptServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp RelayUDPAddr: relayUDPAddr, RelayTCPAddr: relayTCPAddr, initialRtt: rtt, + knownBugs: knownBugs, }, nil }