124 lines
2.3 KiB
Go
124 lines
2.3 KiB
Go
package peer
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/netip"
|
|
"net/url"
|
|
"sync/atomic"
|
|
"time"
|
|
"vppn/m"
|
|
)
|
|
|
|
var zeroAddrPort netip.AddrPort
|
|
|
|
type routeInfo struct {
|
|
Up bool
|
|
Route route
|
|
}
|
|
|
|
type Router struct {
|
|
conf m.PeerConfig
|
|
routes [256]*atomic.Pointer[routeInfo]
|
|
}
|
|
|
|
func NewRouter(conf m.PeerConfig) *Router {
|
|
rm := &Router{
|
|
conf: conf,
|
|
}
|
|
|
|
for i := range rm.routes {
|
|
rm.routes[i] = &atomic.Pointer[routeInfo]{}
|
|
rm.routes[i].Store(&routeInfo{})
|
|
}
|
|
|
|
go rm.pollHub()
|
|
return rm
|
|
}
|
|
|
|
func (rm *Router) GetRoute(ip byte) *route {
|
|
if route := rm.routes[ip].Load(); route != nil && route.Up {
|
|
return &route.Route
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rm *Router) pollHub() {
|
|
u, err := url.Parse(rm.conf.HubAddress)
|
|
if err != nil {
|
|
log.Fatalf("Failed to parse hub address %s: %v", rm.conf.HubAddress, err)
|
|
}
|
|
u.Path = "/peer/fetch-state/"
|
|
|
|
client := &http.Client{Timeout: 8 * time.Second}
|
|
|
|
req := &http.Request{
|
|
Method: http.MethodGet,
|
|
URL: u,
|
|
Header: http.Header{},
|
|
}
|
|
req.SetBasicAuth("", rm.conf.APIKey)
|
|
|
|
rm._pollHub(client, req)
|
|
|
|
for range time.Tick(time.Minute) {
|
|
rm._pollHub(client, req)
|
|
}
|
|
}
|
|
|
|
func (rm *Router) _pollHub(client *http.Client, req *http.Request) {
|
|
var state m.NetworkState
|
|
|
|
log.Printf("Fetching peer state from %s...", rm.conf.HubAddress)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
log.Printf("Failed to fetch peer state: %v", err)
|
|
return
|
|
}
|
|
body, err := io.ReadAll(resp.Body)
|
|
_ = resp.Body.Close()
|
|
if err != nil {
|
|
log.Printf("Failed to read body: %v", err)
|
|
return
|
|
}
|
|
|
|
if err := json.Unmarshal(body, &state); err != nil {
|
|
log.Printf("Failed to unmarshal response from hub: %v", err)
|
|
return
|
|
}
|
|
|
|
for i, peer := range state.Peers {
|
|
if peer == nil {
|
|
continue
|
|
}
|
|
route := rm.routes[i].Load()
|
|
rm.routes[i].Store(rm.updateRoute(route, peer))
|
|
}
|
|
}
|
|
|
|
func (rm *Router) updateRoute(routePtr *routeInfo, peer *m.Peer) *routeInfo {
|
|
if peer == nil {
|
|
return &routeInfo{}
|
|
}
|
|
|
|
route := *routePtr
|
|
|
|
addr, ok := netip.AddrFromSlice(peer.IP)
|
|
if !ok {
|
|
return &routeInfo{}
|
|
}
|
|
|
|
route.Up = true
|
|
route.Route.Addr = netip.AddrPortFrom(addr, peer.Port)
|
|
route.Route.Mediator = peer.Mediator
|
|
route.Route.ViaIP = 0
|
|
if len(route.Route.SignPubKey) == 0 {
|
|
route.Route.SignPubKey = peer.SignPubKey
|
|
route.Route.EncSharedKey = computeSharedKey(peer.EncPubKey, rm.conf.EncPrivKey)
|
|
}
|
|
|
|
return &route
|
|
}
|