diff --git a/zip.go b/zip.go index a970ef3..50198c4 100644 --- a/zip.go +++ b/zip.go @@ -100,10 +100,23 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd if err != nil { return err } + + var resp interface { + Marshal() ([]byte, error) + } + switch zipkt := zipkt.(type) { + case *zip.QueryPacket: + // TODO: multiple packets + resp = &zip.ReplyPacket{ + Extended: false, + Networks: zones.Query(zipkt.Networks), + } + // TODO: direct to queryer + case *zip.GetNetInfoPacket: // Only running a network with one zone for now. - resp := &zip.GetNetInfoReplyPacket{ + resp = &zip.GetNetInfoReplyPacket{ ZoneInvalid: zipkt.ZoneName != cfg.EtherTalk.ZoneName, UseBroadcast: true, // TODO: add multicast addr computation OnlyOneZone: true, @@ -113,43 +126,47 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd MulticastAddr: ethertalk.AppleTalkBroadcast, DefaultZoneName: cfg.EtherTalk.ZoneName, } - respRaw, err := resp.Marshal() - if err != nil { - return fmt.Errorf("couldn't marshal GetNetInfoReplyPacket: %w", err) - } - - // TODO: fix - // "In cases where a node's provisional address is - // invalid, routers will not be able to respond to - // the node in a directed manner. An address is - // invalid if the network number is neither in the - // startup range nor in the network number range - // assigned to the node's network. In these cases, - // if the request was sent via a broadcast, the - // routers should respond with a broadcast." - ddpkt.DstNet, ddpkt.DstNode, ddpkt.DstSocket = 0x0000, 0xFF, ddpkt.SrcSocket - ddpkt.SrcNet = myAddr.Proto.Network - ddpkt.SrcNode = myAddr.Proto.Node - ddpkt.SrcSocket = 6 - ddpkt.Data = respRaw - outFrame, err := ethertalk.AppleTalk(myHWAddr, *ddpkt) - if err != nil { - return fmt.Errorf("couldn't create EtherTalk frame: %w", err) - } - outFrame.Dst = srcHWAddr - outFrameRaw, err := ethertalk.Marshal(*outFrame) - if err != nil { - return fmt.Errorf("couldn't marshal EtherTalk frame: %w", err) - } - if err := pcapHandle.WritePacketData(outFrameRaw); err != nil { - return fmt.Errorf("couldn't write packet data: %w", err) - } - return nil default: return fmt.Errorf("TODO: handle type %T", zipkt) } + if resp == nil { + return nil + } + respRaw, err := resp.Marshal() + if err != nil { + return fmt.Errorf("couldn't marshal %T: %w", resp, err) + } + + // TODO: fix + // "In cases where a node's provisional address is + // invalid, routers will not be able to respond to + // the node in a directed manner. An address is + // invalid if the network number is neither in the + // startup range nor in the network number range + // assigned to the node's network. In these cases, + // if the request was sent via a broadcast, the + // routers should respond with a broadcast." + ddpkt.DstNet, ddpkt.DstNode, ddpkt.DstSocket = 0x0000, 0xFF, ddpkt.SrcSocket + ddpkt.SrcNet = myAddr.Proto.Network + ddpkt.SrcNode = myAddr.Proto.Node + ddpkt.SrcSocket = 6 + ddpkt.Data = respRaw + outFrame, err := ethertalk.AppleTalk(myHWAddr, *ddpkt) + if err != nil { + return fmt.Errorf("couldn't create EtherTalk frame: %w", err) + } + outFrame.Dst = srcHWAddr + outFrameRaw, err := ethertalk.Marshal(*outFrame) + if err != nil { + return fmt.Errorf("couldn't marshal EtherTalk frame: %w", err) + } + if err := pcapHandle.WritePacketData(outFrameRaw); err != nil { + return fmt.Errorf("couldn't write packet data: %w", err) + } + return nil + default: return fmt.Errorf("invalid DDP type %d on socket 6", ddpkt.Proto) } diff --git a/zones.go b/zones.go index 306fa9c..1f08087 100644 --- a/zones.go +++ b/zones.go @@ -17,6 +17,7 @@ package main import ( + "slices" "sort" "sync" "time" @@ -67,6 +68,23 @@ func (zt *ZoneTable) Upsert(network ddp.Network, name string, local bool) { } } +func (zt *ZoneTable) Query(ns []ddp.Network) map[ddp.Network][]string { + slices.Sort(ns) + zs := make(map[ddp.Network][]string) + + zt.mu.Lock() + defer zt.mu.Unlock() + for _, z := range zt.zones { + if time.Since(z.LastSeen) > maxZoneAge { + continue + } + if _, ok := slices.BinarySearch(ns, z.Network); ok { + zs[z.Network] = append(zs[z.Network], z.Name) + } + } + return zs +} + func (zt *ZoneTable) LocalNames() []string { zt.mu.Lock() seen := make(map[string]struct{})