dnscrypt-proxy/dnscrypt-proxy/serversInfo.go

175 lines
4.6 KiB
Go
Raw Normal View History

package main
import (
"encoding/hex"
2018-01-13 23:52:44 +01:00
"fmt"
"math/rand"
"net"
"strings"
"sync"
"time"
"github.com/VividCortex/ewma"
2018-01-11 11:50:54 +01:00
"github.com/jedisct1/dlog"
"golang.org/x/crypto/ed25519"
)
const (
RTTEwmaDecay = 10.0
2018-01-13 23:52:44 +01:00
DefaultPort = 443
)
type ServerStamp struct {
serverAddrStr string
serverPkStr string
providerName string
}
type RegisteredServer struct {
name string
stamp ServerStamp
}
func NewServerStampFromLegacy(serverAddrStr string, serverPkStr string, providerName string) (ServerStamp, error) {
if net.ParseIP(serverAddrStr) != nil {
2018-01-14 00:17:46 +01:00
serverAddrStr = fmt.Sprintf("%s:%d", serverAddrStr, DefaultPort)
2018-01-13 23:52:44 +01:00
}
return ServerStamp{
serverAddrStr: serverAddrStr,
serverPkStr: serverPkStr,
providerName: providerName,
}, nil
}
type ServerInfo struct {
sync.RWMutex
MagicQuery [8]byte
ServerPk [32]byte
SharedKey [32]byte
CryptoConstruction CryptoConstruction
Name string
Timeout time.Duration
UDPAddr *net.UDPAddr
TCPAddr *net.TCPAddr
lastActionTS time.Time
rtt ewma.MovingAverage
}
type ServersInfo struct {
sync.RWMutex
inner []ServerInfo
registeredServers []RegisteredServer
}
func (serversInfo *ServersInfo) registerServer(proxy *Proxy, name string, stamp ServerStamp) error {
serversInfo.Lock()
defer serversInfo.Unlock()
newServer, err := serversInfo.fetchServerInfo(proxy, name, stamp)
if err != nil {
return err
}
newServer.rtt = ewma.NewMovingAverage(RTTEwmaDecay)
for i, oldServer := range serversInfo.inner {
if oldServer.Name == newServer.Name {
serversInfo.inner[i] = newServer
return nil
}
}
serversInfo.inner = append(serversInfo.inner, newServer)
serversInfo.registeredServers = append(serversInfo.registeredServers, RegisteredServer{name: name, stamp: stamp})
return nil
}
func (serversInfo *ServersInfo) refresh(proxy *Proxy) (int, error) {
2018-01-11 11:50:54 +01:00
dlog.Infof("Refreshing certificates")
serversInfo.RLock()
registeredServers := serversInfo.registeredServers
serversInfo.RUnlock()
liveServers := 0
var err error
for _, registeredServer := range registeredServers {
if err = serversInfo.registerServer(proxy, registeredServer.name, registeredServer.stamp); err == nil {
liveServers++
}
}
return liveServers, err
}
func (serversInfo *ServersInfo) liveServers() int {
serversInfo.RLock()
liveServers := len(serversInfo.registeredServers)
serversInfo.RUnlock()
return liveServers
}
func (serversInfo *ServersInfo) getOne() *ServerInfo {
serversInfo.Lock()
defer serversInfo.Unlock()
2018-01-10 16:01:29 +01:00
serversCount := len(serversInfo.inner)
if serversCount <= 0 {
return nil
}
candidate := rand.Intn(serversCount)
if candidate == 0 {
return &serversInfo.inner[candidate]
}
if serversInfo.inner[candidate].rtt.Value() < serversInfo.inner[0].rtt.Value() {
serversInfo.inner[candidate], serversInfo.inner[0] = serversInfo.inner[0], serversInfo.inner[candidate]
}
2018-01-14 00:34:28 +01:00
candidate = rand.Intn(Max(Min(serversCount, 2), len(serversInfo.inner)))
serverInfo := &serversInfo.inner[candidate]
return serverInfo
}
func (serversInfo *ServersInfo) fetchServerInfo(proxy *Proxy, name string, stamp ServerStamp) (ServerInfo, error) {
serverPk, err := hex.DecodeString(strings.Replace(stamp.serverPkStr, ":", "", -1))
if err != nil || len(serverPk) != ed25519.PublicKeySize {
2018-01-11 11:50:54 +01:00
dlog.Fatalf("Unsupported public key: [%v]", serverPk)
}
certInfo, err := FetchCurrentCert(proxy, proxy.mainProto, serverPk, stamp.serverAddrStr, stamp.providerName)
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
}
serverInfo := ServerInfo{
MagicQuery: certInfo.MagicQuery,
ServerPk: certInfo.ServerPk,
SharedKey: certInfo.SharedKey,
CryptoConstruction: certInfo.CryptoConstruction,
Name: name,
2018-01-10 12:09:59 +01:00
Timeout: proxy.timeout,
UDPAddr: remoteUDPAddr,
TCPAddr: remoteTCPAddr,
}
return serverInfo, nil
}
2018-01-10 16:01:29 +01:00
func (serverInfo *ServerInfo) noticeFailure(proxy *Proxy) {
serverInfo.Lock()
serverInfo.rtt.Set(float64(proxy.timeout.Nanoseconds()))
serverInfo.Unlock()
}
func (serverInfo *ServerInfo) noticeBegin(proxy *Proxy) {
serverInfo.Lock()
serverInfo.lastActionTS = time.Now()
serverInfo.Unlock()
}
func (serverInfo *ServerInfo) noticeSuccess(proxy *Proxy) {
now := time.Now()
serverInfo.Lock()
elapsed := now.Sub(serverInfo.lastActionTS) / 1024
if elapsed > 0 {
serverInfo.rtt.Add(float64(elapsed))
}
serverInfo.Unlock()
2018-01-10 16:01:29 +01:00
}