vppn/peer/ifreader.go
2025-01-29 11:45:09 +01:00

101 lines
1.8 KiB
Go

package peer
import (
"io"
"log"
"sync/atomic"
)
type ifReader struct {
iface io.Reader
routes [256]*atomic.Pointer[peerRoute]
relay *atomic.Pointer[peerRoute]
sender dataPacketSender
}
func newIFReader(
iface io.Reader,
routes [256]*atomic.Pointer[peerRoute],
relay *atomic.Pointer[peerRoute],
sender dataPacketSender,
) *ifReader {
return &ifReader{
iface: iface,
routes: routes,
relay: relay,
sender: sender,
}
}
func (r *ifReader) Run() {
var (
packet = make([]byte, bufferSize)
remoteIP byte
ok bool
)
for {
packet = r.readNextPacket(packet)
if remoteIP, ok = r.parsePacket(packet); ok {
r.sendPacket(packet, remoteIP)
}
}
}
func (r *ifReader) sendPacket(pkt []byte, remoteIP byte) {
route := r.routes[remoteIP].Load()
if !route.Up {
log.Printf("Route not connected: %d", remoteIP)
return
}
// Direct path => early return.
if route.Direct {
r.sender.SendDataPacket(pkt, route)
return
}
if relay := r.relay.Load(); relay != nil && relay.Up {
r.sender.RelayDataPacket(pkt, route, relay)
}
}
// Get next packet, returning packet, and destination ip.
func (r *ifReader) readNextPacket(buf []byte) []byte {
n, err := r.iface.Read(buf[:cap(buf)])
if err != nil {
log.Fatalf("Failed to read from interface: %v", err)
}
return buf[:n]
}
func (r *ifReader) parsePacket(buf []byte) (byte, bool) {
n := len(buf)
if n == 0 {
return 0, false
}
version := buf[0] >> 4
switch version {
case 4:
if n < 20 {
log.Printf("Short IPv4 packet: %d", len(buf))
return 0, false
}
return buf[19], true
case 6:
if len(buf) < 40 {
log.Printf("Short IPv6 packet: %d", len(buf))
return 0, false
}
return buf[39], true
default:
log.Printf("Invalid IP packet version: %v", version)
return 0, false
}
}