103 lines
2.0 KiB
Go
103 lines
2.0 KiB
Go
package node
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type ifReader struct {
|
|
iface io.Reader
|
|
routes [256]*atomic.Pointer[peerRoute]
|
|
relay *atomic.Pointer[peerRoute]
|
|
sendDataPacket func(pkt []byte, route *peerRoute)
|
|
relayDataPacket func(pkt []byte, route, relay *peerRoute)
|
|
}
|
|
|
|
func newIFReader(
|
|
iface io.Reader,
|
|
routes [256]*atomic.Pointer[peerRoute],
|
|
relay *atomic.Pointer[peerRoute],
|
|
sendDataPacket func(pkt []byte, route *peerRoute),
|
|
relayDackPacket func(pkt []byte, route, relay *peerRoute),
|
|
) *ifReader {
|
|
return &ifReader{
|
|
iface: iface,
|
|
routes: routes,
|
|
relay: relay,
|
|
sendDataPacket: sendDataPacket,
|
|
}
|
|
}
|
|
|
|
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.sendDataPacket(pkt, route)
|
|
return
|
|
}
|
|
|
|
if relay := r.relay.Load(); relay != nil {
|
|
r.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
|
|
}
|
|
}
|