Updates to take out UDP and do this at the AX.25 level

This commit is contained in:
John Burwell 2025-04-26 23:27:28 -05:00
parent 258b59198a
commit 738ea6e75e
3 changed files with 23 additions and 28 deletions

View File

@ -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?
---

View File

@ -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}...")

View File

@ -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]