diff --git a/main.go b/main.go index 6f8adb5..1f1b40a 100644 --- a/main.go +++ b/main.go @@ -32,6 +32,8 @@ import ( "time" "gitea.drjosh.dev/josh/jrouter/aurp" + "gitea.drjosh.dev/josh/jrouter/router" + "github.com/google/gopacket/pcap" "github.com/sfiera/multitalk/pkg/ddp" "github.com/sfiera/multitalk/pkg/ethernet" @@ -46,7 +48,7 @@ func main() { flag.Parse() log.Println("jrouter") - cfg, err := loadConfig(*configFilePath) + cfg, err := router.LoadConfig(*configFilePath) if err != nil { log.Fatalf("Couldn't load configuration file: %v", err) } @@ -80,7 +82,7 @@ func main() { log.Printf("EtherTalk configuration: %+v", cfg.EtherTalk) - peers := make(map[udpAddr]*peer) + peers := make(map[udpAddr]*router.Peer) var nextConnID uint16 for nextConnID == 0 { nextConnID = uint16(rand.IntN(0x10000)) @@ -131,17 +133,17 @@ func main() { handlersWG.Wait() ln.Close() }() - goPeerHandler := func(p *peer) { + goPeerHandler := func(p *router.Peer) { handlersWG.Add(1) go func() { defer handlersWG.Done() - p.handle(ctx) + p.Handle(ctx) }() } // -------------------------------- Tables -------------------------------- - routing := NewRoutingTable() - zones := NewZoneTable() + routing := router.NewRoutingTable() + zones := router.NewZoneTable() zones.Upsert(cfg.EtherTalk.NetStart, cfg.EtherTalk.ZoneName, true) // ------------------------- Configured peer setup ------------------------ @@ -156,18 +158,18 @@ func main() { } log.Printf("resolved %q to %v", peerStr, raddr) - peer := &peer{ - cfg: cfg, - tr: &aurp.Transport{ + peer := &router.Peer{ + Config: cfg, + Transport: &aurp.Transport{ LocalDI: localDI, RemoteDI: aurp.IPDomainIdentifier(raddr.IP), LocalConnID: nextConnID, }, - conn: ln, - raddr: raddr, - recv: make(chan aurp.Packet, 1024), - routingTable: routing, - zoneTable: zones, + UDPConn: ln, + RemoteAddr: raddr, + RecieveCh: make(chan aurp.Packet, 1024), + RoutingTable: routing, + ZoneTable: zones, } aurp.Inc(&nextConnID) peers[udpAddrFromNet(raddr)] = peer @@ -175,20 +177,30 @@ func main() { } // --------------------------------- AARP --------------------------------- - aarpMachine := NewAARPMachine(cfg, pcapHandle, myHWAddr) + aarpMachine := router.NewAARPMachine(cfg, pcapHandle, myHWAddr) aarpCh := make(chan *ethertalk.Packet, 1024) go aarpMachine.Run(ctx, aarpCh) // --------------------------------- RTMP --------------------------------- - rtmpMachine := &RTMPMachine{ - aarp: aarpMachine, - cfg: cfg, - pcapHandle: pcapHandle, - routingTable: routing, + rtmpMachine := &router.RTMPMachine{ + AARP: aarpMachine, + Config: cfg, + PcapHandle: pcapHandle, + RoutingTable: routing, } rtmpCh := make(chan *ddp.ExtPacket, 1024) go rtmpMachine.Run(ctx, rtmpCh) + // -------------------------------- Router -------------------------------- + rooter := &router.Router{ + Config: cfg, + PcapHandle: pcapHandle, + MyHWAddr: myHWAddr, + // MyDDPAddr: ..., + RouteTable: routing, + ZoneTable: zones, + } + // ---------------------- Raw AppleTalk/AARP inbound ---------------------- go func() { for { @@ -249,6 +261,7 @@ func main() { if !ok { continue } + rooter.MyDDPAddr = myAddr.Proto // Our network? // "The network number 0 is reserved to mean unknown; by default @@ -264,8 +277,8 @@ func main() { } // Encap ethPacket.Payload into an AURP packet - log.Printf("DDP: forwarding to AURP peer %v", rt.Peer.tr.RemoteDI) - if _, err := rt.Peer.send(rt.Peer.tr.NewAppleTalkPacket(ethFrame.Payload)); err != nil { + log.Printf("DDP: forwarding to AURP peer %v", rt.Peer.Transport.RemoteDI) + if _, err := rt.Peer.Send(rt.Peer.Transport.NewAppleTalkPacket(ethFrame.Payload)); err != nil { log.Printf("DDP: Couldn't forward packet to AURP peer: %v", err) } @@ -285,17 +298,17 @@ func main() { rtmpCh <- ddpkt case 2: // The NIS (name information socket / NBP socket) - if err := handleNBP(pcapHandle, myHWAddr, ethFrame.Src, myAddr, zones, routing, cfg, ddpkt); err != nil { + if err := rooter.HandleNBP(ethFrame.Src, ddpkt); err != nil { log.Printf("NBP: Couldn't handle: %v", err) } case 4: // The AEP socket - if err := handleAEP(pcapHandle, myHWAddr, ethFrame.Src, ddpkt); err != nil { + if err := rooter.HandleAEP(ethFrame.Src, ddpkt); err != nil { log.Printf("AEP: Couldn't handle: %v", err) } case 6: // The ZIS (zone information socket / ZIP socket) - if err := handleZIP(pcapHandle, ethFrame.Src, myHWAddr, myAddr, cfg, zones, ddpkt); err != nil { + if err := rooter.HandleZIP(ethFrame.Src, ddpkt); err != nil { log.Printf("ZIP: couldn't handle: %v", err) } @@ -375,7 +388,7 @@ func main() { continue } // It's NBP - if err := handleNBPInAURP(pcapHandle, myHWAddr, ddpkt); err != nil { + if err := rooter.HandleNBPInAURP(ddpkt); err != nil { log.Printf("NBP/DDP/AURP: %v", err) } continue @@ -413,18 +426,18 @@ func main() { pr := peers[ra] if pr == nil { // New peer! - pr = &peer{ - cfg: cfg, - tr: &aurp.Transport{ + pr = &router.Peer{ + Config: cfg, + Transport: &aurp.Transport{ LocalDI: localDI, RemoteDI: dh.SourceDI, // platinum rule LocalConnID: nextConnID, }, - conn: ln, - raddr: raddr, - recv: make(chan aurp.Packet, 1024), - routingTable: routing, - zoneTable: zones, + UDPConn: ln, + RemoteAddr: raddr, + RecieveCh: make(chan aurp.Packet, 1024), + RoutingTable: routing, + ZoneTable: zones, } aurp.Inc(&nextConnID) peers[ra] = pr @@ -433,7 +446,7 @@ func main() { // Pass the packet to the goroutine in charge of this peer. select { - case pr.recv <- pkt: + case pr.RecieveCh <- pkt: // That's it for us. case <-ctx.Done(): diff --git a/aarp.go b/router/aarp.go similarity index 99% rename from aarp.go rename to router/aarp.go index fc3676d..6a6169f 100644 --- a/aarp.go +++ b/router/aarp.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "context" @@ -44,7 +44,7 @@ const ( type AARPMachine struct { *addressMappingTable - cfg *config + cfg *Config pcapHandle *pcap.Handle // The Run goroutine is responsible for all writes to myAddr.Proto and @@ -58,7 +58,7 @@ type AARPMachine struct { } // NewAARPMachine creates a new AARPMachine. -func NewAARPMachine(cfg *config, pcapHandle *pcap.Handle, myHWAddr ethernet.Addr) *AARPMachine { +func NewAARPMachine(cfg *Config, pcapHandle *pcap.Handle, myHWAddr ethernet.Addr) *AARPMachine { return &AARPMachine{ addressMappingTable: new(addressMappingTable), cfg: cfg, diff --git a/aep.go b/router/aep.go similarity index 87% rename from aep.go rename to router/aep.go index f81d1a1..9695a88 100644 --- a/aep.go +++ b/router/aep.go @@ -14,19 +14,18 @@ limitations under the License. */ -package main +package router import ( "fmt" "gitea.drjosh.dev/josh/jrouter/atalk/aep" - "github.com/google/gopacket/pcap" "github.com/sfiera/multitalk/pkg/ddp" "github.com/sfiera/multitalk/pkg/ethernet" "github.com/sfiera/multitalk/pkg/ethertalk" ) -func handleAEP(pcapHandle *pcap.Handle, src, dst ethernet.Addr, ddpkt *ddp.ExtPacket) error { +func (rtr *Router) HandleAEP(src ethernet.Addr, ddpkt *ddp.ExtPacket) error { if ddpkt.Proto != ddp.ProtoAEP { return fmt.Errorf("invalid DDP type %d on socket 4", ddpkt.Proto) } @@ -49,16 +48,16 @@ func handleAEP(pcapHandle *pcap.Handle, src, dst ethernet.Addr, ddpkt *ddp.ExtPa ddpkt.DstSocket, ddpkt.SrcSocket = ddpkt.SrcSocket, ddpkt.DstSocket ddpkt.Data[0] = byte(aep.EchoReply) - ethFrame, err := ethertalk.AppleTalk(src, *ddpkt) + ethFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, *ddpkt) if err != nil { return err } - ethFrame.Dst = dst + ethFrame.Dst = src ethFrameRaw, err := ethertalk.Marshal(*ethFrame) if err != nil { return err } - return pcapHandle.WritePacketData(ethFrameRaw) + return rtr.PcapHandle.WritePacketData(ethFrameRaw) default: return fmt.Errorf("invalid AEP function %d", ep.Function) diff --git a/config.go b/router/config.go similarity index 94% rename from config.go rename to router/config.go index d573177..6ee5d76 100644 --- a/config.go +++ b/router/config.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "os" @@ -23,7 +23,7 @@ import ( "gopkg.in/yaml.v3" ) -type config struct { +type Config struct { // Optional: default is 387. ListenPort uint16 `yaml:"listen_port"` @@ -55,14 +55,14 @@ type config struct { Peers []string `yaml:"peers"` } -func loadConfig(cfgPath string) (*config, error) { +func LoadConfig(cfgPath string) (*Config, error) { f, err := os.Open(cfgPath) if err != nil { return nil, err } defer f.Close() - c := new(config) + c := new(Config) if err := yaml.NewDecoder(f).Decode(c); err != nil { return nil, err } diff --git a/nbp.go b/router/nbp.go similarity index 82% rename from nbp.go rename to router/nbp.go index 2e7680d..deb5fd7 100644 --- a/nbp.go +++ b/router/nbp.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "fmt" @@ -22,14 +22,12 @@ import ( "gitea.drjosh.dev/josh/jrouter/atalk" "gitea.drjosh.dev/josh/jrouter/atalk/nbp" - "github.com/google/gopacket/pcap" - "github.com/sfiera/multitalk/pkg/aarp" "github.com/sfiera/multitalk/pkg/ddp" "github.com/sfiera/multitalk/pkg/ethernet" "github.com/sfiera/multitalk/pkg/ethertalk" ) -func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAddr aarp.AddrPair, zoneTable *ZoneTable, routeTable *RoutingTable, cfg *config, ddpkt *ddp.ExtPacket) error { +func (rtr *Router) HandleNBP(srcHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) error { if ddpkt.Proto != ddp.ProtoNBP { return fmt.Errorf("invalid DDP type %d on socket 2", ddpkt.Proto) } @@ -51,7 +49,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd if tuple.Type != "AppleRouter" && tuple.Type != "=" { return nil } - if tuple.Zone != cfg.EtherTalk.ZoneName && tuple.Zone != "*" && tuple.Zone != "" { + if tuple.Zone != rtr.Config.EtherTalk.ZoneName && tuple.Zone != "*" && tuple.Zone != "" { return nil } respPkt := &nbp.Packet{ @@ -59,13 +57,13 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd NBPID: nbpkt.NBPID, Tuples: []nbp.Tuple{ { - Network: myAddr.Proto.Network, - Node: myAddr.Proto.Node, + Network: rtr.MyDDPAddr.Network, + Node: rtr.MyDDPAddr.Node, Socket: 253, Enumerator: 0, Object: "jrouter", Type: "AppleRouter", - Zone: cfg.EtherTalk.ZoneName, + Zone: rtr.Config.EtherTalk.ZoneName, }, }, } @@ -80,13 +78,13 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd DstNet: ddpkt.SrcNet, DstNode: ddpkt.SrcNode, DstSocket: ddpkt.SrcSocket, - SrcNet: myAddr.Proto.Network, - SrcNode: myAddr.Proto.Node, + SrcNet: rtr.MyDDPAddr.Network, + SrcNode: rtr.MyDDPAddr.Node, SrcSocket: 2, }, Data: respRaw, } - outFrame, err := ethertalk.AppleTalk(myHWAddr, outDDP) + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, outDDP) if err != nil { return err } @@ -95,7 +93,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd if err != nil { return err } - return pcapHandle.WritePacketData(outFrameRaw) + return rtr.PcapHandle.WritePacketData(outFrameRaw) case nbp.FunctionBrRq: // There must be 1! @@ -105,7 +103,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd ethDst = atalk.MulticastAddr(tuple.Zone) } - zones := zoneTable.LookupName(tuple.Zone) + zones := rtr.ZoneTable.LookupName(tuple.Zone) for _, z := range zones { if z.Local { // If it's for the local zone, translate it to a LkUp and broadcast it back @@ -127,7 +125,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd outDDP.DstNode = 0xFF // Broadcast node address within the dest network outDDP.Data = nbpRaw - outFrame, err := ethertalk.AppleTalk(myHWAddr, outDDP) + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, outDDP) if err != nil { return err } @@ -136,14 +134,14 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd if err != nil { return err } - if err := pcapHandle.WritePacketData(outFrameRaw); err != nil { + if err := rtr.PcapHandle.WritePacketData(outFrameRaw); err != nil { return err } continue } - route := routeTable.LookupRoute(z.Network) + route := rtr.RouteTable.LookupRoute(z.Network) if route == nil { return fmt.Errorf("no route for network %d", z.Network) } @@ -171,7 +169,7 @@ func handleNBP(pcapHandle *pcap.Handle, myHWAddr, srcHWAddr ethernet.Addr, myAdd return err } - if _, err := peer.send(peer.tr.NewAppleTalkPacket(outDDPRaw)); err != nil { + if _, err := peer.Send(peer.Transport.NewAppleTalkPacket(outDDPRaw)); err != nil { return fmt.Errorf("sending FwdReq on to peer: %w", err) } } diff --git a/nbp_aurp.go b/router/nbp_aurp.go similarity index 87% rename from nbp_aurp.go rename to router/nbp_aurp.go index 10087f2..c4241ac 100644 --- a/nbp_aurp.go +++ b/router/nbp_aurp.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "fmt" @@ -22,13 +22,11 @@ import ( "gitea.drjosh.dev/josh/jrouter/atalk" "gitea.drjosh.dev/josh/jrouter/atalk/nbp" - "github.com/google/gopacket/pcap" "github.com/sfiera/multitalk/pkg/ddp" - "github.com/sfiera/multitalk/pkg/ethernet" "github.com/sfiera/multitalk/pkg/ethertalk" ) -func handleNBPInAURP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) error { +func (rtr *Router) HandleNBPInAURP(ddpkt *ddp.ExtPacket) error { if ddpkt.Proto != ddp.ProtoNBP { return fmt.Errorf("invalid DDP type %d on socket 2", ddpkt.Proto) } @@ -63,7 +61,7 @@ func handleNBPInAURP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, ddpkt *ddp ddpkt.DstNode = 0xFF // Broadcast node address within the dest network ddpkt.Data = nbpRaw - outFrame, err := ethertalk.AppleTalk(myHWAddr, *ddpkt) + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, *ddpkt) if err != nil { return err } @@ -74,5 +72,5 @@ func handleNBPInAURP(pcapHandle *pcap.Handle, myHWAddr ethernet.Addr, ddpkt *ddp if err != nil { return err } - return pcapHandle.WritePacketData(outFrameRaw) + return rtr.PcapHandle.WritePacketData(outFrameRaw) } diff --git a/peer.go b/router/peer.go similarity index 77% rename from peer.go rename to router/peer.go index 3855495..320e329 100644 --- a/peer.go +++ b/router/peer.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "bytes" @@ -75,28 +75,27 @@ func (ss senderState) String() string { }[ss] } -type peer struct { - cfg *config - tr *aurp.Transport - conn *net.UDPConn - raddr *net.UDPAddr - recv chan aurp.Packet - - routingTable *RoutingTable - zoneTable *ZoneTable +type Peer struct { + Config *Config + Transport *aurp.Transport + UDPConn *net.UDPConn + RemoteAddr *net.UDPAddr + RecieveCh chan aurp.Packet + RoutingTable *RoutingTable + ZoneTable *ZoneTable } -// send encodes and sends pkt to the remote host. -func (p *peer) send(pkt aurp.Packet) (int, error) { +// Send encodes and sends pkt to the remote host. +func (p *Peer) Send(pkt aurp.Packet) (int, error) { var b bytes.Buffer if _, err := pkt.WriteTo(&b); err != nil { return 0, err } - log.Printf("Sending %T (len %d) to %v", pkt, b.Len(), p.raddr) - return p.conn.WriteToUDP(b.Bytes(), p.raddr) + log.Printf("Sending %T (len %d) to %v", pkt, b.Len(), p.RemoteAddr) + return p.UDPConn.WriteToUDP(b.Bytes(), p.RemoteAddr) } -func (p *peer) handle(ctx context.Context) error { +func (p *Peer) Handle(ctx context.Context) error { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() @@ -108,7 +107,7 @@ func (p *peer) handle(ctx context.Context) error { sstate := ssUnconnected // Write an Open-Req packet - if _, err := p.send(p.tr.NewOpenReqPacket(nil)); err != nil { + if _, err := p.Send(p.Transport.NewOpenReqPacket(nil)); err != nil { log.Printf("Couldn't send Open-Req packet: %v", err) return err } @@ -123,7 +122,7 @@ func (p *peer) handle(ctx context.Context) error { return ctx.Err() } // Send a best-effort Router Down before returning - if _, err := p.send(p.tr.NewRDPacket(aurp.ErrCodeNormalClose)); err != nil { + if _, err := p.Send(p.Transport.NewRDPacket(aurp.ErrCodeNormalClose)); err != nil { log.Printf("Couldn't send RD packet: %v", err) } return ctx.Err() @@ -143,7 +142,7 @@ func (p *peer) handle(ctx context.Context) error { // Send another Open-Req sendRetries++ lastSend = time.Now() - if _, err := p.send(p.tr.NewOpenReqPacket(nil)); err != nil { + if _, err := p.Send(p.Transport.NewOpenReqPacket(nil)); err != nil { log.Printf("Couldn't send Open-Req packet: %v", err) return err } @@ -153,7 +152,7 @@ func (p *peer) handle(ctx context.Context) error { if time.Since(lastHeardFrom) <= lastHeardFromTimer { break } - if _, err := p.send(p.tr.NewTicklePacket()); err != nil { + if _, err := p.Send(p.Transport.NewTicklePacket()); err != nil { log.Printf("Couldn't send Tickle: %v", err) return err } @@ -173,7 +172,7 @@ func (p *peer) handle(ctx context.Context) error { sendRetries++ lastSend = time.Now() - if _, err := p.send(p.tr.NewTicklePacket()); err != nil { + if _, err := p.Send(p.Transport.NewTicklePacket()); err != nil { log.Printf("Couldn't send Tickle: %v", err) return err } @@ -185,7 +184,7 @@ func (p *peer) handle(ctx context.Context) error { // TODO } - case pkt := <-p.recv: + case pkt := <-p.RecieveCh: lastHeardFrom = time.Now() switch pkt := pkt.(type) { @@ -195,25 +194,25 @@ func (p *peer) handle(ctx context.Context) error { } // The peer tells us their connection ID in Open-Req. - p.tr.RemoteConnID = pkt.ConnectionID + p.Transport.RemoteConnID = pkt.ConnectionID // Formulate a response. var orsp *aurp.OpenRspPacket switch { case pkt.Version != 1: // Respond with Open-Rsp with unknown version error. - orsp = p.tr.NewOpenRspPacket(0, int16(aurp.ErrCodeInvalidVersion), nil) + orsp = p.Transport.NewOpenRspPacket(0, int16(aurp.ErrCodeInvalidVersion), nil) case len(pkt.Options) > 0: // Options? OPTIONS? We don't accept no stinkin' _options_ - orsp = p.tr.NewOpenRspPacket(0, int16(aurp.ErrCodeOptionNegotiation), nil) + orsp = p.Transport.NewOpenRspPacket(0, int16(aurp.ErrCodeOptionNegotiation), nil) default: // Accept it I guess. - orsp = p.tr.NewOpenRspPacket(0, 1, nil) + orsp = p.Transport.NewOpenRspPacket(0, 1, nil) } - if _, err := p.send(orsp); err != nil { + if _, err := p.Send(orsp); err != nil { log.Printf("Couldn't send Open-Rsp: %v", err) return err } @@ -225,7 +224,7 @@ func (p *peer) handle(ctx context.Context) error { if rstate == rsUnconnected { lastSend = time.Now() sendRetries = 0 - if _, err := p.send(p.tr.NewOpenReqPacket(nil)); err != nil { + if _, err := p.Send(p.Transport.NewOpenReqPacket(nil)); err != nil { log.Printf("Couldn't send Open-Req packet: %v", err) return err } @@ -238,7 +237,7 @@ func (p *peer) handle(ctx context.Context) error { } if pkt.RateOrErrCode < 0 { // It's an error code. - log.Printf("Open-Rsp error code from peer %v: %d", p.raddr.IP, pkt.RateOrErrCode) + log.Printf("Open-Rsp error code from peer %v: %d", p.RemoteAddr.IP, pkt.RateOrErrCode) rstate = rsUnconnected break } @@ -246,7 +245,7 @@ func (p *peer) handle(ctx context.Context) error { rstate = rsConnected // Send an RI-Req - if _, err := p.send(p.tr.NewRIReqPacket()); err != nil { + if _, err := p.Send(p.Transport.NewRIReqPacket()); err != nil { log.Printf("Couldn't send RI-Req packet: %v", err) return err } @@ -260,13 +259,13 @@ func (p *peer) handle(ctx context.Context) error { nets := aurp.NetworkTuples{ { Extended: true, - RangeStart: uint16(p.cfg.EtherTalk.NetStart), - RangeEnd: uint16(p.cfg.EtherTalk.NetEnd), + RangeStart: uint16(p.Config.EtherTalk.NetStart), + RangeEnd: uint16(p.Config.EtherTalk.NetEnd), Distance: 0, }, } - p.tr.LocalSeq = 1 - if _, err := p.send(p.tr.NewRIRspPacket(aurp.RoutingFlagLast, nets)); err != nil { + p.Transport.LocalSeq = 1 + if _, err := p.Send(p.Transport.NewRIRspPacket(aurp.RoutingFlagLast, nets)); err != nil { log.Printf("Couldn't send RI-Rsp packet: %v", err) return err } @@ -280,7 +279,7 @@ func (p *peer) handle(ctx context.Context) error { log.Printf("Learned about these networks: %v", pkt.Networks) for _, nt := range pkt.Networks { - p.routingTable.UpsertRoute( + p.RoutingTable.UpsertRoute( nt.Extended, ddp.Network(nt.RangeStart), ddp.Network(nt.RangeEnd), @@ -291,7 +290,7 @@ func (p *peer) handle(ctx context.Context) error { // TODO: track which networks we don't have zone info for, and // only set SZI for those ? - if _, err := p.send(p.tr.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, aurp.RoutingFlagSendZoneInfo)); err != nil { + if _, err := p.Send(p.Transport.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, aurp.RoutingFlagSendZoneInfo)); err != nil { log.Printf("Couldn't send RI-Ack packet: %v", err) return err } @@ -324,11 +323,11 @@ func (p *peer) handle(ctx context.Context) error { if pkt.Flags&aurp.RoutingFlagSendZoneInfo != 0 { zones := aurp.ZoneTuples{ { - Network: uint16(p.cfg.EtherTalk.NetStart), - Name: p.cfg.EtherTalk.ZoneName, + Network: uint16(p.Config.EtherTalk.NetStart), + Name: p.Config.EtherTalk.ZoneName, }, } - if _, err := p.send(p.tr.NewZIRspPacket(zones)); err != nil { + if _, err := p.Send(p.Transport.NewZIRspPacket(zones)); err != nil { log.Printf("Couldn't send ZI-Rsp packet: %v", err) } } @@ -346,7 +345,7 @@ func (p *peer) handle(ctx context.Context) error { log.Printf("Router Down: error code %d %s", pkt.ErrorCode, pkt.ErrorCode) // Respond with RI-Ack - if _, err := p.send(p.tr.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, 0)); err != nil { + if _, err := p.Send(p.Transport.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, 0)); err != nil { log.Printf("Couldn't send RI-Ack: %v", err) return err } @@ -358,11 +357,11 @@ func (p *peer) handle(ctx context.Context) error { // ZI-Req zones := aurp.ZoneTuples{ { - Network: uint16(p.cfg.EtherTalk.NetStart), - Name: p.cfg.EtherTalk.ZoneName, + Network: uint16(p.Config.EtherTalk.NetStart), + Name: p.Config.EtherTalk.ZoneName, }, } - if _, err := p.send(p.tr.NewZIRspPacket(zones)); err != nil { + if _, err := p.Send(p.Transport.NewZIRspPacket(zones)); err != nil { log.Printf("Couldn't send ZI-Rsp packet: %v", err) return err } @@ -370,11 +369,11 @@ func (p *peer) handle(ctx context.Context) error { case *aurp.ZIRspPacket: log.Printf("Learned about these zones: %v", pkt.Zones) for _, zt := range pkt.Zones { - p.zoneTable.Upsert(ddp.Network(zt.Network), zt.Name, false) + p.ZoneTable.Upsert(ddp.Network(zt.Network), zt.Name, false) } case *aurp.GDZLReqPacket: - if _, err := p.send(p.tr.NewGDZLRspPacket(-1, nil)); err != nil { + if _, err := p.Send(p.Transport.NewGDZLRspPacket(-1, nil)); err != nil { log.Printf("Couldn't send GDZL-Rsp packet: %v", err) return err } @@ -383,7 +382,7 @@ func (p *peer) handle(ctx context.Context) error { log.Printf("Received a GDZL-Rsp, but I wouldn't have sent a GDZL-Req - that's weird") case *aurp.GZNReqPacket: - if _, err := p.send(p.tr.NewGZNRspPacket(pkt.ZoneName, false, nil)); err != nil { + if _, err := p.Send(p.Transport.NewGZNRspPacket(pkt.ZoneName, false, nil)); err != nil { log.Printf("Couldn't send GZN-Rsp packet: %v", err) return err } @@ -393,7 +392,7 @@ func (p *peer) handle(ctx context.Context) error { case *aurp.TicklePacket: // Immediately respond with Tickle-Ack - if _, err := p.send(p.tr.NewTickleAckPacket()); err != nil { + if _, err := p.Send(p.Transport.NewTickleAckPacket()); err != nil { log.Printf("Couldn't send Tickle-Ack: %v", err) return err } diff --git a/route.go b/router/route.go similarity index 70% rename from route.go rename to router/route.go index 369b682..e8218d1 100644 --- a/route.go +++ b/router/route.go @@ -1,4 +1,20 @@ -package main +/* + Copyright 2024 Josh Deprez + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package router import ( "fmt" @@ -14,7 +30,7 @@ type Route struct { Extended bool NetStart ddp.Network NetEnd ddp.Network - Peer *peer + Peer *Peer Distance uint8 LastSeen time.Time } @@ -56,7 +72,7 @@ func (rt *RoutingTable) LookupRoute(network ddp.Network) *Route { return bestRoute } -func (rt *RoutingTable) UpsertRoute(extended bool, netStart, netEnd ddp.Network, peer *peer, metric uint8) error { +func (rt *RoutingTable) UpsertRoute(extended bool, netStart, netEnd ddp.Network, peer *Peer, metric uint8) error { if netStart > netEnd { return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd) } diff --git a/router/router.go b/router/router.go new file mode 100644 index 0000000..3fe5515 --- /dev/null +++ b/router/router.go @@ -0,0 +1,32 @@ +/* + Copyright 2024 Josh Deprez + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package router + +import ( + "github.com/google/gopacket/pcap" + "github.com/sfiera/multitalk/pkg/ddp" + "github.com/sfiera/multitalk/pkg/ethernet" +) + +type Router struct { + Config *Config + PcapHandle *pcap.Handle + MyHWAddr ethernet.Addr + MyDDPAddr ddp.Addr + RouteTable *RoutingTable + ZoneTable *ZoneTable +} diff --git a/rtmp.go b/router/rtmp.go similarity index 91% rename from rtmp.go rename to router/rtmp.go index 86d8c66..38463e8 100644 --- a/rtmp.go +++ b/router/rtmp.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "context" @@ -33,17 +33,17 @@ import ( // RTMPMachine implements RTMP on an AppleTalk network attached to the router. type RTMPMachine struct { - aarp *AARPMachine - cfg *config - pcapHandle *pcap.Handle - routingTable *RoutingTable + AARP *AARPMachine + Config *Config + PcapHandle *pcap.Handle + RoutingTable *RoutingTable } // Run executes the machine. func (m *RTMPMachine) Run(ctx context.Context, incomingCh <-chan *ddp.ExtPacket) error { // Await local address assignment before doing anything - <-m.aarp.Assigned() - myAddr, ok := m.aarp.Address() + <-m.AARP.Assigned() + myAddr, ok := m.AARP.Address() if !ok { return fmt.Errorf("AARP machine closed Assigned channel but Address is not valid") } @@ -76,7 +76,7 @@ func (m *RTMPMachine) Run(ctx context.Context, incomingCh <-chan *ddp.ExtPacket) } // should be in the cache... - theirHWAddr, err := m.aarp.Resolve(ctx, ddp.Addr{Network: pkt.SrcNet, Node: pkt.SrcNode}) + theirHWAddr, err := m.AARP.Resolve(ctx, ddp.Addr{Network: pkt.SrcNet, Node: pkt.SrcNode}) if err != nil { log.Printf("RTMP: Couldn't resolve %d.%d to a hardware address: %v", pkt.SrcNet, pkt.SrcNode, err) continue @@ -88,8 +88,8 @@ func (m *RTMPMachine) Run(ctx context.Context, incomingCh <-chan *ddp.ExtPacket) respPkt := &rtmp.ResponsePacket{ SenderAddr: myAddr.Proto, Extended: true, - RangeStart: m.cfg.EtherTalk.NetStart, - RangeEnd: m.cfg.EtherTalk.NetEnd, + RangeStart: m.Config.EtherTalk.NetStart, + RangeEnd: m.Config.EtherTalk.NetEnd, } respPktRaw, err := respPkt.Marshal() if err != nil { @@ -170,7 +170,7 @@ func (m *RTMPMachine) send(src, dst ethernet.Addr, ddpPkt *ddp.ExtPacket) error if err != nil { return err } - return m.pcapHandle.WritePacketData(ethFrameRaw) + return m.PcapHandle.WritePacketData(ethFrameRaw) } func (m *RTMPMachine) broadcastData(myAddr aarp.AddrPair) error { @@ -209,13 +209,13 @@ func (m *RTMPMachine) dataPacket(myAddr ddp.Addr) *rtmp.DataPacket { // to that network." { Extended: true, - RangeStart: m.cfg.EtherTalk.NetStart, - RangeEnd: m.cfg.EtherTalk.NetEnd, + RangeStart: m.Config.EtherTalk.NetStart, + RangeEnd: m.Config.EtherTalk.NetEnd, Distance: 0, }, }, } - for _, rt := range m.routingTable.ValidRoutes() { + for _, rt := range m.RoutingTable.ValidRoutes() { p.NetworkTuples = append(p.NetworkTuples, rtmp.NetworkTuple{ Extended: rt.Extended, RangeStart: rt.NetStart, diff --git a/zip.go b/router/zip.go similarity index 86% rename from zip.go rename to router/zip.go index 9aa158f..d7b1904 100644 --- a/zip.go +++ b/router/zip.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "fmt" @@ -23,14 +23,12 @@ import ( "gitea.drjosh.dev/josh/jrouter/atalk" "gitea.drjosh.dev/josh/jrouter/atalk/atp" "gitea.drjosh.dev/josh/jrouter/atalk/zip" - "github.com/google/gopacket/pcap" - "github.com/sfiera/multitalk/pkg/aarp" "github.com/sfiera/multitalk/pkg/ddp" "github.com/sfiera/multitalk/pkg/ethernet" "github.com/sfiera/multitalk/pkg/ethertalk" ) -func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAddr aarp.AddrPair, cfg *config, zones *ZoneTable, ddpkt *ddp.ExtPacket) error { +func (rtr *Router) HandleZIP(srcHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) error { switch ddpkt.Proto { case ddp.ProtoATP: atpkt, err := atp.UnmarshalPacket(ddpkt.Data) @@ -54,13 +52,13 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd switch gzl.Function { case zip.FunctionGetZoneList: - resp.Zones = zones.AllNames() + resp.Zones = rtr.ZoneTable.AllNames() case zip.FunctionGetLocalZones: - resp.Zones = zones.LocalNames() + resp.Zones = rtr.ZoneTable.LocalNames() case zip.FunctionGetMyZone: - resp.Zones = []string{cfg.EtherTalk.ZoneName} + resp.Zones = []string{rtr.Config.EtherTalk.ZoneName} } // Inside AppleTalk SE, pp 8-8 @@ -101,14 +99,14 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd DstNet: ddpkt.SrcNet, DstNode: ddpkt.SrcNode, DstSocket: ddpkt.SrcSocket, - SrcNet: myAddr.Proto.Network, - SrcNode: myAddr.Proto.Node, + SrcNet: rtr.MyDDPAddr.Network, + SrcNode: rtr.MyDDPAddr.Node, SrcSocket: 6, Proto: ddp.ProtoATP, }, Data: ddpBody, } - outFrame, err := ethertalk.AppleTalk(myHWAddr, respDDP) + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, respDDP) if err != nil { return err } @@ -117,7 +115,7 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd if err != nil { return err } - return pcapHandle.WritePacketData(outFrameRaw) + return rtr.PcapHandle.WritePacketData(outFrameRaw) case *atp.TResp: return fmt.Errorf("TODO: support handling ZIP ATP replies?") @@ -135,7 +133,7 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd switch zipkt := zipkt.(type) { case *zip.QueryPacket: log.Printf("ZIP: Got Query for networks %v", zipkt.Networks) - networks := zones.Query(zipkt.Networks) + networks := rtr.ZoneTable.Query(zipkt.Networks) sendReply := func(resp *zip.ReplyPacket) error { respRaw, err := resp.Marshal() @@ -149,15 +147,15 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd DstNet: ddpkt.SrcNet, DstNode: ddpkt.SrcNode, DstSocket: ddpkt.SrcSocket, - SrcNet: myAddr.Proto.Network, - SrcNode: myAddr.Proto.Node, + SrcNet: rtr.MyDDPAddr.Network, + SrcNode: rtr.MyDDPAddr.Node, SrcSocket: 6, Proto: ddp.ProtoZIP, }, Data: respRaw, } - outFrame, err := ethertalk.AppleTalk(myHWAddr, outDDP) + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, outDDP) if err != nil { return fmt.Errorf("couldn't create EtherTalk frame: %w", err) } @@ -167,7 +165,7 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd if err != nil { return fmt.Errorf("couldn't marshal EtherTalk frame: %w", err) } - if err := pcapHandle.WritePacketData(outFrameRaw); err != nil { + if err := rtr.PcapHandle.WritePacketData(outFrameRaw); err != nil { return fmt.Errorf("couldn't write packet data: %w", err) } return nil @@ -246,14 +244,14 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd // Only running a network with one zone for now. resp := &zip.GetNetInfoReplyPacket{ - ZoneInvalid: zipkt.ZoneName != cfg.EtherTalk.ZoneName, + ZoneInvalid: zipkt.ZoneName != rtr.Config.EtherTalk.ZoneName, UseBroadcast: false, OnlyOneZone: true, - NetStart: cfg.EtherTalk.NetStart, - NetEnd: cfg.EtherTalk.NetEnd, + NetStart: rtr.Config.EtherTalk.NetStart, + NetEnd: rtr.Config.EtherTalk.NetEnd, ZoneName: zipkt.ZoneName, // has to match request - MulticastAddr: atalk.MulticastAddr(cfg.EtherTalk.ZoneName), - DefaultZoneName: cfg.EtherTalk.ZoneName, + MulticastAddr: atalk.MulticastAddr(rtr.Config.EtherTalk.ZoneName), + DefaultZoneName: rtr.Config.EtherTalk.ZoneName, } log.Printf("ZIP: Replying with GetNetInfo-Reply: %+v", resp) @@ -277,8 +275,8 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd DstNet: ddpkt.SrcNet, DstNode: ddpkt.SrcNode, DstSocket: ddpkt.SrcSocket, - SrcNet: myAddr.Proto.Network, - SrcNode: myAddr.Proto.Node, + SrcNet: rtr.MyDDPAddr.Network, + SrcNode: rtr.MyDDPAddr.Node, SrcSocket: 6, Proto: ddp.ProtoZIP, }, @@ -291,7 +289,7 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd outDDP.DstNode = 0xFF } - outFrame, err := ethertalk.AppleTalk(myHWAddr, outDDP) + outFrame, err := ethertalk.AppleTalk(rtr.MyHWAddr, outDDP) if err != nil { return fmt.Errorf("couldn't create EtherTalk frame: %w", err) } @@ -303,7 +301,7 @@ func handleZIP(pcapHandle *pcap.Handle, srcHWAddr, myHWAddr ethernet.Addr, myAdd if err != nil { return fmt.Errorf("couldn't marshal EtherTalk frame: %w", err) } - if err := pcapHandle.WritePacketData(outFrameRaw); err != nil { + if err := rtr.PcapHandle.WritePacketData(outFrameRaw); err != nil { return fmt.Errorf("couldn't write packet data: %w", err) } return nil diff --git a/zones.go b/router/zones.go similarity index 99% rename from zones.go rename to router/zones.go index 24752b9..c7e4a2b 100644 --- a/zones.go +++ b/router/zones.go @@ -14,7 +14,7 @@ limitations under the License. */ -package main +package router import ( "slices"