2018-01-09 16:59:06 +01:00
package main
import (
2020-02-21 20:24:24 +01:00
crypto_rand "crypto/rand"
2018-01-27 17:48:53 +01:00
"crypto/sha256"
2018-04-01 16:35:32 +02:00
"encoding/hex"
2018-01-27 15:26:08 +01:00
"errors"
"fmt"
2021-01-03 13:01:44 +01:00
"math/bits"
2018-01-09 17:19:03 +01:00
"math/rand"
2018-01-09 16:59:06 +01:00
"net"
2018-01-27 15:26:08 +01:00
"net/url"
2019-10-09 16:09:19 +02:00
"sort"
2018-01-09 16:59:06 +01:00
"strings"
"sync"
2018-01-09 17:15:07 +01:00
"time"
2018-01-09 16:59:06 +01:00
2018-01-10 16:42:14 +01:00
"github.com/VividCortex/ewma"
2018-01-11 11:50:54 +01:00
"github.com/jedisct1/dlog"
2021-06-07 10:46:01 +02:00
clocksmith "github.com/jedisct1/go-clocksmith"
2018-04-18 18:58:39 +02:00
stamps "github.com/jedisct1/go-dnsstamps"
2020-02-21 20:24:24 +01:00
"github.com/miekg/dns"
2018-04-01 16:35:32 +02:00
"golang.org/x/crypto/ed25519"
2018-01-09 16:59:06 +01:00
)
2018-01-10 16:42:14 +01:00
const (
2022-02-19 17:55:36 +01:00
RTTEwmaDecay = 10.0
2018-01-18 13:01:16 +01:00
)
2018-01-09 18:27:04 +01:00
type RegisteredServer struct {
2018-01-31 09:42:56 +01:00
name string
2018-04-14 15:03:21 +02:00
stamp stamps . ServerStamp
2018-01-31 09:42:56 +01:00
description string
2018-01-09 18:27:04 +01:00
}
2019-11-16 18:51:16 +01:00
type ServerBugs struct {
2020-03-26 17:20:34 +01:00
fragmentsBlocked bool
2019-11-16 18:51:16 +01:00
}
2020-03-09 22:11:53 +01:00
type DOHClientCreds struct {
clientCert string
clientKey string
2020-06-08 18:01:40 +02:00
rootCA string
2020-03-09 22:11:53 +01:00
}
2018-01-09 17:15:07 +01:00
type ServerInfo struct {
2020-11-14 14:46:59 +01:00
DOHClientCreds DOHClientCreds
lastActionTS time . Time
rtt ewma . MovingAverage
2018-01-09 17:15:07 +01:00
Name string
2018-01-27 15:26:08 +01:00
HostName string
2018-01-09 17:15:07 +01:00
UDPAddr * net . UDPAddr
TCPAddr * net . TCPAddr
2020-12-12 21:18:32 +01:00
Relay * Relay
2020-11-14 14:46:59 +01:00
URL * url . URL
2018-01-17 22:12:34 +01:00
initialRtt int
2020-11-14 14:46:59 +01:00
Timeout time . Duration
CryptoConstruction CryptoConstruction
ServerPk [ 32 ] byte
SharedKey [ 32 ] byte
MagicQuery [ 8 ] byte
knownBugs ServerBugs
2020-12-12 22:19:09 +01:00
Proto stamps . StampProtoType
2018-02-05 11:30:10 +01:00
useGet bool
2021-06-05 17:49:19 +02:00
odohTargetConfigs [ ] ODoHTargetConfig
2018-01-09 17:15:07 +01:00
}
2020-03-20 17:37:34 +01:00
type LBStrategy interface {
getCandidate ( serversCount int ) int
2022-02-15 20:17:48 +01:00
getActiveCount ( serversCount int ) int
2020-03-20 17:37:34 +01:00
}
2018-02-04 21:13:54 +01:00
2020-03-20 17:37:34 +01:00
type LBStrategyP2 struct { }
func ( LBStrategyP2 ) getCandidate ( serversCount int ) int {
return rand . Intn ( Min ( serversCount , 2 ) )
}
2022-02-15 20:17:48 +01:00
func ( LBStrategyP2 ) getActiveCount ( serversCount int ) int {
return Min ( serversCount , 2 )
}
2020-03-20 17:48:54 +01:00
type LBStrategyPN struct { n int }
func ( s LBStrategyPN ) getCandidate ( serversCount int ) int {
return rand . Intn ( Min ( serversCount , s . n ) )
}
2022-02-15 20:17:48 +01:00
func ( s LBStrategyPN ) getActiveCount ( serversCount int ) int {
return Min ( serversCount , s . n )
}
2020-03-20 17:37:34 +01:00
type LBStrategyPH struct { }
func ( LBStrategyPH ) getCandidate ( serversCount int ) int {
return rand . Intn ( Max ( Min ( serversCount , 2 ) , serversCount / 2 ) )
}
2018-02-04 21:13:54 +01:00
2022-02-15 20:17:48 +01:00
func ( LBStrategyPH ) getActiveCount ( serversCount int ) int {
return Max ( Min ( serversCount , 2 ) , serversCount / 2 )
}
2020-03-20 17:37:34 +01:00
type LBStrategyFirst struct { }
func ( LBStrategyFirst ) getCandidate ( int ) int {
return 0
}
2022-02-15 20:17:48 +01:00
func ( LBStrategyFirst ) getActiveCount ( int ) int {
return 1
}
2020-03-20 17:37:34 +01:00
type LBStrategyRandom struct { }
func ( LBStrategyRandom ) getCandidate ( serversCount int ) int {
return rand . Intn ( serversCount )
}
2022-02-15 20:17:48 +01:00
func ( LBStrategyRandom ) getActiveCount ( serversCount int ) int {
return serversCount
}
2020-03-20 17:37:34 +01:00
var DefaultLBStrategy = LBStrategyP2 { }
2018-02-04 21:13:54 +01:00
2020-12-12 21:18:32 +01:00
type DNSCryptRelay struct {
RelayUDPAddr * net . UDPAddr
RelayTCPAddr * net . TCPAddr
}
2021-03-30 11:03:25 +02:00
type ODoHRelay struct {
2021-06-07 10:46:01 +02:00
URL * url . URL
2021-03-30 11:03:25 +02:00
}
2020-12-12 22:35:51 +01:00
2020-12-12 21:18:32 +01:00
type Relay struct {
Proto stamps . StampProtoType
Dnscrypt * DNSCryptRelay
2020-12-12 22:35:51 +01:00
ODoH * ODoHRelay
2020-12-12 21:18:32 +01:00
}
2018-01-09 16:59:06 +01:00
type ServersInfo struct {
sync . RWMutex
2018-03-02 02:30:25 +01:00
inner [ ] * ServerInfo
2018-01-09 18:27:04 +01:00
registeredServers [ ] RegisteredServer
2021-01-09 22:44:32 +01:00
registeredRelays [ ] RegisteredServer
2018-02-04 21:13:54 +01:00
lbStrategy LBStrategy
2019-06-03 13:04:34 +02:00
lbEstimator bool
2018-01-09 16:59:06 +01:00
}
2019-06-03 16:44:09 +02:00
func NewServersInfo ( ) ServersInfo {
2021-01-09 22:44:32 +01:00
return ServersInfo { lbStrategy : DefaultLBStrategy , lbEstimator : true , registeredServers : make ( [ ] RegisteredServer , 0 ) , registeredRelays : make ( [ ] RegisteredServer , 0 ) }
2019-06-03 16:44:09 +02:00
}
2019-11-01 16:37:33 +01:00
func ( serversInfo * ServersInfo ) registerServer ( name string , stamp stamps . ServerStamp ) {
2018-01-17 21:23:01 +01:00
newRegisteredServer := RegisteredServer { name : name , stamp : stamp }
serversInfo . Lock ( )
defer serversInfo . Unlock ( )
for i , oldRegisteredServer := range serversInfo . registeredServers {
if oldRegisteredServer . name == name {
serversInfo . registeredServers [ i ] = newRegisteredServer
2019-11-01 16:37:33 +01:00
return
2018-01-17 21:23:01 +01:00
}
}
serversInfo . registeredServers = append ( serversInfo . registeredServers , newRegisteredServer )
}
2021-01-09 22:44:32 +01:00
func ( serversInfo * ServersInfo ) registerRelay ( name string , stamp stamps . ServerStamp ) {
newRegisteredServer := RegisteredServer { name : name , stamp : stamp }
serversInfo . Lock ( )
defer serversInfo . Unlock ( )
for i , oldRegisteredServer := range serversInfo . registeredRelays {
if oldRegisteredServer . name == name {
serversInfo . registeredRelays [ i ] = newRegisteredServer
return
}
}
serversInfo . registeredRelays = append ( serversInfo . registeredRelays , newRegisteredServer )
}
2018-04-14 15:03:21 +02:00
func ( serversInfo * ServersInfo ) refreshServer ( proxy * Proxy , name string , stamp stamps . ServerStamp ) error {
2019-03-14 01:59:57 +01:00
serversInfo . RLock ( )
2019-10-18 19:02:48 +02:00
isNew := true
for _ , oldServer := range serversInfo . inner {
2018-01-31 00:19:53 +01:00
if oldServer . Name == name {
2019-10-18 19:02:48 +02:00
isNew = false
2018-01-31 00:19:53 +01:00
break
}
}
2019-03-14 01:59:57 +01:00
serversInfo . RUnlock ( )
2019-10-18 19:02:48 +02:00
newServer , err := fetchServerInfo ( proxy , name , stamp , isNew )
2018-01-09 16:59:06 +01:00
if err != nil {
return err
}
2018-01-31 00:19:53 +01:00
if name != newServer . Name {
dlog . Fatalf ( "[%s] != [%s]" , name , newServer . Name )
}
2018-01-10 16:42:14 +01:00
newServer . rtt = ewma . NewMovingAverage ( RTTEwmaDecay )
2019-06-03 17:07:30 +02:00
newServer . rtt . Set ( float64 ( newServer . initialRtt ) )
2019-10-18 19:02:48 +02:00
isNew = true
2019-03-14 01:59:57 +01:00
serversInfo . Lock ( )
for i , oldServer := range serversInfo . inner {
if oldServer . Name == name {
2019-10-18 18:57:04 +02:00
serversInfo . inner [ i ] = & newServer
isNew = false
2019-03-14 01:59:57 +01:00
break
}
}
2021-01-01 14:04:12 +01:00
serversInfo . Unlock ( )
2019-10-18 18:57:04 +02:00
if isNew {
2021-01-01 14:04:12 +01:00
serversInfo . Lock ( )
2019-10-18 18:57:04 +02:00
serversInfo . inner = append ( serversInfo . inner , & newServer )
2021-01-01 14:04:12 +01:00
serversInfo . Unlock ( )
proxy . serversInfo . registerServer ( name , stamp )
2018-01-09 17:15:07 +01:00
}
2021-01-01 14:04:12 +01:00
2018-01-09 16:59:06 +01:00
return nil
}
2018-01-17 17:22:29 +01:00
func ( serversInfo * ServersInfo ) refresh ( proxy * Proxy ) ( int , error ) {
2018-01-30 23:50:42 +01:00
dlog . Debug ( "Refreshing certificates" )
2018-01-09 17:34:19 +01:00
serversInfo . RLock ( )
2018-01-09 18:27:04 +01:00
registeredServers := serversInfo . registeredServers
2018-01-09 17:34:19 +01:00
serversInfo . RUnlock ( )
2018-01-17 17:22:29 +01:00
liveServers := 0
var err error
2018-01-09 18:27:04 +01:00
for _ , registeredServer := range registeredServers {
2018-01-17 21:23:01 +01:00
if err = serversInfo . refreshServer ( proxy , registeredServer . name , registeredServer . stamp ) ; err == nil {
2018-01-17 17:22:29 +01:00
liveServers ++
}
2018-01-09 17:34:19 +01:00
}
2018-01-17 22:12:34 +01:00
serversInfo . Lock ( )
2019-10-09 16:09:19 +02:00
sort . SliceStable ( serversInfo . inner , func ( i , j int ) bool {
return serversInfo . inner [ i ] . initialRtt < serversInfo . inner [ j ] . initialRtt
} )
2018-01-17 22:12:34 +01:00
inner := serversInfo . inner
innerLen := len ( inner )
2019-06-03 18:51:21 +02:00
if innerLen > 1 {
dlog . Notice ( "Sorted latencies:" )
for i := 0 ; i < innerLen ; i ++ {
dlog . Noticef ( "- %5dms %s" , inner [ i ] . initialRtt , inner [ i ] . Name )
}
2019-06-03 13:04:34 +02:00
}
2018-01-30 23:50:42 +01:00
if innerLen > 0 {
2018-01-17 22:12:34 +01:00
dlog . Noticef ( "Server with the lowest initial latency: %s (rtt: %dms)" , inner [ 0 ] . Name , inner [ 0 ] . initialRtt )
}
serversInfo . Unlock ( )
2018-01-17 17:22:29 +01:00
return liveServers , err
}
2018-01-09 17:34:19 +01:00
2019-10-20 17:17:21 +02:00
func ( serversInfo * ServersInfo ) estimatorUpdate ( ) {
2019-10-26 17:28:24 +02:00
// serversInfo.RWMutex is assumed to be Locked
2022-02-15 20:17:48 +01:00
serversCount := len ( serversInfo . inner )
activeCount := serversInfo . lbStrategy . getActiveCount ( serversCount )
if activeCount == serversCount {
2019-10-20 17:17:21 +02:00
return
}
2022-02-15 20:17:48 +01:00
candidate , currentActive := rand . Intn ( serversCount - activeCount ) + activeCount , rand . Intn ( activeCount )
candidateRtt , currentActiveRtt := serversInfo . inner [ candidate ] . rtt . Value ( ) , serversInfo . inner [ currentActive ] . rtt . Value ( )
if currentActiveRtt < 0 {
currentActiveRtt = candidateRtt
serversInfo . inner [ currentActive ] . rtt . Set ( currentActiveRtt )
2018-02-21 00:14:18 +01:00
}
partialSort := false
2022-02-15 20:17:48 +01:00
if candidateRtt < currentActiveRtt {
serversInfo . inner [ candidate ] , serversInfo . inner [ currentActive ] = serversInfo . inner [ currentActive ] , serversInfo . inner [ candidate ]
dlog . Debugf ( "New preferred candidate: %s (RTT: %d vs previous: %d)" , serversInfo . inner [ currentActive ] . Name , int ( candidateRtt ) , int ( currentActiveRtt ) )
2018-02-21 00:14:18 +01:00
partialSort = true
2022-02-19 17:55:36 +01:00
} else if candidateRtt > 0 && candidateRtt >= ( serversInfo . inner [ 0 ] . rtt . Value ( ) + serversInfo . inner [ activeCount - 1 ] . rtt . Value ( ) ) / 2.0 * 4.0 {
2018-02-21 00:14:18 +01:00
if time . Since ( serversInfo . inner [ candidate ] . lastActionTS ) > time . Duration ( 1 * time . Minute ) {
2022-02-19 17:55:36 +01:00
serversInfo . inner [ candidate ] . rtt . Add ( candidateRtt / 2.0 )
2022-02-15 20:17:48 +01:00
dlog . Debugf ( "Giving a new chance to candidate [%s], lowering its RTT from %d to %d (best: %d)" , serversInfo . inner [ candidate ] . Name , int ( candidateRtt ) , int ( serversInfo . inner [ candidate ] . rtt . Value ( ) ) , int ( serversInfo . inner [ 0 ] . rtt . Value ( ) ) )
2018-02-21 00:14:18 +01:00
partialSort = true
}
}
if partialSort {
for i := 1 ; i < serversCount ; i ++ {
if serversInfo . inner [ i - 1 ] . rtt . Value ( ) > serversInfo . inner [ i ] . rtt . Value ( ) {
serversInfo . inner [ i - 1 ] , serversInfo . inner [ i ] = serversInfo . inner [ i ] , serversInfo . inner [ i - 1 ]
}
}
2018-01-10 16:42:14 +01:00
}
2019-06-03 13:04:34 +02:00
}
func ( serversInfo * ServersInfo ) getOne ( ) * ServerInfo {
serversInfo . Lock ( )
serversCount := len ( serversInfo . inner )
if serversCount <= 0 {
2019-11-05 00:37:46 +01:00
serversInfo . Unlock ( )
2019-06-03 13:04:34 +02:00
return nil
}
if serversInfo . lbEstimator {
2019-10-20 17:17:21 +02:00
serversInfo . estimatorUpdate ( )
2019-06-03 13:04:34 +02:00
}
2020-03-20 17:37:34 +01:00
candidate := serversInfo . lbStrategy . getCandidate ( serversCount )
2018-03-02 02:30:25 +01:00
serverInfo := serversInfo . inner [ candidate ]
2019-06-03 17:32:54 +02:00
dlog . Debugf ( "Using candidate [%s] RTT: %d" , ( * serverInfo ) . Name , int ( ( * serverInfo ) . rtt . Value ( ) ) )
2019-11-05 00:37:46 +01:00
serversInfo . Unlock ( )
2018-02-22 14:20:59 +01:00
2018-01-09 16:59:06 +01:00
return serverInfo
}
2019-10-18 19:00:48 +02:00
func fetchServerInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2018-04-14 15:03:21 +02:00
if stamp . Proto == stamps . StampProtoTypeDNSCrypt {
2019-10-18 19:00:48 +02:00
return fetchDNSCryptServerInfo ( proxy , name , stamp , isNew )
2018-04-14 15:03:21 +02:00
} else if stamp . Proto == stamps . StampProtoTypeDoH {
2019-10-18 19:00:48 +02:00
return fetchDoHServerInfo ( proxy , name , stamp , isNew )
2021-03-30 11:03:25 +02:00
} else if stamp . Proto == stamps . StampProtoTypeODoHTarget {
return fetchODoHTargetInfo ( proxy , name , stamp , isNew )
2018-01-27 15:26:08 +01:00
}
2020-12-12 22:19:09 +01:00
return ServerInfo { } , fmt . Errorf ( "Unsupported protocol for [%s]: [%s]" , name , stamp . Proto . String ( ) )
2018-01-27 15:26:08 +01:00
}
2021-01-03 13:01:44 +01:00
func findFarthestRoute ( proxy * Proxy , name string , relayStamps [ ] stamps . ServerStamp ) * stamps . ServerStamp {
2021-01-03 16:22:23 +01:00
serverIdx := - 1
2021-01-03 16:40:38 +01:00
proxy . serversInfo . RLock ( )
for i , registeredServer := range proxy . serversInfo . registeredServers {
2021-01-03 13:01:44 +01:00
if registeredServer . name == name {
2021-01-03 16:22:23 +01:00
serverIdx = i
2021-01-03 13:01:44 +01:00
break
}
}
2021-01-03 16:22:23 +01:00
if serverIdx < 0 {
2021-01-03 13:01:44 +01:00
return nil
}
2021-01-03 16:40:38 +01:00
server := proxy . serversInfo . registeredServers [ serverIdx ]
proxy . serversInfo . RUnlock ( )
2021-06-07 11:00:21 +02:00
// Fall back to random relays until the logic is implementeed for non-DNSCrypt relays
2021-06-07 11:06:41 +02:00
if server . stamp . Proto == stamps . StampProtoTypeODoHTarget {
candidates := make ( [ ] int , 0 )
for relayIdx , relayStamp := range relayStamps {
if relayStamp . Proto != stamps . StampProtoTypeODoHRelay {
continue
}
candidates = append ( candidates , relayIdx )
}
return & relayStamps [ candidates [ rand . Intn ( len ( candidates ) ) ] ]
} else if server . stamp . Proto != stamps . StampProtoTypeDNSCrypt {
return nil
2021-06-07 11:00:21 +02:00
}
2021-08-03 11:24:16 +02:00
// Anonymized DNSCrypt relays
2021-01-03 13:01:44 +01:00
serverAddrStr , _ := ExtractHostAndPort ( server . stamp . ServerAddrStr , 443 )
serverAddr := net . ParseIP ( serverAddrStr )
if serverAddr == nil {
return nil
}
2021-01-09 22:44:32 +01:00
if len ( proxy . serversInfo . registeredRelays ) == 0 {
2021-01-03 13:01:44 +01:00
return nil
}
bestRelayIdxs := make ( [ ] int , 0 )
bestRelaySamePrefixBits := 128
for relayIdx , relayStamp := range relayStamps {
2021-06-07 11:06:41 +02:00
if relayStamp . Proto != stamps . StampProtoTypeDNSCryptRelay {
continue
}
2021-01-03 13:01:44 +01:00
relayAddrStr , _ := ExtractHostAndPort ( relayStamp . ServerAddrStr , 443 )
relayAddr := net . ParseIP ( relayAddrStr )
if relayAddr == nil {
continue
}
relayIsIPv6 := relayAddr . To4 ( ) == nil
if relayIsIPv6 != ( serverAddr . To4 ( ) == nil ) {
continue
}
firstByte := 0
if ! relayIsIPv6 {
firstByte = 12
}
samePrefixBits := 0
for i := firstByte ; i < 16 ; i ++ {
x := serverAddr [ i ] ^ relayAddr [ i ]
samePrefixBits += bits . LeadingZeros8 ( x )
if x != 0 {
break
}
}
if samePrefixBits <= bestRelaySamePrefixBits {
bestRelaySamePrefixBits = samePrefixBits
bestRelayIdxs = append ( bestRelayIdxs , relayIdx )
}
}
return & relayStamps [ bestRelayIdxs [ rand . Intn ( len ( bestRelayIdxs ) ) ] ]
}
2021-06-08 10:52:06 +02:00
func relayProtoForServerProto ( proto stamps . StampProtoType ) ( stamps . StampProtoType , error ) {
switch proto {
case stamps . StampProtoTypeDNSCrypt :
return stamps . StampProtoTypeDNSCryptRelay , nil
case stamps . StampProtoTypeODoHTarget :
return stamps . StampProtoTypeODoHRelay , nil
default :
return 0 , errors . New ( "protocol cannot be anonymized" )
}
}
func route ( proxy * Proxy , name string , serverProto stamps . StampProtoType ) ( * Relay , error ) {
2019-10-20 12:26:12 +02:00
routes := proxy . routes
if routes == nil {
2020-12-12 21:18:32 +01:00
return nil , nil
2019-10-20 12:26:12 +02:00
}
2021-01-03 13:33:51 +01:00
wildcard := false
2019-10-20 12:26:12 +02:00
relayNames , ok := ( * routes ) [ name ]
2019-10-20 14:19:21 +02:00
if ! ok {
2021-01-03 13:33:51 +01:00
wildcard = true
2019-10-20 14:19:21 +02:00
relayNames , ok = ( * routes ) [ "*" ]
}
2021-06-08 10:27:03 +02:00
if ! ok || len ( relayNames ) == 0 {
2020-12-12 21:18:32 +01:00
return nil , nil
2019-10-20 12:26:12 +02:00
}
2021-06-08 10:52:06 +02:00
relayProto , err := relayProtoForServerProto ( serverProto )
if err != nil {
dlog . Errorf ( "Server [%v]'s protocol doesn't support anonymization" , name )
return nil , nil
}
2021-01-03 13:01:44 +01:00
relayStamps := make ( [ ] stamps . ServerStamp , 0 )
for _ , relayName := range relayNames {
if relayStamp , err := stamps . NewServerStampFromString ( relayName ) ; err == nil {
2021-06-08 10:52:06 +02:00
if relayStamp . Proto == relayProto {
relayStamps = append ( relayStamps , relayStamp )
}
2021-01-03 13:01:44 +01:00
} else if relayName == "*" {
2021-01-09 22:44:32 +01:00
proxy . serversInfo . RLock ( )
for _ , registeredServer := range proxy . serversInfo . registeredRelays {
2021-06-08 10:52:06 +02:00
if registeredServer . stamp . Proto == relayProto {
relayStamps = append ( relayStamps , registeredServer . stamp )
}
2019-10-20 14:19:21 +02:00
}
2021-01-09 22:44:32 +01:00
proxy . serversInfo . RUnlock ( )
2021-01-03 13:33:51 +01:00
wildcard = true
break
2021-01-03 13:01:44 +01:00
} else {
2021-01-09 22:44:32 +01:00
proxy . serversInfo . RLock ( )
for _ , registeredServer := range proxy . serversInfo . registeredRelays {
2021-06-08 10:52:06 +02:00
if registeredServer . name == relayName && registeredServer . stamp . Proto == relayProto {
2021-01-03 13:01:44 +01:00
relayStamps = append ( relayStamps , registeredServer . stamp )
break
}
}
2021-01-03 16:40:38 +01:00
for _ , registeredServer := range proxy . serversInfo . registeredServers {
2021-06-08 10:52:06 +02:00
if registeredServer . name == relayName && registeredServer . stamp . Proto == relayProto {
2021-01-03 13:01:44 +01:00
relayStamps = append ( relayStamps , registeredServer . stamp )
break
}
2019-10-20 12:26:12 +02:00
}
2021-01-03 16:40:38 +01:00
proxy . serversInfo . RUnlock ( )
2019-10-20 12:26:12 +02:00
}
}
2021-01-03 13:01:44 +01:00
if len ( relayStamps ) == 0 {
2021-06-08 10:52:06 +02:00
dlog . Warnf ( "Empty relay set for [%v]" , name )
return nil , nil
2021-01-03 13:01:44 +01:00
}
2021-01-03 13:33:51 +01:00
var relayCandidateStamp * stamps . ServerStamp
if ! wildcard || len ( relayStamps ) == 1 {
relayCandidateStamp = & relayStamps [ rand . Intn ( len ( relayStamps ) ) ]
} else {
relayCandidateStamp = findFarthestRoute ( proxy , name , relayStamps )
}
2019-10-20 12:26:12 +02:00
if relayCandidateStamp == nil {
2021-01-03 13:01:44 +01:00
return nil , fmt . Errorf ( "No valid relay for server [%v]" , name )
2019-10-20 12:26:12 +02:00
}
2021-01-03 13:33:51 +01:00
relayName := relayCandidateStamp . ServerAddrStr
2021-01-09 22:44:32 +01:00
proxy . serversInfo . RLock ( )
for _ , registeredServer := range proxy . serversInfo . registeredRelays {
2022-01-17 19:43:12 +01:00
if registeredServer . stamp . Proto == relayProto && registeredServer . stamp . ServerAddrStr == relayCandidateStamp . ServerAddrStr {
2021-01-03 13:33:51 +01:00
relayName = registeredServer . name
break
}
}
2021-01-09 22:44:32 +01:00
proxy . serversInfo . RUnlock ( )
2020-12-12 21:18:32 +01:00
switch relayCandidateStamp . Proto {
2020-12-26 17:55:31 +01:00
case stamps . StampProtoTypeDNSCrypt , stamps . StampProtoTypeDNSCryptRelay :
2019-10-20 12:26:12 +02:00
relayUDPAddr , err := net . ResolveUDPAddr ( "udp" , relayCandidateStamp . ServerAddrStr )
if err != nil {
2020-12-12 21:18:32 +01:00
return nil , err
2019-10-20 12:26:12 +02:00
}
relayTCPAddr , err := net . ResolveTCPAddr ( "tcp" , relayCandidateStamp . ServerAddrStr )
if err != nil {
2020-12-12 21:18:32 +01:00
return nil , err
2019-10-20 12:26:12 +02:00
}
2021-01-03 13:33:51 +01:00
dlog . Noticef ( "Anonymizing queries for [%v] via [%v]" , name , relayName )
2020-12-12 21:18:32 +01:00
return & Relay { Proto : stamps . StampProtoTypeDNSCryptRelay , Dnscrypt : & DNSCryptRelay { RelayUDPAddr : relayUDPAddr , RelayTCPAddr : relayTCPAddr } } , nil
2020-12-12 21:57:04 +01:00
case stamps . StampProtoTypeODoHRelay :
2021-06-07 10:46:01 +02:00
relayBaseURL , err := url . Parse ( "https://" + url . PathEscape ( relayCandidateStamp . ProviderName ) + relayCandidateStamp . Path )
2021-03-30 11:03:25 +02:00
if err != nil {
return nil , err
}
2021-06-07 10:46:01 +02:00
var relayURLforTarget * url . URL
2021-03-30 11:03:25 +02:00
for _ , server := range proxy . registeredServers {
2021-06-07 10:46:01 +02:00
if server . name != name || server . stamp . Proto != stamps . StampProtoTypeODoHTarget {
continue
2021-03-30 11:03:25 +02:00
}
2021-06-07 10:46:01 +02:00
qs := relayBaseURL . Query ( )
qs . Add ( "targethost" , server . stamp . ProviderName )
qs . Add ( "targetpath" , server . stamp . Path )
tmp := * relayBaseURL
tmp . RawQuery = qs . Encode ( )
relayURLforTarget = & tmp
break
2021-03-30 11:03:25 +02:00
}
2021-06-07 10:46:01 +02:00
if relayURLforTarget == nil {
return nil , fmt . Errorf ( "Relay [%v] not found" , relayName )
}
if len ( relayCandidateStamp . ServerAddrStr ) > 0 {
ipOnly , _ := ExtractHostAndPort ( relayCandidateStamp . ServerAddrStr , - 1 )
if ip := ParseIP ( ipOnly ) ; ip != nil {
2021-09-06 12:02:56 +02:00
host , _ := ExtractHostAndPort ( relayCandidateStamp . ProviderName , - 1 )
proxy . xTransport . saveCachedIP ( host , ip , - 1 * time . Second )
2021-06-07 10:46:01 +02:00
}
}
dlog . Noticef ( "Anonymizing queries for [%v] via [%v]" , name , relayName )
2021-03-30 11:03:25 +02:00
return & Relay { Proto : stamps . StampProtoTypeODoHRelay , ODoH : & ODoHRelay {
2021-06-07 10:46:01 +02:00
URL : relayURLforTarget ,
2021-03-30 11:03:25 +02:00
} } , nil
2019-10-20 12:26:12 +02:00
}
2021-01-03 13:01:44 +01:00
return nil , fmt . Errorf ( "Invalid relay set for server [%v]" , name )
2019-10-20 12:26:12 +02:00
}
2019-10-18 19:00:48 +02:00
func fetchDNSCryptServerInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2018-04-14 15:03:21 +02:00
if len ( stamp . ServerPk ) != ed25519 . PublicKeySize {
serverPk , err := hex . DecodeString ( strings . Replace ( string ( stamp . ServerPk ) , ":" , "" , - 1 ) )
2018-04-01 16:35:32 +02:00
if err != nil || len ( serverPk ) != ed25519 . PublicKeySize {
2018-04-14 15:03:21 +02:00
dlog . Fatalf ( "Unsupported public key for [%s]: [%s]" , name , stamp . ServerPk )
2018-04-01 16:35:32 +02:00
}
2018-04-14 15:03:21 +02:00
dlog . Warnf ( "Public key [%s] shouldn't be hex-encoded any more" , string ( stamp . ServerPk ) )
stamp . ServerPk = serverPk
2018-04-01 16:35:32 +02:00
}
2019-11-16 18:51:16 +01:00
knownBugs := ServerBugs { }
2020-03-25 20:09:46 +01:00
for _ , buggyServerName := range proxy . serversBlockingFragments {
2019-11-16 18:51:16 +01:00
if buggyServerName == name {
2020-03-25 20:09:46 +01:00
knownBugs . fragmentsBlocked = true
dlog . Infof ( "Known bug in [%v]: fragmented questions over UDP are blocked" , name )
break
}
}
2021-06-08 10:52:06 +02:00
relay , err := route ( proxy , name , stamp . Proto )
2019-10-20 12:26:12 +02:00
if err != nil {
return ServerInfo { } , err
2019-10-14 01:45:38 +02:00
}
2020-12-12 21:18:32 +01:00
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 )
2020-03-25 20:09:46 +01:00
if ! knownBugs . fragmentsBlocked && fragmentsBlocked {
2020-03-13 19:45:25 +01:00
dlog . Debugf ( "[%v] drops fragmented queries" , name )
2020-03-25 20:09:46 +01:00
knownBugs . fragmentsBlocked = true
2020-03-24 14:19:41 +01:00
}
2020-12-12 21:18:32 +01:00
if knownBugs . fragmentsBlocked && relay != nil && relay . Dnscrypt != nil {
relay = nil
2021-01-03 16:00:02 +01:00
if proxy . skipAnonIncompatibleResolvers {
dlog . Infof ( "[%v] couldn't be reached anonymously, it will be ignored" , name )
return ServerInfo { } , errors . New ( "Resolver couldn't be reached anonymously" )
2020-03-26 13:41:57 +01:00
}
2021-01-03 16:58:21 +01:00
dlog . Warnf ( "[%v] couldn't be reached anonymously" , name )
2020-03-13 19:45:25 +01:00
}
2019-10-19 23:50:05 +02:00
if err != nil {
return ServerInfo { } , err
}
remoteUDPAddr , err := net . ResolveUDPAddr ( "udp" , stamp . ServerAddrStr )
if err != nil {
return ServerInfo { } , err
}
remoteTCPAddr , err := net . ResolveTCPAddr ( "tcp" , stamp . ServerAddrStr )
if err != nil {
return ServerInfo { } , err
}
2018-04-01 16:35:32 +02:00
return ServerInfo {
2018-04-14 15:03:21 +02:00
Proto : stamps . StampProtoTypeDNSCrypt ,
2018-04-01 16:35:32 +02:00
MagicQuery : certInfo . MagicQuery ,
ServerPk : certInfo . ServerPk ,
SharedKey : certInfo . SharedKey ,
CryptoConstruction : certInfo . CryptoConstruction ,
Name : name ,
Timeout : proxy . timeout ,
UDPAddr : remoteUDPAddr ,
TCPAddr : remoteTCPAddr ,
2020-12-12 21:18:32 +01:00
Relay : relay ,
2018-04-01 16:35:32 +02:00
initialRtt : rtt ,
2019-11-16 18:51:16 +01:00
knownBugs : knownBugs ,
2018-04-01 16:35:32 +02:00
} , nil
}
2020-02-21 20:24:24 +01:00
func dohTestPacket ( msgID uint16 ) [ ] byte {
msg := dns . Msg { }
msg . SetQuestion ( "." , dns . TypeNS )
msg . Id = msgID
msg . MsgHdr . RecursionDesired = true
msg . SetEdns0 ( uint16 ( MaxDNSPacketSize ) , false )
ext := new ( dns . EDNS0_PADDING )
ext . Padding = make ( [ ] byte , 16 )
crypto_rand . Read ( ext . Padding )
edns0 := msg . IsEdns0 ( )
edns0 . Option = append ( edns0 . Option , ext )
body , err := msg . Pack ( )
if err != nil {
dlog . Fatal ( err )
}
return body
}
2020-08-05 14:39:09 +02:00
func dohNXTestPacket ( msgID uint16 ) [ ] byte {
msg := dns . Msg { }
qName := make ( [ ] byte , 16 )
charset := "abcdefghijklmnopqrstuvwxyz"
for i := range qName {
qName [ i ] = charset [ rand . Intn ( len ( charset ) ) ]
}
2020-08-05 15:03:16 +02:00
msg . SetQuestion ( string ( qName ) + ".test.dnscrypt." , dns . TypeNS )
2020-08-05 14:39:09 +02:00
msg . Id = msgID
msg . MsgHdr . RecursionDesired = true
msg . SetEdns0 ( uint16 ( MaxDNSPacketSize ) , false )
ext := new ( dns . EDNS0_PADDING )
ext . Padding = make ( [ ] byte , 16 )
crypto_rand . Read ( ext . Padding )
edns0 := msg . IsEdns0 ( )
edns0 . Option = append ( edns0 . Option , ext )
body , err := msg . Pack ( )
if err != nil {
dlog . Fatal ( err )
}
return body
}
2019-10-18 19:00:48 +02:00
func fetchDoHServerInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2019-11-03 00:33:17 +01:00
// If an IP has been provided, use it forever.
// Or else, if the fallback server and the DoH server are operated
// by the same entity, it could provide a unique IPv6 for each client
// in order to fingerprint clients across multiple IP addresses.
2018-04-14 15:03:21 +02:00
if len ( stamp . ServerAddrStr ) > 0 {
2019-10-20 17:11:08 +02:00
ipOnly , _ := ExtractHostAndPort ( stamp . ServerAddrStr , - 1 )
2019-10-20 17:09:14 +02:00
if ip := ParseIP ( ipOnly ) ; ip != nil {
2021-09-06 12:02:56 +02:00
host , _ := ExtractHostAndPort ( stamp . ProviderName , - 1 )
proxy . xTransport . saveCachedIP ( host , ip , - 1 * time . Second )
2019-10-20 17:09:14 +02:00
}
2018-01-29 03:58:39 +01:00
}
2018-01-27 15:26:08 +01:00
url := & url . URL {
Scheme : "https" ,
2018-04-14 15:03:21 +02:00
Host : stamp . ProviderName ,
Path : stamp . Path ,
2018-01-27 15:26:08 +01:00
}
2020-02-21 20:24:24 +01:00
body := dohTestPacket ( 0xcafe )
2018-02-05 11:30:10 +01:00
useGet := false
2021-03-30 11:03:25 +02:00
if _ , _ , _ , _ , err := proxy . xTransport . DoHQuery ( useGet , url , body , proxy . timeout ) ; err != nil {
2018-02-05 11:30:10 +01:00
useGet = true
2021-03-30 11:03:25 +02:00
if _ , _ , _ , _ , err := proxy . xTransport . DoHQuery ( useGet , url , body , proxy . timeout ) ; err != nil {
2018-02-05 11:30:10 +01:00
return ServerInfo { } , err
}
dlog . Debugf ( "Server [%s] doesn't appear to support POST; falling back to GET requests" , name )
2018-01-27 16:48:22 +01:00
}
2020-08-05 14:39:09 +02:00
body = dohNXTestPacket ( 0xcafe )
2021-03-30 11:03:25 +02:00
serverResponse , _ , tls , rtt , err := proxy . xTransport . DoHQuery ( useGet , url , body , proxy . timeout )
2018-01-30 15:46:21 +01:00
if err != nil {
2020-08-05 15:50:48 +02:00
dlog . Infof ( "[%s] [%s]: %v" , name , url , err )
2018-01-27 15:26:08 +01:00
return ServerInfo { } , err
}
2018-01-27 17:48:53 +01:00
if tls == nil || ! tls . HandshakeComplete {
return ServerInfo { } , errors . New ( "TLS handshake failed" )
}
2020-08-05 14:39:09 +02:00
msg := dns . Msg { }
if err := msg . Unpack ( serverResponse ) ; err != nil {
2020-08-05 15:39:30 +02:00
dlog . Warnf ( "[%s]: %v" , name , err )
2020-08-05 14:39:09 +02:00
return ServerInfo { } , err
}
if msg . Rcode != dns . RcodeNameError {
dlog . Criticalf ( "[%s] may be a lying resolver" , name )
}
2019-05-12 09:55:13 +02:00
protocol := tls . NegotiatedProtocol
2020-12-17 01:13:11 +01:00
if len ( protocol ) == 0 {
protocol = "http/1.x"
}
if strings . HasPrefix ( protocol , "http/1." ) {
2019-05-12 09:55:13 +02:00
dlog . Warnf ( "[%s] does not support HTTP/2" , name )
}
dlog . Infof ( "[%s] TLS version: %x - Protocol: %v - Cipher suite: %v" , name , tls . Version , protocol , tls . CipherSuite )
2019-06-07 01:23:48 +02:00
showCerts := proxy . showCerts
2018-01-27 17:48:53 +01:00
found := false
var wantedHash [ 32 ] byte
for _ , cert := range tls . PeerCertificates {
h := sha256 . Sum256 ( cert . RawTBSCertificate )
2018-02-05 13:24:17 +01:00
if showCerts {
2019-06-07 01:23:48 +02:00
dlog . Noticef ( "Advertised cert: [%s] [%x]" , cert . Subject , h )
2018-02-05 13:24:17 +01:00
} else {
dlog . Debugf ( "Advertised cert: [%s] [%x]" , cert . Subject , h )
}
2018-04-14 15:03:21 +02:00
for _ , hash := range stamp . Hashes {
2018-01-31 18:16:54 +01:00
if len ( hash ) == len ( wantedHash ) {
copy ( wantedHash [ : ] , hash )
if h == wantedHash {
found = true
break
}
}
}
if found {
2018-01-27 17:48:53 +01:00
break
}
}
2018-04-14 15:03:21 +02:00
if ! found && len ( stamp . Hashes ) > 0 {
2020-08-05 15:39:30 +02:00
dlog . Criticalf ( "[%s] Certificate hash [%x] not found" , name , wantedHash )
return ServerInfo { } , fmt . Errorf ( "Certificate hash not found" )
2018-01-27 17:48:53 +01:00
}
2021-06-07 11:47:11 +02:00
if len ( serverResponse ) < MinDNSPacketSize || len ( serverResponse ) > MaxDNSPacketSize ||
serverResponse [ 0 ] != 0xca || serverResponse [ 1 ] != 0xfe || serverResponse [ 4 ] != 0x00 || serverResponse [ 5 ] != 0x01 {
2020-08-05 15:39:30 +02:00
dlog . Info ( "Webserver returned an unexpected response" )
2018-01-27 15:26:08 +01:00
return ServerInfo { } , errors . New ( "Webserver returned an unexpected response" )
}
2019-06-03 17:07:30 +02:00
xrtt := int ( rtt . Nanoseconds ( ) / 1000000 )
2018-01-31 00:19:53 +01:00
if isNew {
2019-06-03 17:07:30 +02:00
dlog . Noticef ( "[%s] OK (DoH) - rtt: %dms" , name , xrtt )
2018-01-31 00:19:53 +01:00
} else {
2019-06-03 17:07:30 +02:00
dlog . Infof ( "[%s] OK (DoH) - rtt: %dms" , name , xrtt )
2018-01-31 00:19:53 +01:00
}
2018-03-17 22:47:17 +01:00
return ServerInfo {
2018-04-14 15:03:21 +02:00
Proto : stamps . StampProtoTypeDoH ,
2018-01-27 15:26:08 +01:00
Name : name ,
Timeout : proxy . timeout ,
URL : url ,
2018-04-14 15:03:21 +02:00
HostName : stamp . ProviderName ,
2019-06-03 17:07:30 +02:00
initialRtt : xrtt ,
2018-02-05 11:30:10 +01:00
useGet : useGet ,
2018-03-17 22:47:17 +01:00
} , nil
2018-01-27 15:26:08 +01:00
}
2021-06-07 10:05:20 +02:00
func fetchTargetConfigsFromWellKnown ( proxy * Proxy , url * url . URL ) ( [ ] ODoHTargetConfig , error ) {
bin , statusCode , _ , _ , err := proxy . xTransport . Get ( url , "application/binary" , 0 )
2021-03-30 11:03:25 +02:00
if err != nil {
return nil , err
}
2021-06-07 10:05:20 +02:00
if statusCode < 200 || statusCode >= 300 {
return nil , fmt . Errorf ( "HTTP status code was %v" , statusCode )
2021-03-30 11:03:25 +02:00
}
2021-06-07 10:05:20 +02:00
return parseODoHTargetConfigs ( bin )
2021-03-30 11:03:25 +02:00
}
2021-06-07 12:02:21 +02:00
func _fetchODoHTargetInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2021-06-07 10:46:01 +02:00
configURL := & url . URL { Scheme : "https" , Host : stamp . ProviderName , Path : "/.well-known/odohconfigs" }
odohTargetConfigs , err := fetchTargetConfigsFromWellKnown ( proxy , configURL )
2021-06-08 10:18:51 +02:00
if err != nil {
dlog . Debug ( configURL )
return ServerInfo { } , fmt . Errorf ( "[%s] didn't return an ODoH configuration - [%v]" , name , err )
} else if len ( odohTargetConfigs ) == 0 {
dlog . Debug ( configURL )
return ServerInfo { } , fmt . Errorf ( "[%s] has an empty ODoH configuration" , name )
2021-03-30 11:03:25 +02:00
}
2021-06-08 10:52:06 +02:00
relay , err := route ( proxy , name , stamp . Proto )
2021-03-30 11:03:25 +02:00
if err != nil {
return ServerInfo { } , err
}
if relay == nil {
2021-06-08 10:27:03 +02:00
dlog . Criticalf ( "No relay defined for [%v] - Configuring a relay is required for ODoH servers (see the `[anonymized_dns]` section)" , name )
return ServerInfo { } , errors . New ( "No ODoH relay" )
} else {
2021-06-08 10:18:51 +02:00
if relay . ODoH == nil {
dlog . Criticalf ( "Wrong relay type defined for [%v] - ODoH servers require an ODoH relay" , name )
2021-06-08 10:27:03 +02:00
return ServerInfo { } , errors . New ( "Wrong ODoH relay type" )
2021-06-08 10:18:51 +02:00
}
2021-03-30 11:03:25 +02:00
}
2021-06-08 10:18:51 +02:00
dlog . Debugf ( "Pausing after ODoH configuration retrieval" )
delay := time . Duration ( rand . Intn ( 5 * 1000 ) ) * time . Millisecond
clocksmith . Sleep ( time . Duration ( delay ) )
dlog . Debugf ( "Pausing done" )
2021-06-07 12:23:26 +02:00
targetURL := & url . URL {
2021-03-30 11:03:25 +02:00
Scheme : "https" ,
Host : stamp . ProviderName ,
Path : stamp . Path ,
}
2021-06-07 12:02:21 +02:00
workingConfigs := make ( [ ] ODoHTargetConfig , 0 )
2021-06-07 12:05:42 +02:00
rand . Shuffle ( len ( odohTargetConfigs ) , func ( i , j int ) {
odohTargetConfigs [ i ] , odohTargetConfigs [ j ] = odohTargetConfigs [ j ] , odohTargetConfigs [ i ]
} )
2021-06-07 11:47:11 +02:00
for _ , odohTargetConfig := range odohTargetConfigs {
2021-06-08 10:18:51 +02:00
url := relay . ODoH . URL
2021-06-07 13:42:33 +02:00
query := dohTestPacket ( 0xcafe )
2021-06-07 11:47:11 +02:00
odohQuery , err := odohTargetConfig . encryptQuery ( query )
if err != nil {
continue
}
2021-06-07 13:42:33 +02:00
2021-06-07 17:19:56 +02:00
useGet := false
2021-06-07 17:32:34 +02:00
if _ , _ , _ , _ , err := proxy . xTransport . ObliviousDoHQuery ( useGet , url , odohQuery . odohMessage , proxy . timeout ) ; err != nil {
2021-06-07 13:42:33 +02:00
useGet = true
2021-06-07 17:32:34 +02:00
if _ , _ , _ , _ , err := proxy . xTransport . ObliviousDoHQuery ( useGet , url , odohQuery . odohMessage , proxy . timeout ) ; err != nil {
2021-06-07 13:44:08 +02:00
continue
2021-06-07 13:42:33 +02:00
}
dlog . Debugf ( "Server [%s] doesn't appear to support POST; falling back to GET requests" , name )
}
query = dohNXTestPacket ( 0xcafe )
odohQuery , err = odohTargetConfig . encryptQuery ( query )
if err != nil {
continue
2021-06-07 12:23:26 +02:00
}
2021-06-07 13:42:33 +02:00
2021-06-07 11:47:11 +02:00
responseBody , responseCode , tls , rtt , err := proxy . xTransport . ObliviousDoHQuery ( useGet , url , odohQuery . odohMessage , proxy . timeout )
if err != nil {
continue
}
if responseCode == 401 {
2021-06-07 12:02:21 +02:00
return ServerInfo { } , fmt . Errorf ( "Configuration changed during a probe" )
2021-06-07 11:47:11 +02:00
}
serverResponse , err := odohQuery . decryptResponse ( responseBody )
if err != nil {
dlog . Warnf ( "Unable to decrypt response from [%v]: [%v]" , name , err )
continue
}
2021-06-07 12:02:21 +02:00
workingConfigs = append ( workingConfigs , odohTargetConfig )
2021-06-07 11:47:11 +02:00
msg := dns . Msg { }
if err := msg . Unpack ( serverResponse ) ; err != nil {
dlog . Warnf ( "[%s]: %v" , name , err )
return ServerInfo { } , err
}
if msg . Rcode != dns . RcodeNameError {
dlog . Criticalf ( "[%s] may be a lying resolver" , name )
}
protocol := tls . NegotiatedProtocol
if len ( protocol ) == 0 {
protocol = "http/1.x"
}
if strings . HasPrefix ( protocol , "http/1." ) {
dlog . Warnf ( "[%s] does not support HTTP/2" , name )
}
dlog . Infof ( "[%s] TLS version: %x - Protocol: %v - Cipher suite: %v" , name , tls . Version , protocol , tls . CipherSuite )
2021-06-07 12:09:27 +02:00
showCerts := proxy . showCerts
found := false
var wantedHash [ 32 ] byte
for _ , cert := range tls . PeerCertificates {
h := sha256 . Sum256 ( cert . RawTBSCertificate )
if showCerts {
dlog . Noticef ( "Advertised relay cert: [%s] [%x]" , cert . Subject , h )
} else {
dlog . Debugf ( "Advertised relay cert: [%s] [%x]" , cert . Subject , h )
}
for _ , hash := range stamp . Hashes {
if len ( hash ) == len ( wantedHash ) {
copy ( wantedHash [ : ] , hash )
if h == wantedHash {
found = true
break
}
}
}
if found {
break
}
}
if ! found && len ( stamp . Hashes ) > 0 {
dlog . Criticalf ( "[%s] Certificate hash [%x] not found" , name , wantedHash )
return ServerInfo { } , fmt . Errorf ( "Certificate hash not found" )
}
2021-06-07 11:47:11 +02:00
if len ( serverResponse ) < MinDNSPacketSize || len ( serverResponse ) > MaxDNSPacketSize ||
serverResponse [ 0 ] != 0xca || serverResponse [ 1 ] != 0xfe || serverResponse [ 4 ] != 0x00 || serverResponse [ 5 ] != 0x01 {
dlog . Info ( "Webserver returned an unexpected response" )
return ServerInfo { } , errors . New ( "Webserver returned an unexpected response" )
}
xrtt := int ( rtt . Nanoseconds ( ) / 1000000 )
if isNew {
dlog . Noticef ( "[%s] OK (ODoH) - rtt: %dms" , name , xrtt )
} else {
dlog . Infof ( "[%s] OK (ODoH) - rtt: %dms" , name , xrtt )
}
return ServerInfo {
Proto : stamps . StampProtoTypeODoHTarget ,
Name : name ,
Timeout : proxy . timeout ,
2021-06-07 12:23:26 +02:00
URL : targetURL ,
2021-06-07 11:47:11 +02:00
HostName : stamp . ProviderName ,
initialRtt : xrtt ,
useGet : useGet ,
Relay : relay ,
2021-06-07 12:02:21 +02:00
odohTargetConfigs : workingConfigs ,
2021-06-07 11:47:11 +02:00
} , nil
}
return ServerInfo { } , fmt . Errorf ( "No valid network configuration for [%v]" , name )
2021-03-30 11:03:25 +02:00
}
2021-06-07 12:02:21 +02:00
func fetchODoHTargetInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
var err error
var serverInfo ServerInfo
2021-06-07 13:49:37 +02:00
for i := 0 ; i < 3 ; i += 1 {
2021-06-07 12:02:21 +02:00
serverInfo , err = _fetchODoHTargetInfo ( proxy , name , stamp , isNew )
if err == nil {
break
}
dlog . Infof ( "Trying to fetch the [%v] configuration again" , name )
}
2021-06-07 12:38:36 +02:00
return serverInfo , err
2021-06-07 12:02:21 +02:00
}
2018-01-10 16:42:14 +01:00
func ( serverInfo * ServerInfo ) noticeFailure ( proxy * Proxy ) {
2019-10-26 17:28:24 +02:00
proxy . serversInfo . Lock ( )
2018-02-21 00:14:18 +01:00
serverInfo . rtt . Add ( float64 ( proxy . timeout . Nanoseconds ( ) / 1000000 ) )
2019-10-26 17:28:24 +02:00
proxy . serversInfo . Unlock ( )
2018-01-10 16:42:14 +01:00
}
func ( serverInfo * ServerInfo ) noticeBegin ( proxy * Proxy ) {
2019-10-26 17:28:24 +02:00
proxy . serversInfo . Lock ( )
2018-01-10 16:42:14 +01:00
serverInfo . lastActionTS = time . Now ( )
2019-10-26 17:28:24 +02:00
proxy . serversInfo . Unlock ( )
2018-01-10 16:42:14 +01:00
}
func ( serverInfo * ServerInfo ) noticeSuccess ( proxy * Proxy ) {
now := time . Now ( )
2019-10-26 17:28:24 +02:00
proxy . serversInfo . Lock ( )
2018-02-21 00:14:18 +01:00
elapsed := now . Sub ( serverInfo . lastActionTS )
elapsedMs := elapsed . Nanoseconds ( ) / 1000000
if elapsedMs > 0 && elapsed < proxy . timeout {
serverInfo . rtt . Add ( float64 ( elapsedMs ) )
2018-01-10 16:42:14 +01:00
}
2019-10-26 17:28:24 +02:00
proxy . serversInfo . Unlock ( )
2018-01-10 16:01:29 +01:00
}