98 lines
2.0 KiB
Go
98 lines
2.0 KiB
Go
package node
|
|
|
|
import (
|
|
"log"
|
|
"net"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/nacl/sign"
|
|
)
|
|
|
|
func localDiscovery() {
|
|
conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr)
|
|
if err != nil {
|
|
log.Printf("Failed to bind to multicast address: %v", err)
|
|
return
|
|
}
|
|
|
|
go sendLocalDiscovery(conn)
|
|
go recvLocalDiscovery(conn)
|
|
}
|
|
|
|
func sendLocalDiscovery(conn *net.UDPConn) {
|
|
var (
|
|
buf1 = make([]byte, bufferSize)
|
|
buf2 = make([]byte, bufferSize)
|
|
)
|
|
|
|
for range time.Tick(16 * time.Second) {
|
|
signed := buildLocalDiscoveryPacket(buf1, buf2)
|
|
if _, err := conn.WriteToUDP(signed, multicastAddr); err != nil {
|
|
log.Printf("Failed to write multicast UDP packet: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func recvLocalDiscovery(conn *net.UDPConn) {
|
|
var (
|
|
raw = make([]byte, bufferSize)
|
|
buf = make([]byte, bufferSize)
|
|
)
|
|
|
|
for {
|
|
n, remoteAddr, err := conn.ReadFromUDPAddrPort(raw[:bufferSize])
|
|
if err != nil {
|
|
log.Fatalf("Failed to read from UDP port (multicast): %v", err)
|
|
}
|
|
|
|
raw = raw[:n]
|
|
h, ok := openLocalDiscoveryPacket(raw, buf)
|
|
if !ok {
|
|
log.Printf("Failed to open discovery packet?")
|
|
continue
|
|
}
|
|
|
|
msg := controlMsg[localDiscoveryPacket]{
|
|
SrcIP: h.SourceIP,
|
|
SrcAddr: remoteAddr,
|
|
Packet: localDiscoveryPacket{},
|
|
}
|
|
|
|
select {
|
|
case messages <- msg:
|
|
default:
|
|
log.Printf("Dropping local discovery message.")
|
|
}
|
|
}
|
|
}
|
|
|
|
func buildLocalDiscoveryPacket(buf1, buf2 []byte) []byte {
|
|
h := header{
|
|
StreamID: controlStreamID,
|
|
Counter: 0,
|
|
SourceIP: localIP,
|
|
DestIP: 255,
|
|
}
|
|
out := buf1[:headerSize]
|
|
h.Marshal(out)
|
|
return sign.Sign(buf2[:0], out, (*[64]byte)(privSignKey))
|
|
}
|
|
|
|
func openLocalDiscoveryPacket(raw, buf []byte) (h header, ok bool) {
|
|
if len(raw) != headerSize+signOverhead {
|
|
ok = false
|
|
return
|
|
}
|
|
|
|
h.Parse(raw[signOverhead:])
|
|
route := routingTable[h.SourceIP].Load()
|
|
if route == nil || route.PubSignKey == nil {
|
|
log.Printf("Missing signing key: %d", h.SourceIP)
|
|
ok = false
|
|
return
|
|
}
|
|
|
|
_, ok = sign.Open(buf[:0], raw, (*[32]byte)(route.PubSignKey))
|
|
return
|
|
}
|