package peer import ( "io" "log" "net/netip" "sync/atomic" ) type IFReader struct { iface io.Reader writeToUDPAddrPort func([]byte, netip.AddrPort) (int, error) rt *atomic.Pointer[routingTable] buf1 []byte buf2 []byte } func NewIFReader( iface io.Reader, writeToUDPAddrPort func([]byte, netip.AddrPort) (int, error), rt *atomic.Pointer[routingTable], ) *IFReader { return &IFReader{iface, writeToUDPAddrPort, rt, newBuf(), newBuf()} } func (r *IFReader) Run() { packet := newBuf() for { r.handleNextPacket(packet) } } func (r *IFReader) handleNextPacket(packet []byte) { packet = r.readNextPacket(packet) remoteIP, ok := r.parsePacket(packet) if !ok { return } rt := r.rt.Load() peer := rt.Peers[remoteIP] if !peer.Up { r.logf("Peer %d not up.", peer.IP) return } enc := peer.EncryptDataPacket(peer.IP, packet, r.buf1) if peer.Direct { r.writeToUDPAddrPort(enc, peer.DirectAddr) return } relay, ok := rt.GetRelay() if !ok { r.logf("Relay not available for peer %d.", peer.IP) return } enc = relay.EncryptDataPacket(peer.IP, enc, r.buf2) r.writeToUDPAddrPort(enc, relay.DirectAddr) } 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 { r.logf("Short IPv4 packet: %d", len(buf)) return 0, false } return buf[19], true case 6: if len(buf) < 40 { r.logf("Short IPv6 packet: %d", len(buf)) return 0, false } return buf[39], true default: r.logf("Invalid IP packet version: %v", version) return 0, false } } func (*IFReader) logf(s string, args ...any) { log.Printf("[IFReader] "+s, args...) }