2018-01-09 16:59:06 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
2018-01-13 23:52:44 +01:00
|
|
|
"fmt"
|
2018-01-09 17:19:03 +01:00
|
|
|
"math/rand"
|
2018-01-09 16:59:06 +01:00
|
|
|
"net"
|
|
|
|
"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"
|
2018-01-09 16:59:06 +01:00
|
|
|
"golang.org/x/crypto/ed25519"
|
|
|
|
)
|
|
|
|
|
2018-01-10 16:42:14 +01:00
|
|
|
const (
|
|
|
|
RTTEwmaDecay = 10.0
|
2018-01-13 23:52:44 +01:00
|
|
|
DefaultPort = 443
|
2018-01-10 16:42:14 +01:00
|
|
|
)
|
|
|
|
|
2018-01-09 17:15:07 +01:00
|
|
|
type ServerStamp struct {
|
|
|
|
serverAddrStr string
|
|
|
|
serverPkStr string
|
|
|
|
providerName string
|
|
|
|
}
|
|
|
|
|
2018-01-09 18:27:04 +01:00
|
|
|
type RegisteredServer struct {
|
|
|
|
name string
|
|
|
|
stamp ServerStamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewServerStampFromLegacy(serverAddrStr string, serverPkStr string, providerName string) (ServerStamp, error) {
|
2018-01-14 00:15:01 +01:00
|
|
|
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
|
|
|
}
|
2018-01-09 17:15:07 +01:00
|
|
|
return ServerStamp{
|
|
|
|
serverAddrStr: serverAddrStr,
|
|
|
|
serverPkStr: serverPkStr,
|
|
|
|
providerName: providerName,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type ServerInfo struct {
|
2018-01-10 16:42:14 +01:00
|
|
|
sync.RWMutex
|
2018-01-09 17:15:07 +01:00
|
|
|
MagicQuery [8]byte
|
|
|
|
ServerPk [32]byte
|
|
|
|
SharedKey [32]byte
|
|
|
|
CryptoConstruction CryptoConstruction
|
|
|
|
Name string
|
|
|
|
Timeout time.Duration
|
|
|
|
UDPAddr *net.UDPAddr
|
|
|
|
TCPAddr *net.TCPAddr
|
2018-01-10 16:42:14 +01:00
|
|
|
lastActionTS time.Time
|
|
|
|
rtt ewma.MovingAverage
|
2018-01-09 17:15:07 +01:00
|
|
|
}
|
|
|
|
|
2018-01-09 16:59:06 +01:00
|
|
|
type ServersInfo struct {
|
|
|
|
sync.RWMutex
|
2018-01-09 18:27:04 +01:00
|
|
|
inner []ServerInfo
|
|
|
|
registeredServers []RegisteredServer
|
2018-01-09 16:59:06 +01:00
|
|
|
}
|
|
|
|
|
2018-01-09 17:34:19 +01:00
|
|
|
func (serversInfo *ServersInfo) registerServer(proxy *Proxy, name string, stamp ServerStamp) error {
|
|
|
|
serversInfo.Lock()
|
|
|
|
defer serversInfo.Unlock()
|
|
|
|
newServer, err := serversInfo.fetchServerInfo(proxy, name, stamp)
|
2018-01-09 16:59:06 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-01-10 16:42:14 +01:00
|
|
|
newServer.rtt = ewma.NewMovingAverage(RTTEwmaDecay)
|
2018-01-09 17:15:07 +01:00
|
|
|
for i, oldServer := range serversInfo.inner {
|
|
|
|
if oldServer.Name == newServer.Name {
|
|
|
|
serversInfo.inner[i] = newServer
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2018-01-09 16:59:06 +01:00
|
|
|
serversInfo.inner = append(serversInfo.inner, newServer)
|
2018-01-09 18:27:04 +01:00
|
|
|
serversInfo.registeredServers = append(serversInfo.registeredServers, RegisteredServer{name: name, stamp: stamp})
|
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-11 11:50:54 +01:00
|
|
|
dlog.Infof("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 17:22:29 +01:00
|
|
|
if err = serversInfo.registerServer(proxy, registeredServer.name, registeredServer.stamp); err == nil {
|
|
|
|
liveServers++
|
|
|
|
}
|
2018-01-09 17:34:19 +01:00
|
|
|
}
|
2018-01-17 17:22:29 +01:00
|
|
|
return liveServers, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (serversInfo *ServersInfo) liveServers() int {
|
|
|
|
serversInfo.RLock()
|
|
|
|
liveServers := len(serversInfo.registeredServers)
|
|
|
|
serversInfo.RUnlock()
|
|
|
|
return liveServers
|
2018-01-09 17:34:19 +01:00
|
|
|
}
|
|
|
|
|
2018-01-09 16:59:06 +01:00
|
|
|
func (serversInfo *ServersInfo) getOne() *ServerInfo {
|
2018-01-10 16:42:14 +01:00
|
|
|
serversInfo.Lock()
|
|
|
|
defer serversInfo.Unlock()
|
2018-01-10 16:01:29 +01:00
|
|
|
serversCount := len(serversInfo.inner)
|
|
|
|
if serversCount <= 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2018-01-10 16:42:14 +01:00
|
|
|
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)))
|
2018-01-10 16:42:14 +01:00
|
|
|
serverInfo := &serversInfo.inner[candidate]
|
2018-01-09 16:59:06 +01:00
|
|
|
return serverInfo
|
|
|
|
}
|
|
|
|
|
2018-01-09 17:34:19 +01:00
|
|
|
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)
|
2018-01-09 16:59:06 +01:00
|
|
|
}
|
2018-01-09 18:42:24 +01:00
|
|
|
certInfo, err := FetchCurrentCert(proxy, proxy.mainProto, serverPk, stamp.serverAddrStr, stamp.providerName)
|
2018-01-09 16:59:06 +01:00
|
|
|
if err != nil {
|
2018-01-09 18:42:24 +01:00
|
|
|
return ServerInfo{}, err
|
2018-01-09 16:59:06 +01:00
|
|
|
}
|
2018-01-09 17:34:19 +01:00
|
|
|
remoteUDPAddr, err := net.ResolveUDPAddr("udp", stamp.serverAddrStr)
|
2018-01-09 16:59:06 +01:00
|
|
|
if err != nil {
|
|
|
|
return ServerInfo{}, err
|
|
|
|
}
|
2018-01-09 17:34:19 +01:00
|
|
|
remoteTCPAddr, err := net.ResolveTCPAddr("tcp", stamp.serverAddrStr)
|
2018-01-09 16:59:06 +01:00
|
|
|
if err != nil {
|
|
|
|
return ServerInfo{}, err
|
|
|
|
}
|
|
|
|
serverInfo := ServerInfo{
|
|
|
|
MagicQuery: certInfo.MagicQuery,
|
|
|
|
ServerPk: certInfo.ServerPk,
|
|
|
|
SharedKey: certInfo.SharedKey,
|
|
|
|
CryptoConstruction: certInfo.CryptoConstruction,
|
2018-01-09 17:15:07 +01:00
|
|
|
Name: name,
|
2018-01-10 12:09:59 +01:00
|
|
|
Timeout: proxy.timeout,
|
2018-01-09 16:59:06 +01:00
|
|
|
UDPAddr: remoteUDPAddr,
|
|
|
|
TCPAddr: remoteTCPAddr,
|
|
|
|
}
|
|
|
|
return serverInfo, nil
|
|
|
|
}
|
2018-01-10 16:01:29 +01:00
|
|
|
|
2018-01-10 16:42:14 +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
|
|
|
}
|