OPEN SOURCE · 2026 · MIT LICENSE
appletalk/
An AppleTalk protocol stack in Rust that puts vintage Macs, emulators, and modern Linux machines on the same network — and routes them onto GlobalTalk, the hobbyist AppleTalk internet.
- lang
- Rust 2024
- links
- EtherTalk · LocalTalk · LToUDP
- protocols
- DDP · AARP · RTMP · ZIP · NBP · ATP · AEP · AURP
- size
- 14.4k lines · 329 tests
- runs on
- Linux (raw sockets)
- license
- MIT
## why
AppleTalk is the networking stack that shipped with every Mac from 1985 into the 2000s. A surprising amount of it is still in use: collectors run vintage Macs, Mini vMac and Snow emulate them, and GlobalTalk stitches hobbyists' networks into one AppleTalk internet over UDP tunnels.
This project speaks all of it from a Linux box. It can watch a network and decode what it hears, join the network as a node and ask it questions, bridge emulated Macs onto a real LocalTalk or EtherTalk segment, and act as a full router with AURP tunnels to other networks. Every packet layout was checked against Inside AppleTalk, 2nd edition.
## design
- Parsers fail closed. Each protocol lives in its own file under
src/wire/as a pure parser with no I/O. If a parser doesn't fully recognize a packet it returns nothing and the packet is shown as a hex dump, because a wrong decode is worse than no decode. - The router is a pure function. Its core is
step(input, now) -> Vec<Action>: routing and zone tables, route aging, and split horizon are all tested without a network, a clock, or a thread. - The bridge translates, it doesn't just repeat. It answers address-resolution requests on behalf of LocalTalk nodes, answers LocalTalk's node-ID probes on behalf of Ethernet nodes, and rewrites short DDP headers into extended form, so the two link types look like one network.
- Untrusted peers can't exhaust memory. Open AURP peering is capped at 256 entries and idle strangers are evicted after 90 seconds: a stranger's packet must not buy permanent memory.
## try it
$ appletalk zones
68k Mac Club *
$ appletalk nodes
Mini:AFPServer@* at 6800.150:249
raspberrypi:AFPServer@* at 6800.3:128
$ appletalk ping -c 2 6800.3
8 bytes from 6800.3: seq=0 time=1.42 ms
8 bytes from 6800.3: seq=1 time=0.98 ms
## how it was built
I developed it with Claude Code, working from written specs and implementation plans that live in the repo. Tests build packets from byte literals and check both the parsed fields and the human-readable output.
The router is tested end to end on real hardware: a LocalTalk Mac behind a TashTalk board took an address from the router, listed every GlobalTalk zone in the Chooser, and mounted a file share from a remote network across an AURP tunnel.