61 lines
1.1 KiB
Go
61 lines
1.1 KiB
Go
package peer
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"net/netip"
|
|
|
|
"golang.org/x/crypto/nacl/sign"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
)
|
|
|
|
func (a *App) onMulticastDiscovery(e MulticastEvent) {
|
|
if a.isPublic {
|
|
return
|
|
}
|
|
|
|
// Peek at the VPN IP byte to find the sender peer before verifying.
|
|
// nacl/sign prepends a 64-byte signature, so payload starts at offset sign.Overhead.
|
|
if len(e.signed) != mcSignedBeaconLen {
|
|
return
|
|
}
|
|
netAddr := a.vpnNet.Addr().As4()
|
|
octets := netAddr
|
|
octets[3] = e.signed[sign.Overhead]
|
|
vpnIP := netip.AddrFrom4(octets)
|
|
|
|
peer, ok := a.peersByIP[vpnIP]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if peer.IsPublic || peer.State() == StateDirect {
|
|
return
|
|
}
|
|
|
|
payload, ok := sign.Open(nil, e.signed, &peer.SignPubKey)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
// payload: [1 VPN IP byte][32 WG pubkey][2 WG port]
|
|
wgPubKey, err := wgtypes.NewKey(payload[1:33])
|
|
if err != nil || wgPubKey != peer.PubKey() {
|
|
return
|
|
}
|
|
|
|
wgPort := binary.BigEndian.Uint16(payload[33:35])
|
|
endpoint := netip.AddrPortFrom(e.src, wgPort)
|
|
if !endpoint.IsValid() {
|
|
return
|
|
}
|
|
|
|
var v4, v6 netip.AddrPort
|
|
if e.src.Is4() {
|
|
v4 = endpoint
|
|
} else {
|
|
v6 = endpoint
|
|
}
|
|
|
|
a.addProbe(peer, v4, v6)
|
|
}
|