TAP -> TUN, handle multiple peers behind one NAT

This commit is contained in:
2026-07-23 11:41:01 +02:00
parent fabe2614a5
commit 4d710fb72b
3 changed files with 49 additions and 35 deletions

View File

@@ -1,14 +1,15 @@
// TODO: slice bounds checking
// TODO: authentication
// TODO: somehow persist IPs
// TODO: handle multiple peers behind one NAT
// TODO: key rotation
// TODO: dont trust claimed IP at all
package main
import (
"crypto/hpke"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"log"
"net"
"os"
@@ -17,14 +18,15 @@ import (
)
type Peer struct {
RealAddr *net.UDPAddr
InternalIP string
PublicKey hpke.PublicKey
RealAddr *net.UDPAddr
InternalIP string
HexPublicKey string
}
var (
peers = shared.NewTMap[string, *Peer]()
peersByInternal = shared.NewTMap[string, *Peer]()
peersByPubKey = shared.NewTMap[string, *Peer]()
conn *net.UDPConn
multicastKey = make([]byte, 32)
)
@@ -54,8 +56,8 @@ func receivePackets() {
}
defer conn.Close()
buffer := make([]byte, 50000)
for {
buffer := make([]byte, 50000)
n, addr, err := conn.ReadFromUDP(buffer)
if err != nil {
log.Println(err)
@@ -65,14 +67,16 @@ func receivePackets() {
continue
}
go handleReq(buffer[:n], addr)
req := make([]byte, n)
copy(req, buffer[:n])
go handleReq(req, addr)
}
}
func handleReq(req []byte, addr *net.UDPAddr) {
defer func() {
if r := recover(); r != nil {
log.Printf("recovered from panic while handling request from %s: %v\n", addr.IP.String(), r)
log.Printf("recovered from panic while handling request from %s: %v\n", addr.String(), r)
}
}()
@@ -96,19 +100,25 @@ func handleReq(req []byte, addr *net.UDPAddr) {
return
}
internalIP := randomIP().String()
hexPubKey := hex.EncodeToString(pubKey.Bytes())
if destPeer, ok := peers.GetOK(addr.IP.String()); ok {
internalIP = destPeer.InternalIP
destPeer.PublicKey = pubKey
var internalIP string
// TODO: authenticating only by PUBLIC key is obviously a bad idea
if peer, ok := peersByPubKey.GetOK(hexPubKey); ok {
internalIP = peer.InternalIP
peers.Delete(peer.RealAddr.String())
peer.RealAddr = addr
peers.Set(addr.String(), peer)
} else {
internalIP = randomIP().String()
peer := &Peer{
RealAddr: addr,
InternalIP: internalIP,
PublicKey: pubKey,
RealAddr: addr,
InternalIP: internalIP,
HexPublicKey: hexPubKey,
}
peers.Set(addr.IP.String(), peer)
peers.Set(addr.String(), peer)
peersByInternal.Set(internalIP, peer)
peersByPubKey.Set(hexPubKey, peer)
}
ciphertext, err := hpke.Seal(pubKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn"), multicastKey)
@@ -119,7 +129,7 @@ func handleReq(req []byte, addr *net.UDPAddr) {
resp := shared.BuildPkt(shared.RESP_REGISTER, append(net.ParseIP(internalIP), ciphertext...))
sendTo(addr, resp)
case shared.ENC_PKT:
peer := peers.Get(addr.IP.String())
peer := peers.Get(addr.String())
if peer == nil {
log.Println("data from unregistered peer:", addr.String())
return
@@ -139,7 +149,7 @@ func handleReq(req []byte, addr *net.UDPAddr) {
log.Println(srcIP + " -/> " + destIP + " (unrecognized IP)")
}
case shared.BROADCAST_PKT:
peer := peers.Get(addr.IP.String())
peer := peers.Get(addr.String())
if peer == nil {
log.Println("data from unregistered peer:", addr.String())
return
@@ -150,15 +160,16 @@ func handleReq(req []byte, addr *net.UDPAddr) {
case shared.REQ_GET_PUBKEY:
peerIP := net.IP(req[4:20]).String()
peer := peersByInternal.Get(peerIP)
if peer == nil {
log.Println("tried to get pubkey of unknown peer")
return
if peer != nil {
pubKey, err := hex.DecodeString(peer.HexPublicKey)
if err != nil {
panic(err)
}
resp := shared.BuildPkt(shared.RESP_GET_PUBKEY, append(net.ParseIP(peerIP), pubKey...))
sendTo(addr, resp)
}
resp := shared.BuildPkt(shared.RESP_GET_PUBKEY, append(net.ParseIP(peer.InternalIP), peer.PublicKey.Bytes()...))
sendTo(addr, resp)
case shared.REQ_ESTABLISH, shared.RESP_ESTABLISH:
peer := peers.Get(addr.IP.String())
peer := peers.Get(addr.String())
if peer == nil {
log.Println("unregistered peer tried to ESTABLISH")
return