From 39535114380f5c0c080ed6144347b67b204dfc51 Mon Sep 17 00:00:00 2001 From: Josh Deprez Date: Sun, 21 Apr 2024 17:47:58 +1000 Subject: [PATCH] Fix NBP replies for the router itself --- main.go | 90 +++++++++++++++++++++---------------- router/nbp.go | 110 ++++++++++++++++++++++++--------------------- router/nbp_aurp.go | 29 ++++++++---- router/router.go | 14 ++++++ 4 files changed, 146 insertions(+), 97 deletions(-) diff --git a/main.go b/main.go index a6beaa4..4a3ae98 100644 --- a/main.go +++ b/main.go @@ -266,9 +266,6 @@ func main() { continue } - // TODO: filter ethFrame.Dst to myHWAddr, the broadcast address, - // or the relevant zone multicast address - switch ethFrame.SNAPProto { case ethertalk.AARPProto: // log.Print("Got an AARP frame") @@ -385,7 +382,54 @@ func main() { return } - if apkt, ok := pkt.(*aurp.AppleTalkPacket); ok { + log.Printf("AURP: Got %T from %v", pkt, 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(): + 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 + } + + // 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) @@ -424,7 +468,7 @@ func main() { continue } // It's NBP - if err := rooter.HandleNBPInAURP(ddpkt); err != nil { + if err := rooter.HandleNBPInAURP(pr, ddpkt); err != nil { log.Printf("NBP/DDP/AURP: %v", err) } continue @@ -453,41 +497,9 @@ func main() { log.Printf("DDP/AURP: couldn't write output frame to device: %v", err) } continue - } - log.Printf("AURP: Got %T from %v", pkt, 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) - } - - // 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 + default: + log.Printf("AURP: Got unknown packet type %v", dh.PacketType) } } } diff --git a/router/nbp.go b/router/nbp.go index deb5fd7..77584b8 100644 --- a/router/nbp.go +++ b/router/nbp.go @@ -42,62 +42,16 @@ func (rtr *Router) HandleNBP(srcHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) erro switch nbpkt.Function { case nbp.FunctionLkUp: // when in AppleTalk, do as Apple Internet Router does... - tuple := nbpkt.Tuples[0] - if tuple.Object != "jrouter" && tuple.Object != "=" { - return nil - } - if tuple.Type != "AppleRouter" && tuple.Type != "=" { - return nil - } - if tuple.Zone != rtr.Config.EtherTalk.ZoneName && tuple.Zone != "*" && tuple.Zone != "" { - return nil - } - respPkt := &nbp.Packet{ - Function: nbp.FunctionLkUpReply, - NBPID: nbpkt.NBPID, - Tuples: []nbp.Tuple{ - { - Network: rtr.MyDDPAddr.Network, - Node: rtr.MyDDPAddr.Node, - Socket: 253, - Enumerator: 0, - Object: "jrouter", - Type: "AppleRouter", - Zone: rtr.Config.EtherTalk.ZoneName, - }, - }, - } - respRaw, err := respPkt.Marshal() - if err != nil { - return fmt.Errorf("couldn't marshal LkUp-Reply: %v", err) - } - outDDP := ddp.ExtPacket{ - ExtHeader: ddp.ExtHeader{ - Size: uint16(len(respRaw)) + atalk.DDPExtHeaderSize, - Cksum: 0, - DstNet: ddpkt.SrcNet, - DstNode: ddpkt.SrcNode, - DstSocket: ddpkt.SrcSocket, - SrcNet: rtr.MyDDPAddr.Network, - SrcNode: rtr.MyDDPAddr.Node, - SrcSocket: 2, - }, - Data: respRaw, - } - outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, outDDP) - if err != nil { + outDDP, err := rtr.helloWorldThisIsMe(ddpkt, nbpkt.NBPID, &nbpkt.Tuples[0]) + if err != nil || outDDP == nil { return err } - outFrame.Dst = srcHWAddr - outFrameRaw, err := ethertalk.Marshal(*outFrame) - if err != nil { - return err - } - return rtr.PcapHandle.WritePacketData(outFrameRaw) + return rtr.sendEtherTalkDDP(srcHWAddr, outDDP) case nbp.FunctionBrRq: // There must be 1! tuple := &nbpkt.Tuples[0] + ethDst := ethertalk.AppleTalkBroadcast if tuple.Zone != "*" && tuple.Zone != "" { ethDst = atalk.MulticastAddr(tuple.Zone) @@ -138,6 +92,18 @@ func (rtr *Router) HandleNBP(srcHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) erro return err } + // But also...if we match the query, reply as though it was a LkUp + outDDP2, err := rtr.helloWorldThisIsMe(ddpkt, nbpkt.NBPID, tuple) + if err != nil { + return err + } + if outDDP2 == nil { + continue + } + if err := rtr.sendEtherTalkDDP(srcHWAddr, outDDP2); err != nil { + return err + } + continue } @@ -180,3 +146,47 @@ func (rtr *Router) HandleNBP(srcHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) erro return nil } + +func (rtr *Router) helloWorldThisIsMe(ddpkt *ddp.ExtPacket, nbpID uint8, tuple *nbp.Tuple) (*ddp.ExtPacket, error) { + if tuple.Object != "jrouter" && tuple.Object != "=" { + return nil, nil + } + if tuple.Type != "AppleRouter" && tuple.Type != "=" { + return nil, nil + } + if tuple.Zone != rtr.Config.EtherTalk.ZoneName && tuple.Zone != "*" && tuple.Zone != "" { + return nil, nil + } + respPkt := &nbp.Packet{ + Function: nbp.FunctionLkUpReply, + NBPID: nbpID, + Tuples: []nbp.Tuple{ + { + Network: rtr.MyDDPAddr.Network, + Node: rtr.MyDDPAddr.Node, + Socket: 253, + Enumerator: 0, + Object: "jrouter", + Type: "AppleRouter", + Zone: rtr.Config.EtherTalk.ZoneName, + }, + }, + } + respRaw, err := respPkt.Marshal() + if err != nil { + return nil, fmt.Errorf("couldn't marshal LkUp-Reply: %v", err) + } + return &ddp.ExtPacket{ + ExtHeader: ddp.ExtHeader{ + Size: uint16(len(respRaw)) + atalk.DDPExtHeaderSize, + Cksum: 0, + DstNet: ddpkt.SrcNet, + DstNode: ddpkt.SrcNode, + DstSocket: ddpkt.SrcSocket, + SrcNet: rtr.MyDDPAddr.Network, + SrcNode: rtr.MyDDPAddr.Node, + SrcSocket: 2, + }, + Data: respRaw, + }, nil +} diff --git a/router/nbp_aurp.go b/router/nbp_aurp.go index c4241ac..9bdec25 100644 --- a/router/nbp_aurp.go +++ b/router/nbp_aurp.go @@ -26,7 +26,7 @@ import ( "github.com/sfiera/multitalk/pkg/ethertalk" ) -func (rtr *Router) HandleNBPInAURP(ddpkt *ddp.ExtPacket) error { +func (rtr *Router) HandleNBPInAURP(peer *Peer, ddpkt *ddp.ExtPacket) error { if ddpkt.Proto != ddp.ProtoNBP { return fmt.Errorf("invalid DDP type %d on socket 2", ddpkt.Proto) } @@ -44,6 +44,12 @@ func (rtr *Router) HandleNBPInAURP(ddpkt *ddp.ExtPacket) error { } tuple := &nbpkt.Tuples[0] + if tuple.Zone != rtr.Config.EtherTalk.ZoneName { + return fmt.Errorf("FwdReq querying zone %q, which is not our zone", tuple.Zone) + } + + // TODO: Route the FwdReq to another router if it's not our zone + log.Printf("NBP/DDP/AURP: Converting FwdReq to LkUp (%v)", tuple) // Convert it to a LkUp and broadcast on EtherTalk @@ -61,16 +67,23 @@ func (rtr *Router) HandleNBPInAURP(ddpkt *ddp.ExtPacket) error { ddpkt.DstNode = 0xFF // Broadcast node address within the dest network ddpkt.Data = nbpRaw - outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, *ddpkt) - if err != nil { - return err - } + dstEth := ethertalk.AppleTalkBroadcast if tuple.Zone != "*" && tuple.Zone != "" { - outFrame.Dst = atalk.MulticastAddr(tuple.Zone) + dstEth = atalk.MulticastAddr(tuple.Zone) } - outFrameRaw, err := ethertalk.Marshal(*outFrame) + if err := rtr.sendEtherTalkDDP(dstEth, ddpkt); err != nil { + return err + } + + // But also... if it matches us, reply directly with a LkUp-Reply of our own + outDDP, err := rtr.helloWorldThisIsMe(ddpkt, nbpkt.NBPID, tuple) + if err != nil || outDDP == nil { + return err + } + outDDPRaw, err := ddp.ExtMarshal(*outDDP) if err != nil { return err } - return rtr.PcapHandle.WritePacketData(outFrameRaw) + _, err = peer.Send(peer.Transport.NewAppleTalkPacket(outDDPRaw)) + return err } diff --git a/router/router.go b/router/router.go index 3fe5515..4bda4c0 100644 --- a/router/router.go +++ b/router/router.go @@ -20,6 +20,7 @@ import ( "github.com/google/gopacket/pcap" "github.com/sfiera/multitalk/pkg/ddp" "github.com/sfiera/multitalk/pkg/ethernet" + "github.com/sfiera/multitalk/pkg/ethertalk" ) type Router struct { @@ -30,3 +31,16 @@ type Router struct { RouteTable *RoutingTable ZoneTable *ZoneTable } + +func (rtr *Router) sendEtherTalkDDP(dstEth ethernet.Addr, pkt *ddp.ExtPacket) error { + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, *pkt) + if err != nil { + return err + } + outFrame.Dst = dstEth + outFrameRaw, err := ethertalk.Marshal(*outFrame) + if err != nil { + return err + } + return rtr.PcapHandle.WritePacketData(outFrameRaw) +}