This commit is contained in:
Josh Deprez 2024-04-23 11:56:15 +10:00
parent 1b33388e2a
commit 74936edbdd
Signed by: josh
SSH key fingerprint: SHA256:zZji7w1Ilh2RuUpbQcqkLPrqmRwpiCSycbF2EfKm6Kw

243
main.go
View file

@ -127,15 +127,16 @@ func main() {
pcapHandle.Close()
log.Fatalf("Couldn't set BPF filter on packet capture: %v", err)
}
defer pcapHandle.Close()
// defer pcapHandle.Close()
// Wait until all peer handlers have finished before closing the port
var handlersWG sync.WaitGroup
defer func() {
log.Print("Waiting for handlers to return...")
handlersWG.Wait()
ln.Close()
}()
defer handlersWG.Wait()
// defer func() {
// // log.Print("Waiting for handlers to return...")
// // handlersWG.Wait()
// // ln.Close()
// }()
goPeerHandler := func(p *router.Peer) {
handlersWG.Add(1)
go func() {
@ -244,9 +245,9 @@ func main() {
}
rawPkt, _, err := pcapHandle.ReadPacketData()
if errors.Is(err, pcap.NextErrorTimeoutExpired) {
continue
}
// if errors.Is(err, pcap.NextErrorTimeoutExpired) {
// continue
// }
if errors.Is(err, io.EOF) || errors.Is(err, pcap.NextErrorNoMorePackets) {
return
}
@ -357,132 +358,134 @@ func main() {
}()
// ----------------------------- AURP inbound -----------------------------
for {
if ctx.Err() != nil {
return
}
ln.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
pktbuf := make([]byte, 4096)
pktlen, raddr, readErr := ln.ReadFromUDP(pktbuf)
var operr *net.OpError
if errors.As(readErr, &operr) && operr.Timeout() {
continue
}
// log.Printf("AURP: Received packet of length %d from %v", pktlen, raddr)
dh, pkt, parseErr := aurp.ParsePacket(pktbuf[:pktlen])
if parseErr != nil {
log.Printf("AURP: Failed to parse packet: %v", parseErr)
continue
}
if readErr != nil {
log.Printf("AURP: Failed to read packet: %v", readErr)
return
}
log.Printf("AURP: Got %T from %v (%v)", pkt, raddr, dh.SourceDI)
// Existing peer?
ra := udpAddrFromNet(raddr)
pr := peers[ra]
if pr == nil {
// New peer!
pr = &router.Peer{
Config: cfg,
Transport: &aurp.Transport{
LocalDI: localDI,
RemoteDI: dh.SourceDI, // platinum rule
LocalConnID: nextConnID,
},
UDPConn: ln,
RemoteAddr: raddr,
RecieveCh: make(chan aurp.Packet, 1024),
RoutingTable: routes,
ZoneTable: zones,
Reconnect: false,
}
aurp.Inc(&nextConnID)
peers[ra] = pr
goPeerHandler(pr)
}
switch dh.PacketType {
case aurp.PacketTypeRouting:
// It's AURP routing data.
// Pass the packet to the goroutine in charge of this peer.
select {
case pr.RecieveCh <- pkt:
// That's it for us.
case <-ctx.Done():
go func() {
for {
if ctx.Err() != nil {
return
}
continue
// ln.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
pktbuf := make([]byte, 4096)
pktlen, raddr, readErr := ln.ReadFromUDP(pktbuf)
case aurp.PacketTypeAppleTalk:
apkt, ok := pkt.(*aurp.AppleTalkPacket)
if !ok {
log.Printf("AURP: Got %T but domain header packet type was %v ?", pkt, dh.PacketType)
// var operr *net.OpError
// if errors.As(readErr, &operr) && operr.Timeout() {
// continue
// }
// log.Printf("AURP: Received packet of length %d from %v", pktlen, raddr)
dh, pkt, parseErr := aurp.ParsePacket(pktbuf[:pktlen])
if parseErr != nil {
log.Printf("AURP: Failed to parse packet: %v", parseErr)
continue
}
// Route or otherwise handle the encapsulated AppleTalk traffic
ddpkt := new(ddp.ExtPacket)
if err := ddp.ExtUnmarshal(apkt.Data, ddpkt); err != nil {
log.Printf("AURP: Couldn't unmarshal encapsulated DDP packet: %v", err)
continue
}
log.Printf("DDP/AURP: Got %d.%d.%d -> %d.%d.%d proto %d data len %d",
ddpkt.SrcNet, ddpkt.SrcNode, ddpkt.SrcSocket,
ddpkt.DstNet, ddpkt.DstNode, ddpkt.DstSocket,
ddpkt.Proto, len(ddpkt.Data))
// "Route" the packet
// Since for now there's only one local network, the routing
// decision is pretty easy
// TODO: Fix this to support other AppleTalk routers
if ddpkt.DstNet < cfg.EtherTalk.NetStart || ddpkt.DstNet > cfg.EtherTalk.NetEnd {
log.Print("DDP/AURP: dropping packet not addressed to our EtherTalk range")
continue
if readErr != nil {
log.Printf("AURP: Failed to read packet: %v", readErr)
return
}
// Check and adjust the Hop Count
// Note the ddp package doesn't make this simple
hopCount := (ddpkt.Size & 0x3C00) >> 10
if hopCount >= 15 {
log.Printf("DDP/AURP: hop count exceeded (%d >= 15)", hopCount)
continue
}
hopCount++
ddpkt.Size &^= 0x3C00
ddpkt.Size |= hopCount << 10
log.Printf("AURP: Got %T from %v (%v)", pkt, raddr, dh.SourceDI)
// Is it addressed to me? Is it NBP?
if ddpkt.DstNode == 0 { // Node 0 = the router for the network
if ddpkt.DstSocket != 2 {
// Something else?? TODO
log.Printf("DDP/AURP: I don't have anything 'listening' on socket %d", ddpkt.DstSocket)
// Existing peer?
ra := udpAddrFromNet(raddr)
pr := peers[ra]
if pr == nil {
// New peer!
pr = &router.Peer{
Config: cfg,
Transport: &aurp.Transport{
LocalDI: localDI,
RemoteDI: dh.SourceDI, // platinum rule
LocalConnID: nextConnID,
},
UDPConn: ln,
RemoteAddr: raddr,
RecieveCh: make(chan aurp.Packet, 1024),
RoutingTable: routes,
ZoneTable: zones,
Reconnect: false,
}
aurp.Inc(&nextConnID)
peers[ra] = pr
goPeerHandler(pr)
}
switch dh.PacketType {
case aurp.PacketTypeRouting:
// It's AURP routing data.
// Pass the packet to the goroutine in charge of this peer.
select {
case pr.RecieveCh <- pkt:
// That's it for us.
case <-ctx.Done():
return
}
continue
case aurp.PacketTypeAppleTalk:
apkt, ok := pkt.(*aurp.AppleTalkPacket)
if !ok {
log.Printf("AURP: Got %T but domain header packet type was %v ?", pkt, dh.PacketType)
continue
}
// It's NBP
if err := rooter.HandleNBPInAURP(pr, ddpkt); err != nil {
log.Printf("NBP/DDP/AURP: %v", err)
// Route or otherwise handle the encapsulated AppleTalk traffic
ddpkt := new(ddp.ExtPacket)
if err := ddp.ExtUnmarshal(apkt.Data, ddpkt); err != nil {
log.Printf("AURP: Couldn't unmarshal encapsulated DDP packet: %v", err)
continue
}
log.Printf("DDP/AURP: Got %d.%d.%d -> %d.%d.%d proto %d data len %d",
ddpkt.SrcNet, ddpkt.SrcNode, ddpkt.SrcSocket,
ddpkt.DstNet, ddpkt.DstNode, ddpkt.DstSocket,
ddpkt.Proto, len(ddpkt.Data))
// "Route" the packet
// Since for now there's only one local network, the routing
// decision is pretty easy
// TODO: Fix this to support other AppleTalk routers
if ddpkt.DstNet < cfg.EtherTalk.NetStart || ddpkt.DstNet > cfg.EtherTalk.NetEnd {
log.Print("DDP/AURP: dropping packet not addressed to our EtherTalk range")
continue
}
// Check and adjust the Hop Count
// Note the ddp package doesn't make this simple
hopCount := (ddpkt.Size & 0x3C00) >> 10
if hopCount >= 15 {
log.Printf("DDP/AURP: hop count exceeded (%d >= 15)", hopCount)
continue
}
hopCount++
ddpkt.Size &^= 0x3C00
ddpkt.Size |= hopCount << 10
// Is it addressed to me? Is it NBP?
if ddpkt.DstNode == 0 { // Node 0 = the router for the network
if ddpkt.DstSocket != 2 {
// Something else?? TODO
log.Printf("DDP/AURP: I don't have anything 'listening' on socket %d", ddpkt.DstSocket)
continue
}
// It's NBP
if err := rooter.HandleNBPInAURP(pr, ddpkt); err != nil {
log.Printf("NBP/DDP/AURP: %v", err)
}
continue
}
// Note: resolving AARP can block
if err := rooter.SendEtherTalkDDP(ctx, ddpkt); err != nil {
log.Printf("DDP/AURP: couldn't send Ethertalk out: %v", err)
}
continue
}
// Note: resolving AARP can block
if err := rooter.SendEtherTalkDDP(ctx, ddpkt); err != nil {
log.Printf("DDP/AURP: couldn't send Ethertalk out: %v", err)
default:
log.Printf("AURP: Got unknown packet type %v", dh.PacketType)
}
continue
default:
log.Printf("AURP: Got unknown packet type %v", dh.PacketType)
}
}
}()
}
// Hashable net.UDPAddr