Cleanup - WIP
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"git.crumpington.com/lib/go/webutil"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
func (a *App) _root(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||
@@ -366,20 +367,27 @@ func (a *App) peersList(networkID int64) (peers []m.Peer, err error) {
|
||||
peers = make([]m.Peer, 0, len(l))
|
||||
|
||||
for _, p := range l {
|
||||
if len(p.WGPubKey) != 0 {
|
||||
if len(p.WGPubKey) == 0 {
|
||||
continue
|
||||
}
|
||||
wgKey, err := wgtypes.NewKey(p.WGPubKey)
|
||||
if err != nil {
|
||||
continue // malformed key; skip rather than serve garbage
|
||||
}
|
||||
var signKey [32]byte
|
||||
copy(signKey[:], p.SignPubKey)
|
||||
peers = append(peers, m.Peer{
|
||||
PeerIP: p.PeerIP,
|
||||
Version: p.Version,
|
||||
Name: p.Name,
|
||||
Addr4: p.Addr4,
|
||||
Addr6: p.Addr6,
|
||||
Addr4: addrFromBytes(p.Addr4),
|
||||
Addr6: addrFromBytes(p.Addr6),
|
||||
Port: p.Port,
|
||||
Relay: p.Relay,
|
||||
WGPubKey: p.WGPubKey,
|
||||
SignPubKey: p.SignPubKey,
|
||||
WGPubKey: wgKey,
|
||||
SignPubKey: signKey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
13
hub/util.go
13
hub/util.go
@@ -38,6 +38,19 @@ func (app *App) sendJSON(w http.ResponseWriter, data any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// addrFromBytes parses raw IP bytes (4 or 16) into a netip.Addr, unmapping
|
||||
// IPv4-in-IPv6, returning the zero Addr for empty/invalid input.
|
||||
func addrFromBytes(b []byte) netip.Addr {
|
||||
if len(b) == 0 {
|
||||
return netip.Addr{}
|
||||
}
|
||||
addr, ok := netip.AddrFromSlice(b)
|
||||
if !ok {
|
||||
return netip.Addr{}
|
||||
}
|
||||
return addr.Unmap()
|
||||
}
|
||||
|
||||
func stringToIP(in string) ([]byte, error) {
|
||||
in = strings.TrimSpace(in)
|
||||
if len(in) == 0 {
|
||||
|
||||
115
m/models.go
115
m/models.go
@@ -1,6 +1,15 @@
|
||||
// The package `m` contains models shared between the hub and peer programs.
|
||||
package m
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
type PeerInitArgs struct {
|
||||
WGPubKey []byte
|
||||
SignPubKey []byte
|
||||
@@ -13,16 +22,114 @@ type PeerInitResp struct {
|
||||
NetworkState NetworkState
|
||||
}
|
||||
|
||||
// Peer is the network membership record for a single peer, exchanged between
|
||||
// the hub and peers. Addr4/Addr6 are the peer's public endpoint addresses (zero
|
||||
// if it has none); Port is its WireGuard listen port, meaningful even for a
|
||||
// non-public peer (it is the peer's own bind/beacon port).
|
||||
type Peer struct {
|
||||
PeerIP byte
|
||||
Version int64
|
||||
Name string
|
||||
Addr4 []byte
|
||||
Addr6 []byte
|
||||
Addr4 netip.Addr // zero if none
|
||||
Addr6 netip.Addr // zero if none
|
||||
Port uint16
|
||||
Relay bool
|
||||
WGPubKey []byte
|
||||
SignPubKey []byte
|
||||
WGPubKey wgtypes.Key
|
||||
SignPubKey [32]byte
|
||||
}
|
||||
|
||||
// IsPublic reports whether the peer advertises at least one reachable endpoint.
|
||||
func (p Peer) IsPublic() bool {
|
||||
return p.Addr4.IsValid() || p.Addr6.IsValid()
|
||||
}
|
||||
|
||||
// Endpoint4 returns the IPv4 endpoint (addr+port), or the zero AddrPort if the
|
||||
// peer has no IPv4 address.
|
||||
func (p Peer) Endpoint4() netip.AddrPort {
|
||||
if !p.Addr4.IsValid() {
|
||||
return netip.AddrPort{}
|
||||
}
|
||||
return netip.AddrPortFrom(p.Addr4, p.Port)
|
||||
}
|
||||
|
||||
// Endpoint6 returns the IPv6 endpoint (addr+port), or the zero AddrPort if the
|
||||
// peer has no IPv6 address.
|
||||
func (p Peer) Endpoint6() netip.AddrPort {
|
||||
if !p.Addr6.IsValid() {
|
||||
return netip.AddrPort{}
|
||||
}
|
||||
return netip.AddrPortFrom(p.Addr6, p.Port)
|
||||
}
|
||||
|
||||
// PreferredEndpoint returns the IPv4 endpoint if present, else IPv6.
|
||||
func (p Peer) PreferredEndpoint() netip.AddrPort {
|
||||
if ep := p.Endpoint4(); ep.IsValid() {
|
||||
return ep
|
||||
}
|
||||
return p.Endpoint6()
|
||||
}
|
||||
|
||||
// peerJSON is the wire representation. netip.Addr fields round-trip as text
|
||||
// strings automatically; only the fixed-size key arrays need base64 (otherwise
|
||||
// encoding/json would emit them as arrays of numbers).
|
||||
type peerJSON struct {
|
||||
PeerIP byte
|
||||
Version int64
|
||||
Name string
|
||||
Addr4 netip.Addr
|
||||
Addr6 netip.Addr
|
||||
Port uint16
|
||||
Relay bool
|
||||
WGPubKey string
|
||||
SignPubKey string
|
||||
}
|
||||
|
||||
func (p Peer) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(peerJSON{
|
||||
PeerIP: p.PeerIP,
|
||||
Version: p.Version,
|
||||
Name: p.Name,
|
||||
Addr4: p.Addr4,
|
||||
Addr6: p.Addr6,
|
||||
Port: p.Port,
|
||||
Relay: p.Relay,
|
||||
WGPubKey: base64.StdEncoding.EncodeToString(p.WGPubKey[:]),
|
||||
SignPubKey: base64.StdEncoding.EncodeToString(p.SignPubKey[:]),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Peer) UnmarshalJSON(data []byte) error {
|
||||
var j peerJSON
|
||||
if err := json.Unmarshal(data, &j); err != nil {
|
||||
return err
|
||||
}
|
||||
wg, err := base64.StdEncoding.DecodeString(j.WGPubKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode WGPubKey: %w", err)
|
||||
}
|
||||
key, err := wgtypes.NewKey(wg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid WGPubKey: %w", err)
|
||||
}
|
||||
sign, err := base64.StdEncoding.DecodeString(j.SignPubKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode SignPubKey: %w", err)
|
||||
}
|
||||
if len(sign) != 32 {
|
||||
return fmt.Errorf("invalid SignPubKey length: %d", len(sign))
|
||||
}
|
||||
*p = Peer{
|
||||
PeerIP: j.PeerIP,
|
||||
Version: j.Version,
|
||||
Name: j.Name,
|
||||
Addr4: j.Addr4,
|
||||
Addr6: j.Addr6,
|
||||
Port: j.Port,
|
||||
Relay: j.Relay,
|
||||
WGPubKey: key,
|
||||
SignPubKey: [32]byte(sign),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NetworkState struct {
|
||||
|
||||
15
peer/app.go
15
peer/app.go
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"vppn/m"
|
||||
"vppn/peer/control"
|
||||
"vppn/peer/wginterface"
|
||||
)
|
||||
@@ -21,18 +22,6 @@ const (
|
||||
TimeoutInterval = 30 * time.Second
|
||||
)
|
||||
|
||||
// HubPeer is a peer entry as reported by the hub poller.
|
||||
type HubPeer struct {
|
||||
PubKey wgtypes.Key
|
||||
VPNIP netip.Addr
|
||||
Name string
|
||||
IsRelay bool
|
||||
IsPublic bool
|
||||
EndpointV4 netip.AddrPort // zero if none
|
||||
EndpointV6 netip.AddrPort // zero if none
|
||||
SignPubKey [32]byte
|
||||
}
|
||||
|
||||
type PingEvent struct {
|
||||
srcVPNIP netip.Addr
|
||||
ping control.Ping
|
||||
@@ -70,7 +59,7 @@ type App struct {
|
||||
selfV6 netip.AddrPort
|
||||
|
||||
// Event channels fed by background goroutines
|
||||
hubAddCh <-chan HubPeer
|
||||
hubAddCh <-chan m.Peer
|
||||
hubRemoveCh <-chan wgtypes.Key
|
||||
pingCh <-chan PingEvent
|
||||
multicastCh <-chan MulticastEvent
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"time"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"vppn/m"
|
||||
)
|
||||
|
||||
// addRelayPeer adds a public relay peer and marks it Up so it satisfies
|
||||
@@ -13,12 +15,13 @@ import (
|
||||
func addRelayPeer(t *testing.T, a *App, vpnIP string, ep netip.AddrPort) *Peer {
|
||||
t.Helper()
|
||||
key := mustKey(t)
|
||||
a.onAddPeer(HubPeer{
|
||||
PubKey: key,
|
||||
VPNIP: netip.MustParseAddr(vpnIP),
|
||||
IsPublic: true,
|
||||
IsRelay: true,
|
||||
EndpointV4: ep,
|
||||
ip := netip.MustParseAddr(vpnIP)
|
||||
a.onAddPeer(m.Peer{
|
||||
WGPubKey: key,
|
||||
PeerIP: ip.As4()[3],
|
||||
Addr4: ep.Addr(),
|
||||
Port: ep.Port(),
|
||||
Relay: true,
|
||||
})
|
||||
p := a.peersByKey[key]
|
||||
p.wgPeer.LastHandshakeTime = time.Now()
|
||||
@@ -48,7 +51,7 @@ func newTestApp(t *testing.T, vpnIP string, isPublic, isRelay bool) (*App, *fake
|
||||
controlConn: cc,
|
||||
peersByKey: make(map[wgtypes.Key]*Peer),
|
||||
peersByIP: make(map[netip.Addr]*Peer),
|
||||
hubAddCh: make(chan HubPeer),
|
||||
hubAddCh: make(chan m.Peer),
|
||||
hubRemoveCh: make(chan wgtypes.Key),
|
||||
pingCh: make(chan PingEvent),
|
||||
multicastCh: make(chan MulticastEvent),
|
||||
|
||||
@@ -22,7 +22,7 @@ type HubPoller struct {
|
||||
hubURL string
|
||||
apiKey string
|
||||
statePath string // where the network state cache is persisted
|
||||
addCh chan<- HubPeer
|
||||
addCh chan<- m.Peer
|
||||
removeCh chan<- wgtypes.Key
|
||||
known map[wgtypes.Key]int64 // pubKey → last seen version
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func NewHubPoller(
|
||||
vpnNet netip.Prefix,
|
||||
hubURL, apiKey string,
|
||||
statePath string,
|
||||
addCh chan<- HubPeer,
|
||||
addCh chan<- m.Peer,
|
||||
removeCh chan<- wgtypes.Key,
|
||||
) (*HubPoller, error) {
|
||||
u, err := url.Parse(hubURL)
|
||||
@@ -119,12 +119,7 @@ func (hp *HubPoller) apply(state m.NetworkState) (changed bool) {
|
||||
netAddr := hp.vpnNet.Addr().As4()
|
||||
|
||||
for _, p := range state.Peers {
|
||||
if len(p.WGPubKey) != wgtypes.KeyLen || len(p.SignPubKey) != 32 {
|
||||
continue
|
||||
}
|
||||
|
||||
pubKey, err := wgtypes.NewKey(p.WGPubKey)
|
||||
if err != nil {
|
||||
if p.WGPubKey == (wgtypes.Key{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -135,13 +130,13 @@ func (hp *HubPoller) apply(state m.NetworkState) (changed bool) {
|
||||
continue
|
||||
}
|
||||
|
||||
seen[pubKey] = struct{}{}
|
||||
seen[p.WGPubKey] = struct{}{}
|
||||
|
||||
if v, ok := hp.known[pubKey]; ok && v == p.Version {
|
||||
if v, ok := hp.known[p.WGPubKey]; ok && v == p.Version {
|
||||
continue
|
||||
}
|
||||
hp.known[pubKey] = p.Version
|
||||
hp.addCh <- hubPeerFrom(pubKey, vpnIP, p)
|
||||
hp.known[p.WGPubKey] = p.Version
|
||||
hp.addCh <- p
|
||||
changed = true
|
||||
}
|
||||
|
||||
@@ -155,30 +150,3 @@ func (hp *HubPoller) apply(state m.NetworkState) (changed bool) {
|
||||
|
||||
return changed
|
||||
}
|
||||
|
||||
func hubPeerFrom(pubKey wgtypes.Key, vpnIP netip.Addr, p m.Peer) HubPeer {
|
||||
var ep4, ep6 netip.AddrPort
|
||||
if len(p.Addr4) > 0 {
|
||||
if addr, ok := netip.AddrFromSlice(p.Addr4); ok {
|
||||
ep4 = netip.AddrPortFrom(addr.Unmap(), p.Port)
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.Addr6) > 0 {
|
||||
if addr, ok := netip.AddrFromSlice(p.Addr6); ok {
|
||||
ep6 = netip.AddrPortFrom(addr.Unmap(), p.Port)
|
||||
}
|
||||
}
|
||||
var signPubKey [32]byte
|
||||
copy(signPubKey[:], p.SignPubKey)
|
||||
return HubPeer{
|
||||
PubKey: pubKey,
|
||||
VPNIP: vpnIP,
|
||||
Name: p.Name,
|
||||
IsRelay: p.Relay,
|
||||
IsPublic: ep4.IsValid() || ep6.IsValid(),
|
||||
EndpointV4: ep4,
|
||||
EndpointV6: ep6,
|
||||
SignPubKey: signPubKey,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"vppn/m"
|
||||
)
|
||||
|
||||
func testPoller(t *testing.T) (*HubPoller, chan HubPeer, chan wgtypes.Key) {
|
||||
func testPoller(t *testing.T) (*HubPoller, chan m.Peer, chan wgtypes.Key) {
|
||||
t.Helper()
|
||||
addCh := make(chan HubPeer, 8)
|
||||
addCh := make(chan m.Peer, 8)
|
||||
removeCh := make(chan wgtypes.Key, 8)
|
||||
hp := &HubPoller{
|
||||
selfVPNIP: netip.MustParseAddr("10.0.0.1"),
|
||||
@@ -27,8 +27,7 @@ func stateWith(key wgtypes.Key, peerIP byte, version int64) m.NetworkState {
|
||||
return m.NetworkState{Peers: []m.Peer{{
|
||||
PeerIP: peerIP,
|
||||
Version: version,
|
||||
WGPubKey: key[:],
|
||||
SignPubKey: make([]byte, 32),
|
||||
WGPubKey: key,
|
||||
}}}
|
||||
}
|
||||
|
||||
@@ -42,7 +41,7 @@ func TestApply_EmitsAddsAndReportsChange(t *testing.T) {
|
||||
if len(addCh) != 1 {
|
||||
t.Fatalf("expected 1 add, got %d", len(addCh))
|
||||
}
|
||||
if got := <-addCh; got.PubKey != key {
|
||||
if got := <-addCh; got.WGPubKey != key {
|
||||
t.Errorf("add pubkey mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
27
peer/init.go
27
peer/init.go
@@ -78,10 +78,13 @@ func initFromHub(hubURL, apiKey string, privKey wgtypes.Key) (LocalState, error)
|
||||
return LocalState{}, fmt.Errorf("generate sign key: %w", err)
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(m.PeerInitArgs{
|
||||
body, err := json.Marshal(m.PeerInitArgs{
|
||||
WGPubKey: wgPubKey[:],
|
||||
SignPubKey: signPubKey[:],
|
||||
})
|
||||
if err != nil {
|
||||
return LocalState{}, fmt.Errorf("json error: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, hubURL+"/peer/init/", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
@@ -126,31 +129,15 @@ func initFromHub(hubURL, apiKey string, privKey wgtypes.Key) (LocalState, error)
|
||||
return LocalState{}, fmt.Errorf("hub init: no peer for own IP: %d", r.PeerIP)
|
||||
}
|
||||
|
||||
var isRelay, public bool
|
||||
var wgPort uint16
|
||||
|
||||
var ep4, ep6 netip.AddrPort
|
||||
if len(self.Addr4) > 0 {
|
||||
if addr, ok := netip.AddrFromSlice(self.Addr4); ok {
|
||||
ep4 = netip.AddrPortFrom(addr.Unmap(), self.Port)
|
||||
}
|
||||
}
|
||||
if len(self.Addr6) > 0 {
|
||||
if addr, ok := netip.AddrFromSlice(self.Addr6); ok {
|
||||
ep6 = netip.AddrPortFrom(addr.Unmap(), self.Port)
|
||||
}
|
||||
}
|
||||
public = ep4.IsValid() || ep6.IsValid()
|
||||
isRelay = self.Relay && public
|
||||
wgPort = self.Port
|
||||
public := self.IsPublic()
|
||||
|
||||
return LocalState{
|
||||
PrivKey: privKey,
|
||||
SignKey: *signPrivKey,
|
||||
VPNIP: vpnIP,
|
||||
VPNNet: vpnNet,
|
||||
WGPort: wgPort,
|
||||
IsRelay: isRelay,
|
||||
WGPort: self.Port,
|
||||
IsRelay: self.Relay && public,
|
||||
IsPublic: public,
|
||||
LocalDomain: r.LocalDomain,
|
||||
}, nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -11,25 +12,27 @@ import (
|
||||
func TestNetworkState_RoundTrip(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "network.json")
|
||||
|
||||
var sign1 [32]byte
|
||||
copy(sign1[:], []byte("0123456789abcdef0123456789abcdef"))
|
||||
|
||||
state := m.NetworkState{Peers: []m.Peer{
|
||||
{
|
||||
PeerIP: 1,
|
||||
Version: 7,
|
||||
Name: "hub",
|
||||
Addr4: []byte{10, 11, 12, 1},
|
||||
Addr4: netip.MustParseAddr("10.11.12.1"),
|
||||
Port: 51820,
|
||||
Relay: true,
|
||||
WGPubKey: make([]byte, 32),
|
||||
SignPubKey: make([]byte, 32),
|
||||
WGPubKey: mustKey(t),
|
||||
SignPubKey: sign1,
|
||||
},
|
||||
{
|
||||
PeerIP: 10,
|
||||
Version: 3,
|
||||
Name: "laptop",
|
||||
Addr4: []byte{10, 11, 12, 10},
|
||||
Addr4: netip.MustParseAddr("10.11.12.10"),
|
||||
Port: 51820,
|
||||
WGPubKey: []byte("0123456789abcdef0123456789abcdef"),
|
||||
SignPubKey: []byte("fedcba9876543210fedcba9876543210"),
|
||||
WGPubKey: mustKey(t),
|
||||
},
|
||||
}}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"vppn/m"
|
||||
"vppn/peer/wginterface"
|
||||
)
|
||||
|
||||
@@ -57,7 +58,7 @@ func New(
|
||||
}
|
||||
|
||||
pingCh := make(chan PingEvent)
|
||||
hubAddCh := make(chan HubPeer)
|
||||
hubAddCh := make(chan m.Peer)
|
||||
hubRemoveCh := make(chan wgtypes.Key)
|
||||
multicastCh := make(chan MulticastEvent)
|
||||
|
||||
|
||||
@@ -8,33 +8,31 @@ import (
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"vppn/m"
|
||||
"vppn/peer/control"
|
||||
)
|
||||
|
||||
func (a *App) onAddPeer(p HubPeer) {
|
||||
a.onRemovePeer(p.PubKey)
|
||||
func (a *App) onAddPeer(p m.Peer) {
|
||||
a.onRemovePeer(p.WGPubKey)
|
||||
|
||||
octets := a.vpnNet.Addr().As4()
|
||||
octets[3] = p.PeerIP
|
||||
vpnIP := netip.AddrFrom4(octets)
|
||||
|
||||
peer := &Peer{
|
||||
wgPeer: wgtypes.Peer{PublicKey: p.PubKey},
|
||||
VPNIP: p.VPNIP,
|
||||
wgPeer: wgtypes.Peer{PublicKey: p.WGPubKey},
|
||||
VPNIP: vpnIP,
|
||||
Name: p.Name,
|
||||
IsRelay: p.IsRelay,
|
||||
IsPublic: p.IsPublic,
|
||||
Endpoint4: p.EndpointV4,
|
||||
Endpoint6: p.EndpointV6,
|
||||
IsRelay: p.Relay,
|
||||
IsPublic: p.IsPublic(),
|
||||
Endpoint4: p.Endpoint4(),
|
||||
Endpoint6: p.Endpoint6(),
|
||||
RTT: time.Duration(math.MaxInt64) * time.Nanosecond,
|
||||
Role: roleFor(a.isPublic, a.vpnIP, p),
|
||||
Role: roleFor(a.isPublic, a.vpnIP, p.IsPublic(), vpnIP),
|
||||
SignPubKey: p.SignPubKey,
|
||||
}
|
||||
|
||||
endpoint := peer.PreferredEndpoint()
|
||||
if peer.IsPublic && !endpoint.IsValid() {
|
||||
// The peer is misconfigured.
|
||||
// TODO: Log here.
|
||||
return
|
||||
}
|
||||
|
||||
a.peersByKey[p.PubKey] = peer
|
||||
a.peersByKey[p.WGPubKey] = peer
|
||||
a.peersByIP[peer.VPNIP] = peer
|
||||
defer a.updateHosts()
|
||||
|
||||
@@ -50,7 +48,7 @@ func (a *App) onAddPeer(p HubPeer) {
|
||||
return
|
||||
}
|
||||
|
||||
a.devAddDirect(peer, endpoint)
|
||||
a.devAddDirect(peer, peer.PreferredEndpoint())
|
||||
}
|
||||
|
||||
func (a *App) onRemovePeer(key wgtypes.Key) {
|
||||
@@ -104,12 +102,12 @@ func preferredEndpoint(v4, v6 netip.AddrPort) netip.AddrPort {
|
||||
return v6
|
||||
}
|
||||
|
||||
func roleFor(selfIsPublic bool, selfIP netip.Addr, p HubPeer) control.Role {
|
||||
if !selfIsPublic && p.IsPublic {
|
||||
func roleFor(selfIsPublic bool, selfIP netip.Addr, peerIsPublic bool, peerVPNIP netip.Addr) control.Role {
|
||||
if !selfIsPublic && peerIsPublic {
|
||||
return control.Client
|
||||
}
|
||||
if selfIsPublic && !p.IsPublic {
|
||||
if selfIsPublic && !peerIsPublic {
|
||||
return control.Server
|
||||
}
|
||||
return control.RoleFor(selfIP, p.VPNIP)
|
||||
return control.RoleFor(selfIP, peerVPNIP)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"time"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"vppn/m"
|
||||
)
|
||||
|
||||
func mustKey(t *testing.T) wgtypes.Key {
|
||||
@@ -25,13 +27,13 @@ func TestOnAddPeer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
setup func(a *App, key wgtypes.Key)
|
||||
peer func(key wgtypes.Key) HubPeer
|
||||
peer func(key wgtypes.Key) m.Peer
|
||||
check func(t *testing.T, a *App, dev *fakeWGDevice, key wgtypes.Key)
|
||||
}{
|
||||
{
|
||||
name: "non-public peer registered in WG via AddPeer",
|
||||
peer: func(k wgtypes.Key) HubPeer {
|
||||
return HubPeer{PubKey: k, VPNIP: peerVPNIP}
|
||||
peer: func(k wgtypes.Key) m.Peer {
|
||||
return m.Peer{WGPubKey: k, PeerIP: 2}
|
||||
},
|
||||
check: func(t *testing.T, a *App, dev *fakeWGDevice, key wgtypes.Key) {
|
||||
p := a.peersByKey[key]
|
||||
@@ -49,8 +51,8 @@ func TestOnAddPeer(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "public peer with endpoint registered via AddDirect",
|
||||
peer: func(k wgtypes.Key) HubPeer {
|
||||
return HubPeer{PubKey: k, VPNIP: peerVPNIP, IsPublic: true, EndpointV4: ep1}
|
||||
peer: func(k wgtypes.Key) m.Peer {
|
||||
return m.Peer{WGPubKey: k, PeerIP: 2, Addr4: ep1.Addr(), Port: ep1.Port()}
|
||||
},
|
||||
check: func(t *testing.T, a *App, dev *fakeWGDevice, key wgtypes.Key) {
|
||||
p := a.peersByKey[key]
|
||||
@@ -60,28 +62,13 @@ func TestOnAddPeer(t *testing.T) {
|
||||
dev.AssertAddDirect(t, 0, p.PubKey(), ep1, p.VPNIP)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "public peer with no endpoint is dropped",
|
||||
peer: func(k wgtypes.Key) HubPeer {
|
||||
return HubPeer{PubKey: k, VPNIP: peerVPNIP, IsPublic: true}
|
||||
},
|
||||
check: func(t *testing.T, a *App, dev *fakeWGDevice, key wgtypes.Key) {
|
||||
if a.peersByKey[key] != nil {
|
||||
t.Fatal("peer should not be in peersByKey")
|
||||
}
|
||||
if a.peersByIP[peerVPNIP] != nil {
|
||||
t.Fatal("peer should not be in peersByIP")
|
||||
}
|
||||
dev.AssertNoCalls(t)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "re-add removes old WG entry before adding new one",
|
||||
setup: func(a *App, key wgtypes.Key) {
|
||||
a.onAddPeer(HubPeer{PubKey: key, VPNIP: peerVPNIP, IsPublic: true, EndpointV4: ep1})
|
||||
a.onAddPeer(m.Peer{WGPubKey: key, PeerIP: 2, Addr4: ep1.Addr(), Port: ep1.Port()})
|
||||
},
|
||||
peer: func(k wgtypes.Key) HubPeer {
|
||||
return HubPeer{PubKey: k, VPNIP: peerVPNIP, IsPublic: true, EndpointV4: ep2}
|
||||
peer: func(k wgtypes.Key) m.Peer {
|
||||
return m.Peer{WGPubKey: k, PeerIP: 2, Addr4: ep2.Addr(), Port: ep2.Port()}
|
||||
},
|
||||
check: func(t *testing.T, a *App, dev *fakeWGDevice, key wgtypes.Key) {
|
||||
if len(dev.Calls) != 2 {
|
||||
@@ -135,7 +122,7 @@ func TestOnRemovePeer(t *testing.T) {
|
||||
name: "StateRelayed peer removed from maps with RemovePeer",
|
||||
setup: func(t *testing.T, a *App) wgtypes.Key {
|
||||
key := mustKey(t)
|
||||
a.onAddPeer(HubPeer{PubKey: key, VPNIP: netip.MustParseAddr("10.0.0.2")})
|
||||
a.onAddPeer(m.Peer{WGPubKey: key, PeerIP: 2})
|
||||
return key
|
||||
},
|
||||
check: func(t *testing.T, a *App, dev *fakeWGDevice) {
|
||||
@@ -152,7 +139,7 @@ func TestOnRemovePeer(t *testing.T) {
|
||||
name: "StateDirect peer removed from maps with RemovePeer",
|
||||
setup: func(t *testing.T, a *App) wgtypes.Key {
|
||||
key := mustKey(t)
|
||||
a.onAddPeer(HubPeer{PubKey: key, VPNIP: netip.MustParseAddr("10.0.0.2"), IsPublic: true, EndpointV4: ep1})
|
||||
a.onAddPeer(m.Peer{WGPubKey: key, PeerIP: 2, Addr4: ep1.Addr(), Port: ep1.Port()})
|
||||
return key
|
||||
},
|
||||
check: func(t *testing.T, a *App, dev *fakeWGDevice) {
|
||||
|
||||
Reference in New Issue
Block a user