From 1a83e4d5439a174deb4b5cf169055a48c52ec4e3 Mon Sep 17 00:00:00 2001 From: Josh Deprez Date: Fri, 12 Apr 2024 16:14:27 +1000 Subject: [PATCH] Start routing table --- atalk/nbp/nbp.go | 10 ++++++++- aurp/transport.go | 8 +++++++ main.go | 30 ++++++++++++++++++++------ peer.go | 5 ++++- route.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 route.go diff --git a/atalk/nbp/nbp.go b/atalk/nbp/nbp.go index dc4ed89..20acd90 100644 --- a/atalk/nbp/nbp.go +++ b/atalk/nbp/nbp.go @@ -79,6 +79,14 @@ func Unmarshal(data []byte) (*Packet, error) { NBPID: data[1], } tupleCount := data[0] & 0x0F + if tupleCount == 0 { + return nil, fmt.Errorf("no tuples") + } + // Only LkUp-Reply can have more than 1 tuple + if tupleCount > 1 && p.Function != FunctionLkUpReply { + return nil, fmt.Errorf("wrong number of tuples %d for function %s", tupleCount, p.Function) + } + data = data[2:] for range tupleCount { if len(data) < 8 { @@ -144,7 +152,7 @@ func (t *Tuple) writeTo(b *bytes.Buffer) error { return nil } -func (t *Tuple) String() string { +func (t Tuple) String() string { return fmt.Sprintf("%d.%d.%d (enum %d) <-> %s:%s@%s", t.Network, t.Node, t.Socket, t.Enumerator, t.Object, t.Type, t.Zone, ) diff --git a/aurp/transport.go b/aurp/transport.go index 63f7716..f3fe5a6 100644 --- a/aurp/transport.go +++ b/aurp/transport.go @@ -102,6 +102,14 @@ func (tr *Transport) sequenced(connID, seq uint16) TrHeader { } } +// NewAppleTalkPacket returns a new AppleTalkPacket. +func (tr *Transport) NewAppleTalkPacket(data []byte) *AppleTalkPacket { + return &AppleTalkPacket{ + DomainHeader: tr.domainHeader(PacketTypeAppleTalk), + Data: data, + } +} + // NewOpenReqPacket returns a new Open-Req packet structure. By default it sets // all SUI flags and uses version 1. func (tr *Transport) NewOpenReqPacket(opts Options) *OpenReqPacket { diff --git a/main.go b/main.go index 3b0cc98..eba3813 100644 --- a/main.go +++ b/main.go @@ -128,7 +128,7 @@ func main() { }() } - // --------------- Configured peer setup --------------- + // ------------------------- Configured peer setup ------------------------ for _, peerStr := range cfg.Peers { if !hasPortRE.MatchString(peerStr) { peerStr += ":387" @@ -156,12 +156,12 @@ func main() { goPeerHandler(peer) } - // -------------------- AARP -------------------- + // --------------------------------- AARP --------------------------------- aarpMachine := NewAARPMachine(cfg, pcapHandle, myHWAddr) aarpCh := make(chan *ethertalk.Packet, 1024) go aarpMachine.Run(ctx, aarpCh) - // -------------------- RTMP -------------------- + // --------------------------------- RTMP --------------------------------- rtmpMachine := &RTMPMachine{ aarp: aarpMachine, cfg: cfg, @@ -170,7 +170,7 @@ func main() { rtmpCh := make(chan *ddp.ExtPacket, 1024) go rtmpMachine.Run(ctx, rtmpCh) - // --------------------- NBP -------------------- + // ---------------------------------- NBP --------------------------------- nbpMachine := &NBPMachine{ aarp: aarpMachine, pcapHandle: pcapHandle, @@ -178,7 +178,7 @@ func main() { nbpCh := make(chan *ddp.ExtPacket, 1024) go nbpMachine.Run(ctx, nbpCh) - // ---------- Raw AppleTalk/AARP inbound ---------- + // ---------------------- Raw AppleTalk/AARP inbound ---------------------- go func() { for { if ctx.Err() != nil { @@ -235,12 +235,28 @@ func main() { continue } + // TODO: If the packet is NBP BrRq and for a zone we have in + // our zone info table, convert it to a FwdReq and send that + // out to the peer + // TODO: implement the zone information table + // Our network? // "The network number 0 is reserved to mean unknown; by default // it specifies the local network to which the node is // connected. Packets whose destination network number is 0 are // addressed to a node on the local network." - if ddpkt.DstNet != 0 && ddpkt.DstNet != myAddr.Proto.Network { + if ddpkt.DstNet != 0 && (ddpkt.DstNet < cfg.EtherTalk.NetStart || ddpkt.DstNet > cfg.EtherTalk.NetEnd) { + // Is it for a network in the routing table? + rt := lookupRoute(ddpkt.DstNet) + if rt == nil { + continue + } + + // Encap ethPacket.Payload into an AURP packet + if _, err := rt.peer.send(rt.peer.tr.NewAppleTalkPacket(ethFrame.Payload)); err != nil { + log.Printf("DDP: Couldn't forward packet to AURP peer: %v", err) + } + continue } @@ -275,7 +291,7 @@ func main() { } }() - // ---------- AURP inbound ---------- + // ----------------------------- AURP inbound ----------------------------- for { if ctx.Err() != nil { return diff --git a/peer.go b/peer.go index ebb40d4..690e4f0 100644 --- a/peer.go +++ b/peer.go @@ -24,6 +24,7 @@ import ( "time" "gitea.drjosh.dev/josh/jrouter/aurp" + "github.com/sfiera/multitalk/pkg/ddp" ) const ( @@ -275,7 +276,9 @@ func (p *peer) handle(ctx context.Context) error { log.Printf("Learned about these networks: %v", pkt.Networks) - // TODO: Integrate info into route table + for _, nt := range pkt.Networks { + upsertRoutes(ddp.Network(nt.RangeStart), ddp.Network(nt.RangeEnd), p, nt.Distance) + } // TODO: track which networks we don't have zone info for, and // only set SZI for those ? diff --git a/route.go b/route.go new file mode 100644 index 0000000..f0d9f52 --- /dev/null +++ b/route.go @@ -0,0 +1,54 @@ +package main + +import ( + "cmp" + "fmt" + "slices" + "sync" + "time" + + "github.com/sfiera/multitalk/pkg/ddp" +) + +type route struct { + peer *peer + metric uint8 + last time.Time +} + +var ( + routingTableMu sync.Mutex + routingTable = make(map[ddp.Network][]*route) +) + +func lookupRoute(network ddp.Network) *route { + routingTableMu.Lock() + defer routingTableMu.Unlock() + + rs := routingTable[network] + if len(rs) == 0 { + return nil + } + return rs[0] +} + +func upsertRoutes(netStart, netEnd ddp.Network, peer *peer, metric uint8) error { + if netStart > netEnd { + return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd) + } + r := &route{ + peer: peer, + metric: metric, + last: time.Now(), + } + + routingTableMu.Lock() + defer routingTableMu.Unlock() + for n := netStart; n <= netEnd; n++ { + routingTable[n] = append(routingTable[n], r) + slices.SortFunc(routingTable[n], func(r, s *route) int { + return cmp.Compare(r.metric, s.metric) + }) + } + return nil +}