From 0902341322588b0baf6604baba256897c6972c2e Mon Sep 17 00:00:00 2001 From: jdl Date: Thu, 11 Jun 2026 18:11:21 +0200 Subject: [PATCH] Cleanup - WIP --- hub/handlers.go | 32 +++++++---- hub/util.go | 13 +++++ m/models.go | 115 +++++++++++++++++++++++++++++++++++-- peer/app.go | 15 +---- peer/app_test.go | 17 +++--- peer/hub_poller.go | 46 +++------------ peer/hub_poller_test.go | 13 ++--- peer/init.go | 27 +++------ peer/network_state_test.go | 23 ++++---- peer/new.go | 3 +- peer/on_hub.go | 42 +++++++------- peer/on_hub_test.go | 37 ++++-------- 12 files changed, 223 insertions(+), 160 deletions(-) diff --git a/hub/handlers.go b/hub/handlers.go index 3130111..5d30ba0 100644 --- a/hub/handlers.go +++ b/hub/handlers.go @@ -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,19 +367,26 @@ 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 { - peers = append(peers, m.Peer{ - PeerIP: p.PeerIP, - Version: p.Version, - Name: p.Name, - Addr4: p.Addr4, - Addr6: p.Addr6, - Port: p.Port, - Relay: p.Relay, - WGPubKey: p.WGPubKey, - SignPubKey: p.SignPubKey, - }) + 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: addrFromBytes(p.Addr4), + Addr6: addrFromBytes(p.Addr6), + Port: p.Port, + Relay: p.Relay, + WGPubKey: wgKey, + SignPubKey: signKey, + }) } return peers, nil diff --git a/hub/util.go b/hub/util.go index 5503cc9..bf70738 100644 --- a/hub/util.go +++ b/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 { diff --git a/m/models.go b/m/models.go index a49724f..b751ef8 100644 --- a/m/models.go +++ b/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 { diff --git a/peer/app.go b/peer/app.go index 63affe6..78a0219 100644 --- a/peer/app.go +++ b/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 diff --git a/peer/app_test.go b/peer/app_test.go index 2825c54..569b2f1 100644 --- a/peer/app_test.go +++ b/peer/app_test.go @@ -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), diff --git a/peer/hub_poller.go b/peer/hub_poller.go index 343f5b2..a41f888 100644 --- a/peer/hub_poller.go +++ b/peer/hub_poller.go @@ -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, - } -} diff --git a/peer/hub_poller_test.go b/peer/hub_poller_test.go index f7f765c..4131a23 100644 --- a/peer/hub_poller_test.go +++ b/peer/hub_poller_test.go @@ -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"), @@ -25,10 +25,9 @@ func testPoller(t *testing.T) (*HubPoller, chan HubPeer, chan wgtypes.Key) { 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), + PeerIP: peerIP, + Version: version, + 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") } } diff --git a/peer/init.go b/peer/init.go index 20658b3..e3a1699 100644 --- a/peer/init.go +++ b/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 diff --git a/peer/network_state_test.go b/peer/network_state_test.go index 1776bdb..85d9c0e 100644 --- a/peer/network_state_test.go +++ b/peer/network_state_test.go @@ -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}, - Port: 51820, - WGPubKey: []byte("0123456789abcdef0123456789abcdef"), - SignPubKey: []byte("fedcba9876543210fedcba9876543210"), + PeerIP: 10, + Version: 3, + Name: "laptop", + Addr4: netip.MustParseAddr("10.11.12.10"), + Port: 51820, + WGPubKey: mustKey(t), }, }} diff --git a/peer/new.go b/peer/new.go index e2145ad..10bbd55 100644 --- a/peer/new.go +++ b/peer/new.go @@ -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) diff --git a/peer/on_hub.go b/peer/on_hub.go index 02b11e4..0d55718 100644 --- a/peer/on_hub.go +++ b/peer/on_hub.go @@ -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) } diff --git a/peer/on_hub_test.go b/peer/on_hub_test.go index 98c7c17..5114563 100644 --- a/peer/on_hub_test.go +++ b/peer/on_hub_test.go @@ -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) {