diff --git a/CRAPRNIAC Protocol.md b/CRAPRNIAC Protocol.md index e23ba69..212395c 100644 --- a/CRAPRNIAC Protocol.md +++ b/CRAPRNIAC Protocol.md @@ -1,4 +1,4 @@ -# CRAPRNIAC: Completely Ridiculous Amateur Protocol for Radio Node IP Auto-Configuration +# CRAPRNIAC: Completely Ridiculous Amateur Protocol for Radio Node IP Address Configuration ## Status of this Memo @@ -8,10 +8,9 @@ This document describes version 0.1a of CRAPRNIAC, a protocol designed to facili Existing service discovery and dynamic host configuration protocols for TCP/IP networks are not ideal for bandwidth-constrained, high-latency, and lossy VHF packet radio environments. CRAPRNIAC addresses this by defining a join-and-configure protocol between a "base station" and one or more "client stations" that aims to cut the chatter. -The goal is to: -- Minimize the number of packet exchanges required for a client to join a VHF packet network. -- Allow manual or automatic IP configuration with a minimum of overhead. -- Bring honor to you and your house. +The goals are to: +- Let a client discover a nearby base station, request an IP address, and join a packet network. +- Bring honor to you and your house? ## 2. Protocol Overview @@ -26,6 +25,8 @@ CRAPRNIAC defines four primary message types: Messages are transmitted as plain ASCII text using simple pipe-separated (`|`) fields, allowing easy parsing by humans and computers alike. +The protocol is versioned and extensible to allow for a future in which this is relevant enough for there to be concern over compatibility. + ## 3. Message Format Each CRAPRNIAC message is a single text string with the following general format: @@ -93,26 +94,26 @@ Fields: ## 6. Design Considerations -- **Minimal Airtime Usage:** Critical for low-bandwidth links. -- **Human-Readable:** Easy troubleshooting with a dumb terminal. -- **Flexibility:** Can extend in future versions with additional fields. -- **Backward Compatibility:** Protocol version prefix allows for graceful upgrades. +- Make it, despite its name, not crappy ## 7. Security Considerations -The S in CRAPRNIAC stands for Security! +That's what the 'S' in CRAPRNIAC stands for. ## 8. Other Considerations -CRAPRNIAC will squat on whatever amateur frequencies operators choose. +- CRAPRNIAC does not prescribe a particular lower-layer protocol, though it is designed with a working AX.25 stack in mind, whether that's a classic serial TNC, a more modern bluetooth doodad, or Direwolf with kissattach creating an ax0 interface. The example implementation uses UDP packets over IP over AX.25. +- CRAPRNIAC will squat on an amateur frequency of the operator's choice. ## 9. Conclusion -CRAPRNIAC provides a starting point for connecting TCP/IP stacks over slow amateur radio links. By limiting the number and length of transmissions required for negotiation, it offers networking over VHF that works like it smells. +CRAPRNIAC provides a starting point for connecting TCP/IP stacks over slow amateur radio links. By limiting the number and length of transmissions required for negotiation, it offers networking over VHF that works as nice as it smells. ## 10. Further Development -Future enhancements may include optional mesh extensions self-organizing slowness. +- Future enhancements may include optional mesh extensions for self-organizing slowness. +- A TLV protocol would be more compact. But why make it more efficient when the transmissions are literally slow enough to read with your eyes? + --- diff --git a/base_station/server.py b/base_station/server.py index 87d9e15..f73a1d2 100644 --- a/base_station/server.py +++ b/base_station/server.py @@ -2,13 +2,11 @@ import socket import time import threading -BROADCAST_IP = "127.0.0.1" -PORT = 4444 - -BEACON_INTERVAL = 10 # seconds BASE_CALLSIGN = "KI5QKX-10" NETWORK_NAME = "HAMNET-HOUSTON" +BEACON_INTERVAL = 10 # seconds + # Fake IP pool IP_POOL = [ "44.127.254.12", @@ -71,14 +69,14 @@ def handle_request(data, addr, sock): def beacon_loop(sock): while True: beacon = build_beacon().encode('utf-8') - sock.sendto(beacon, (BROADCAST_IP, PORT)) + # Beacon to *broadcast* — here we'll just send to our own callsign for now + sock.sendto(beacon, ('CRAPR-0',)) print(f"Sent beacon: {beacon.decode('utf-8')}") time.sleep(BEACON_INTERVAL) def main(): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - # sock.bind((BROADCAST_IP, PORT)) + sock = socket.socket(socket.AF_AX25, socket.SOCK_DGRAM) + sock.bind((BASE_CALLSIGN,)) # Bind to our station callsign print(f"Base Station {BASE_CALLSIGN} starting up on {NETWORK_NAME}...") diff --git a/client_node/client.py b/client_node/client.py index 6031f6a..6295528 100644 --- a/client_node/client.py +++ b/client_node/client.py @@ -1,9 +1,6 @@ import socket import time -LISTEN_IP = "0.0.0.0" -PORT = 4444 - CLIENT_CALLSIGN = "N0CALL-7" configured = False @@ -33,9 +30,8 @@ def apply_network_config(assigned_ip, gateway, dns, lease_time): def main(): global configured, lease_expiration - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((LISTEN_IP, PORT)) + sock = socket.socket(socket.AF_AX25, socket.SOCK_DGRAM) + sock.bind((CLIENT_CALLSIGN,)) # Bind to our own callsign print(f"Client {CLIENT_CALLSIGN} listening for CRAPRNIAC beacons...") @@ -64,7 +60,7 @@ def main(): print(f" Network: {network_name}") print("Sending join request...") request = build_request(network_name).encode('utf-8') - sock.sendto(request, addr) + sock.sendto(request, (base_callsign,)) elif parts[1] == "CRAP_ACCEPT": client_callsign = parts[2]