Fix NBP replies for the router itself
This commit is contained in:
parent
5103850d6e
commit
3953511438
4 changed files with 146 additions and 97 deletions
90
main.go
90
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
110
router/nbp.go
110
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue