diff --git a/main.go b/main.go index 74e34cc..f3c5c97 100644 --- a/main.go +++ b/main.go @@ -278,7 +278,7 @@ func main() { rtmpCh <- ddpkt case 2: // The NIS (name information socket / NBP socket) - if err := handleNBP(pcapHandle, myHWAddr, cfg, ddpkt); err != nil { + if err := handleNBP(pcapHandle, myHWAddr, ethFrame.Src, myAddr, cfg, ddpkt); err != nil { log.Printf("NBP: Couldn't handle: %v", err) } @@ -434,7 +434,7 @@ func main() { } } -func handleNBP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, cfg *config, ddpkt *ddp.ExtPacket) error { +func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAddr aarp.AddrPair, cfg *config, ddpkt *ddp.ExtPacket) error { if ddpkt.Proto != ddp.ProtoNBP { return fmt.Errorf("invalid DDP type %d on socket 2", ddpkt.Proto) } @@ -446,47 +446,97 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, cfg *config, ddp log.Printf("NBP: Got %v id %d with tuples %v", nbpkt.Function, nbpkt.NBPID, nbpkt.Tuples) - // Is it a BrRq? - if nbpkt.Function != nbp.FunctionBrRq { - return nil - } + 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 != cfg.EtherTalk.ZoneName && tuple.Zone != "*" && tuple.Zone != "" { + return nil + } + respPkt := &nbp.Packet{ + Function: nbp.FunctionLkUpReply, + NBPID: nbpkt.NBPID, + Tuples: []nbp.Tuple{ + { + Network: myAddr.Proto.Network, + Node: myAddr.Proto.Node, + Socket: 253, + Enumerator: 0, + Object: "jrouter", + Type: "AppleRouter", + Zone: cfg.EtherTalk.ZoneName, + }, + }, + } + respRaw, err := respPkt.Marshal() + if err != nil { + return fmt.Errorf("couldn't marshal LkUp-Reply: %v", err) + } + ddpkt.DstNet = ddpkt.SrcNet + ddpkt.DstNode = ddpkt.SrcNode + ddpkt.DstSocket = ddpkt.SrcSocket + ddpkt.SrcNet = myAddr.Proto.Network + ddpkt.SrcNode = myAddr.Proto.Node + ddpkt.SrcSocket = 2 + ddpkt.Data = respRaw + outFrame, err := ethertalk.AppleTalk(myHWAddr, *ddpkt) + if err != nil { + return err + } + outFrame.Dst = srcHWAddr + outFrameRaw, err := ethertalk.Marshal(*outFrame) + if err != nil { + return err + } + return pcapHandle.WritePacketData(outFrameRaw) - // There must be 1! - tuple := nbpkt.Tuples[0] + case nbp.FunctionBrRq: + // There must be 1! + tuple := nbpkt.Tuples[0] - if tuple.Zone != cfg.EtherTalk.ZoneName { - // TODO: Translate it into a FwdReq and route it to the - // routers with the appropriate zone(s). - return errors.New("TODO: BrRq-FwdReq translation") - } + if tuple.Zone != cfg.EtherTalk.ZoneName { + // TODO: Translate it into a FwdReq and route it to the + // routers with the appropriate zone(s). + return errors.New("TODO: BrRq-FwdReq translation") + } - // If it's for the local zone, translate it to a LkUp and broadcast it back - // out the EtherTalk port. - // "Note: On an internet, nodes on extended networks performing lookups in - // their own zone must replace a zone name of asterisk (*) with their actual - // zone name before sending the packet to A-ROUTER. All nodes performing - // lookups in their own zone will receive LkUp packets from themselves - // (actually sent by a router). The node's NBP process should expect to - // receive these packets and must reply to them." - // TODO: use zone-specific multicast - nbpkt.Function = nbp.FunctionLkUp - nbpRaw, err := nbpkt.Marshal() - if err != nil { - return fmt.Errorf("couldn't marshal LkUp: %v", err) - } + // If it's for the local zone, translate it to a LkUp and broadcast it back + // out the EtherTalk port. + // "Note: On an internet, nodes on extended networks performing lookups in + // their own zone must replace a zone name of asterisk (*) with their actual + // zone name before sending the packet to A-ROUTER. All nodes performing + // lookups in their own zone will receive LkUp packets from themselves + // (actually sent by a router). The node's NBP process should expect to + // receive these packets and must reply to them." + // TODO: use zone-specific multicast + nbpkt.Function = nbp.FunctionLkUp + nbpRaw, err := nbpkt.Marshal() + if err != nil { + return fmt.Errorf("couldn't marshal LkUp: %v", err) + } - ddpkt.DstNode = 0xFF // Broadcast node address within the dest network - ddpkt.Data = nbpRaw + ddpkt.DstNode = 0xFF // Broadcast node address within the dest network + ddpkt.Data = nbpRaw - outFrame, err := ethertalk.AppleTalk(myHWAddr, *ddpkt) - if err != nil { - return err + outFrame, err := ethertalk.AppleTalk(myHWAddr, *ddpkt) + if err != nil { + return err + } + outFrameRaw, err := ethertalk.Marshal(*outFrame) + if err != nil { + return err + } + return pcapHandle.WritePacketData(outFrameRaw) + + default: + return fmt.Errorf("TODO: handle function %v", nbpkt.Function) } - outFrameRaw, err := ethertalk.Marshal(*outFrame) - if err != nil { - return err - } - return pcapHandle.WritePacketData(outFrameRaw) } func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAddr aarp.AddrPair, cfg *config, ddpkt *ddp.ExtPacket) error {