This commit is contained in:
Laan Tungir
2026-08-13 05:42:08 -04:00
parent 9f7145b65c
commit faf6d5afc3
2 changed files with 14 additions and 55 deletions
+1 -49
View File
@@ -1,6 +1,6 @@
# UDP Nostr
Send a Nostr event as a single UDP datagram — no handshake, no connection, no state. The most unstoppable way to post content ever invented.
Send a Nostr event as a single UDP datagram — no handshake, no connection, no state. The most unstoppable way to post content ever invented?
---
@@ -223,51 +223,3 @@ With DF set, the kernel checks the path MTU before sending. If the packet is lar
### What the Receiver Can Know
The receiver **cannot** directly observe IP-level fragmentation. The OS reassembles fragments before delivering to `recvfrom()`. The receiver only sees the complete reassembled datagram. The size check is a heuristic — if the datagram is ≤ 1472 bytes, it *could* have been sent as one packet, but the receiver cannot prove it.
### The Asymmetry
| Role | Can they know? | How? |
|------|---------------|------|
| **Sender** | **Yes, definitively** | DF flag → `EMSGSIZE` if fragmentation needed |
| **Receiver** | **No, not definitively** | OS hides fragmentation; can only check size |
| **Adversary (on-path)** | **Yes** | Can observe IP fragments directly |
| **Adversary (off-path)** | **No** | Cannot see the packet at all |
The sender is the only party that can **enforce** single-packet delivery. The receiver can only **infer** it. This is why the DF flag is critical — it moves the guarantee from "probably" to "provably."
### What About the OS?
- **Linux**: `IP_MTU_DISCOVER` with `IP_PMTUDISC_DO` sets DF and performs path MTU discovery
- **macOS/BSD**: `IP_DONTFRAG` socket option (different constant, same effect)
- **Windows**: `setsockopt` with `IP_DONTFRAGMENT` (requires WinSock)
## Related Documents
### Design & analysis — [`docs/`](docs/)
| Document | Description |
|---|---|
| [`docs/protocol_hardening.md`](docs/protocol_hardening.md) | The core idea: design protocols so interference requires violating physics or OS guarantees. Explains the MTU boundary, substrate constraints, and the adversary's dilemma. |
| [`docs/mtu_exploration.md`](docs/mtu_exploration.md) | Survey of 10 projects/people who have worked on MTU exploitation for censorship resistance: QUIC, CurveCP (djb), obfs4 (Tor), DNS tunneling, uTP (BitTorrent), WireGuard, CoAP/DTLS, binary events, IP fragmentation, tcpcrypt. |
| [`docs/no_handshake.md`](docs/no_handshake.md) | Analysis of the no-handshake property: why Nostr's self-validating events are fundamentally different from every protocol that announces itself with a handshake pattern. |
| [`docs/binary_events.md`](docs/binary_events.md) | The `.bne` binary event format: byte layout, encoding, and size savings vs JSON. |
| [`docs/max_single_packet_event.md`](docs/max_single_packet_event.md) | Maximum single-packet event sizing and the full `.bne` byte layout. |
| [`docs/passive_sniffing_relay.md`](docs/passive_sniffing_relay.md) | Plausible-deniability relay models: passive sniffing and authoritative-DNS reception. |
| [`docs/TCP_vs_UDP.md`](docs/TCP_vs_UDP.md) | TCP vs UDP comparison in the context of censorship resistance. |
| [`docs/udp_nostr_relay_plan.md`](docs/udp_nostr_relay_plan.md) | Design plan for a UDP Nostr relay. |
### Programs — [`src/`](src/)
| File | Description |
|---|---|
| [`src/udp_nostr_send.py`](src/udp_nostr_send.py) | Sender: reads signed event JSON from stdin (pipe from `nak`), sends as single UDP datagram. |
| [`src/udp_nostr_recv.py`](src/udp_nostr_recv.py) | Receiver: listens for UDP datagrams, prints the JSON. |
| [`src/udp_nostr_send.js`](src/udp_nostr_send.js) | Sender (JavaScript/Node.js): same logic using the built-in `dgram` module. |
| [`src/udp_nostr_recv.js`](src/udp_nostr_recv.js) | Receiver (JavaScript/Node.js): same logic using the built-in `dgram` module. |
| [`src/test_local.sh`](src/test_local.sh) | Local loopback test script. |
### Plans — [`plans/`](plans/)
| Document | Description |
|---|---|
| [`plans/udp_nostr_fips_discovery.md`](plans/udp_nostr_fips_discovery.md) | Plan: combine UDP Nostr with FIPS Nostr-mediated endpoint discovery (relay mobility without a data-plane handshake). |
+13 -6
View File
@@ -7,26 +7,26 @@ nak event -k 1 -c "I don't shake hands, because Ewwwwww!" | nc -u -w1 laantungir
'''
## The problem:
https://blossom.laantungir.net/b63479f895a207fccfbac9323ac7a4bd47cbc20e43ebfcd60f3c54e41bfb1d1d.jpg
As far as I know, every circumvention tool [VPN, Tor, Shadowsocks, obfs4] has a handshake. You start off messaging the server, and the server replies before you can send your information. National firewalls detect those handshakes, fingerprint them, probe the handshake, then block the IP or take other action. The handshake is a vulnerability. Every tool plays cat-and-mouse obfuscating it.
For example Tor bridges are vulnerable to active probing. The adversary connects to a suspected bridge and sends data. If the server responds with a valid obfs4 handshake, the adversary knows it is a bridge. This is how China blocks many Tor bridges.
https://blossom.laantungir.net/b63479f895a207fccfbac9323ac7a4bd47cbc20e43ebfcd60f3c54e41bfb1d1d.jpg
For example Tor bridges are vulnerable to active probing. The adversary connects to a suspected bridge and sends data. If the server responds with a valid obfs4 handshake, the adversary knows it is a bridge. This is how many Tor bridges get blocked.
## The idea:
UDP Nostr eliminates the handshake entirely. The Nostr event is already signed before it touches the network. The signature replaces the handshake. There is no SYN, no TLS ClientHello, no SNI, no key exchange, no recognizable structure — just a blob of bytes in one UDP packet under 1472 bytes.
The adversary can send a probe, but the relay doesn't respond at all. No handshake to detect. No TCP RST to inject (UDP has no RST). No DNS to poison (send to the IP directly).
The adversary can send a probe, but the relay doesn't respond at all. No handshake to detect. No TCP RST to inject (UDP has no RST). No DNS to poison.
## Live example — full zero-config round-trip
My relay runs my c-nostr-pg project and has fully implemented UDP Nostr.
My relay has fully implemented UDP Nostr.
https://blossom.laantungir.net/5b1c5fc4ddf89b4aec123c7a2a5934e9a22c3271fa641b071cc8f7740a342bbd.png
**command line**
```bash
# Console 1 - Set up a live watch for the nak default events on the relay
nak req -a 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 --stream laantungir.net/relay
@@ -72,3 +72,10 @@ With the default nak key, empty tags, and a 10-digit timestamp, the Nostr JSON o
## Future work
I'm currently working on an encryption scheme specifically for this protocol.
https://15.235.3.231/git/laantungir/udp_nostr
https://laantungir.net/git/laantungir/udp_nostr
https://[2607:5300:203:bb5c:4a46:c3d3:1dc3:fbe8]/git/laantungir/udp_nostr
http://kn2jam4kyz6s5wacyozo3do3d2zsvh4to45uh7xliulwdust6zjuvnad.onion/git/laantungir/udp_nostr
http://npub1crpldvy49ef8z34wlacwujnfudy4nd7k96aqdx5wgn6ckztz7z8q9t59ud.fips/git/laantungir/udp_nostr