@dp-pcs/ogp 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -12
- package/dist/cli/config.d.ts +4 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +45 -2
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/expose.d.ts +4 -1
- package/dist/cli/expose.d.ts.map +1 -1
- package/dist/cli/expose.js +7 -106
- package/dist/cli/expose.js.map +1 -1
- package/dist/cli/install.d.ts +1 -0
- package/dist/cli/install.d.ts.map +1 -1
- package/dist/cli/install.js +8 -2
- package/dist/cli/install.js.map +1 -1
- package/dist/cli/project.d.ts +24 -0
- package/dist/cli/project.d.ts.map +1 -1
- package/dist/cli/project.js +68 -15
- package/dist/cli/project.js.map +1 -1
- package/dist/cli/tunnel.d.ts +65 -0
- package/dist/cli/tunnel.d.ts.map +1 -0
- package/dist/cli/tunnel.js +413 -0
- package/dist/cli/tunnel.js.map +1 -0
- package/dist/cli.js +21 -8
- package/dist/cli.js.map +1 -1
- package/dist/daemon/contribution-signing.d.ts +49 -0
- package/dist/daemon/contribution-signing.d.ts.map +1 -0
- package/dist/daemon/contribution-signing.js +91 -0
- package/dist/daemon/contribution-signing.js.map +1 -0
- package/dist/daemon/message-handler.js +41 -18
- package/dist/daemon/message-handler.js.map +1 -1
- package/dist/daemon/openclaw-bridge.d.ts +6 -0
- package/dist/daemon/openclaw-bridge.d.ts.map +1 -1
- package/dist/daemon/openclaw-bridge.js +27 -12
- package/dist/daemon/openclaw-bridge.js.map +1 -1
- package/dist/daemon/peers.d.ts.map +1 -1
- package/dist/daemon/peers.js +19 -0
- package/dist/daemon/peers.js.map +1 -1
- package/dist/daemon/projects.d.ts +20 -0
- package/dist/daemon/projects.d.ts.map +1 -1
- package/dist/daemon/projects.js +70 -0
- package/dist/daemon/projects.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +43 -2
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/state-lock.d.ts +23 -0
- package/dist/daemon/state-lock.d.ts.map +1 -0
- package/dist/daemon/state-lock.js +115 -0
- package/dist/daemon/state-lock.js.map +1 -0
- package/package.json +13 -3
- package/scripts/completion.bash +25 -6
- package/scripts/completion.zsh +26 -8
- package/skills/ogp-expose/SKILL.md +40 -10
- package/docs/RC1-FEDERATION-TEST-CHECKLIST.md +0 -477
- package/docs/case-studies/CRASH_RESOLUTION_20260407.md +0 -190
- package/docs/case-studies/OpenClaw_Hermes_Status_Report_20260407.md +0 -142
- package/docs/case-studies/OpenClaw_Stability_Fix_Summary.md +0 -209
- package/docs/case-studies/README.md +0 -40
- package/docs/case-studies/crash_observations.md +0 -250
- package/docs/nat-hole-punch-spike.md +0 -399
- package/docs/project-intent-testing.md +0 -97
- package/scripts/render-ogp-overview-video.mjs +0 -454
- package/scripts/test-migration-execute.js +0 -74
- package/scripts/test-migration.js +0 -42
- package/scripts/test-project-intents.mjs +0 -614
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
# NAT Hole Punching Research Spike for OGP
|
|
2
|
-
|
|
3
|
-
**Date:** 2026-03-30
|
|
4
|
-
**Status:** Research Complete — No Implementation
|
|
5
|
-
**Goal:** Evaluate UDP NAT hole punching to enable home users behind NAT to federate without port forwarding or tunnels
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 🎯 Recommendation: DEFER Implementation
|
|
10
|
-
|
|
11
|
-
**Do NOT implement UDP hole punching for OGP at this time.**
|
|
12
|
-
|
|
13
|
-
### Rationale
|
|
14
|
-
|
|
15
|
-
1. **HTTP fallback already works** — OGP's rendezvous server + HTTP messaging provides zero-config federation for 95%+ of residential users via UPnP, public IP detection, and tunnel services (ngrok/Cloudflare)
|
|
16
|
-
|
|
17
|
-
2. **Symmetric NAT is a deal-breaker** — UDP hole punching fails for ~15% of residential users behind symmetric NAT, requiring a TURN relay server (expensive, complex, defeats the purpose of P2P)
|
|
18
|
-
|
|
19
|
-
3. **High implementation complexity** — Adding UDP transport is a major undertaking (S → L complexity) with marginal benefit over existing HTTP solution
|
|
20
|
-
|
|
21
|
-
4. **TCP already traverses NAT** — HTTP over TCP is already NAT-friendly and works behind most residential routers without special handling
|
|
22
|
-
|
|
23
|
-
5. **No clear user pain point** — Users aren't blocked by the current HTTP approach; they use rendezvous server or tunnels successfully
|
|
24
|
-
|
|
25
|
-
### If User Demand Changes
|
|
26
|
-
|
|
27
|
-
If home users report widespread federation issues due to NAT (not currently the case), revisit this decision. Priority order:
|
|
28
|
-
|
|
29
|
-
1. **Improve HTTP rendezvous** — Add TURN-style relay for HTTP (simpler than UDP hole punching)
|
|
30
|
-
2. **Integrate tunnel services** — Embed ngrok/Cloudflare SDK for automatic tunnel setup
|
|
31
|
-
3. **UDP hole punching** — Only if HTTP solutions prove insufficient (unlikely)
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## 📊 Library Comparison
|
|
36
|
-
|
|
37
|
-
### Evaluated Node.js STUN/UDP Libraries
|
|
38
|
-
|
|
39
|
-
| Library | Version | Last Updated | Weekly DLs | TS Support | License | Status | Verdict |
|
|
40
|
-
|---------|---------|--------------|------------|------------|---------|--------|---------|
|
|
41
|
-
| **stun** (nodertc) | 2.1.0 | 6 years ago | Low | ❌ No | MIT | Unmaintained | ❌ Too old |
|
|
42
|
-
| **node-stun** | 0.1.2 | 8 years ago | Minimal | ❌ No | Unknown | Abandoned | ❌ Abandoned |
|
|
43
|
-
| **werift** | 0.22.2 | 6 months ago | 29 dependents | ✅ Yes | MIT | Active | ⚠️ Overkill (full WebRTC) |
|
|
44
|
-
| **udp-hole-puncher** | 1.1.0 | 9 months ago | None | ❌ No | MIT | Stale | ❌ No adoption |
|
|
45
|
-
| **xkore** | 1.0.1 | 2 months ago | 1 dependent | Unknown | ISC | New/unproven | ⚠️ Too new |
|
|
46
|
-
| **nat-traversal** | Latest | Unknown | Low | ❌ No | Unknown | Active | ⚠️ TCP relay (not UDP hole punch) |
|
|
47
|
-
|
|
48
|
-
### Analysis
|
|
49
|
-
|
|
50
|
-
**No clear winner.** The ecosystem is fragmented:
|
|
51
|
-
|
|
52
|
-
- **Old libraries** (stun, node-stun) are unmaintained and lack TypeScript
|
|
53
|
-
- **New libraries** (xkore) are unproven with zero adoption
|
|
54
|
-
- **WebRTC stacks** (werift) include hole punching but bring massive complexity (ICE, DTLS, SRTP, SDP negotiation) — massive overkill for simple peer-to-peer messaging
|
|
55
|
-
- **Purpose-built hole punchers** (udp-hole-puncher) have zero community adoption
|
|
56
|
-
|
|
57
|
-
**Best option if forced to implement:** Use the **nodertc/stun** library for basic STUN client functionality and implement custom UDP hole punching logic (no library does it well). This is 80% of the work anyway.
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## 🏗️ OGP Architecture Analysis
|
|
62
|
-
|
|
63
|
-
### Current HTTP Architecture
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
67
|
-
│ OGP Daemon (src/daemon/server.ts) │
|
|
68
|
-
│ - Express HTTP server on port 18790 │
|
|
69
|
-
│ - Endpoints: /federation/request, /federation/message, etc. │
|
|
70
|
-
│ - Rendezvous registration (POST /register every 30s) │
|
|
71
|
-
│ - Peer lookup (GET /peer/:pubkey) │
|
|
72
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
73
|
-
▲
|
|
74
|
-
│ HTTP/JSON + RSA signatures
|
|
75
|
-
▼
|
|
76
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
77
|
-
│ Rendezvous Server (rendezvous.elelem.expert) │
|
|
78
|
-
│ - HTTPS server (Express on port 3000 default) │
|
|
79
|
-
│ - Stores: { pubkey, ip, port, timestamp } with 90s TTL │
|
|
80
|
-
│ - Never touches message content (privacy preserved) │
|
|
81
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Key observation:** OGP daemon is a single-port HTTP server. It does NOT have:
|
|
85
|
-
- UDP socket handling
|
|
86
|
-
- STUN client/server logic
|
|
87
|
-
- ICE candidate gathering
|
|
88
|
-
- Hole punching coordination
|
|
89
|
-
|
|
90
|
-
### Integration Points (If Implemented)
|
|
91
|
-
|
|
92
|
-
To add UDP hole punching WITHOUT breaking HTTP:
|
|
93
|
-
|
|
94
|
-
1. **Dual transport layer** — Run HTTP server (18790) AND UDP socket (18791) concurrently
|
|
95
|
-
2. **Rendezvous server changes** — Add STUN endpoint on UDP port, store both TCP port (18790) and UDP port (18791) per peer
|
|
96
|
-
3. **Connection attempt sequence** — Try UDP hole punch first, fall back to HTTP if fails (timeout after 3-5s)
|
|
97
|
-
4. **Protocol negotiation** — Peers must agree which transport to use via rendezvous server
|
|
98
|
-
|
|
99
|
-
**Critical constraint:** Cannot break existing HTTP federation (v0.2.0 protocol). UDP must be additive, not replacement.
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 🔬 NAT Traversal Feasibility
|
|
104
|
-
|
|
105
|
-
### NAT Type Distribution (Estimated)
|
|
106
|
-
|
|
107
|
-
| NAT Type | % of Residential ISPs | UDP Hole Punch Success Rate | Notes |
|
|
108
|
-
|----------|----------------------|---------------------------|-------|
|
|
109
|
-
| Full Cone | ~5-10% | >95% | Rare in modern routers |
|
|
110
|
-
| Restricted Cone | ~40-50% | >95% | Most common, hole punching works |
|
|
111
|
-
| Port-Restricted Cone | ~25-35% | ~80% | Common, mostly works |
|
|
112
|
-
| Symmetric NAT | ~10-15% | <10% | **Requires TURN relay** |
|
|
113
|
-
|
|
114
|
-
**Sources:**
|
|
115
|
-
- [Academic research (IEEE)](https://ieeexplore.ieee.org/document/7021753/)
|
|
116
|
-
- [NAT usage studies (Springer)](https://link.springer.com/chapter/10.1007/978-3-642-19260-9_4)
|
|
117
|
-
- [Tailscale's NAT traversal analysis](https://tailscale.com/blog/how-nat-traversal-works)
|
|
118
|
-
|
|
119
|
-
**Key finding:** UDP hole punching succeeds for ~82-85% of peers in cone NAT scenarios. The remaining ~15% (symmetric NAT) require a TURN relay server.
|
|
120
|
-
|
|
121
|
-
### TURN Relay Server Requirements
|
|
122
|
-
|
|
123
|
-
For symmetric NAT, peers cannot establish direct UDP connections. A TURN relay server is required:
|
|
124
|
-
|
|
125
|
-
- **Server:** [Coturn](https://github.com/coturn/coturn) (most popular open-source TURN server)
|
|
126
|
-
- **Hosting cost:** $20-50/month for small deployments (bandwidth-heavy)
|
|
127
|
-
- **Implementation effort:** Medium (2-3 weeks for integration + testing)
|
|
128
|
-
- **User experience:** Degrades to relay (higher latency, costs money)
|
|
129
|
-
|
|
130
|
-
**This defeats the purpose of P2P.** If we're relaying 15% of traffic, why not just use HTTP for everyone?
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 📋 Proposed Protocol Flow (If Implemented)
|
|
135
|
-
|
|
136
|
-
**NOTE:** This is theoretical. Do NOT implement without re-evaluating user need.
|
|
137
|
-
|
|
138
|
-
### Step 1: Rendezvous Registration (Startup)
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
OGP Daemon A Rendezvous Server
|
|
142
|
-
│ │
|
|
143
|
-
├─ POST /register ──────────────▶ Store:
|
|
144
|
-
│ { │ - pubkey: "abc123..."
|
|
145
|
-
│ pubkey: "abc123...", │ - tcp_ip: "1.2.3.4"
|
|
146
|
-
│ tcp_port: 18790, │ - tcp_port: 18790
|
|
147
|
-
│ udp_port: 18791, │ - udp_ip: "1.2.3.4"
|
|
148
|
-
│ timestamp: 1234567890 │ - udp_port: 18791
|
|
149
|
-
│ } │ - timestamp: 1234567890
|
|
150
|
-
│◀─ 200 OK ─────────────────────┤ TTL: 90 seconds
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Step 2: STUN Binding Request (Detect Public IP/Port)
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
OGP Daemon A STUN Server (on rendezvous.elelem.expert:3478 UDP)
|
|
157
|
-
│ │
|
|
158
|
-
├─ STUN Binding Request ────────▶
|
|
159
|
-
│ (from local UDP port 18791) │
|
|
160
|
-
│ │
|
|
161
|
-
│◀─ STUN Binding Response ──────┤
|
|
162
|
-
│ { │
|
|
163
|
-
│ public_ip: "1.2.3.4", │
|
|
164
|
-
│ public_port: 54321 │ <-- NAT assigned external port
|
|
165
|
-
│ } │
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Step 3: Peer Connection Attempt
|
|
169
|
-
|
|
170
|
-
```
|
|
171
|
-
OGP Daemon A Rendezvous Server OGP Daemon B
|
|
172
|
-
│ │ │
|
|
173
|
-
├─ GET /peer/xyz789... ─────────▶ │
|
|
174
|
-
│◀─ 200 OK ───────────────────┤ │
|
|
175
|
-
│ { │ │
|
|
176
|
-
│ tcp_ip: "5.6.7.8", │ │
|
|
177
|
-
│ tcp_port: 18790, │ │
|
|
178
|
-
│ udp_ip: "5.6.7.8", │ │
|
|
179
|
-
│ udp_port: 65432 │ │
|
|
180
|
-
│ } │ │
|
|
181
|
-
│ │ │
|
|
182
|
-
├─ Try UDP hole punch ───────────────────────────────────────▶
|
|
183
|
-
│ (both send UDP packets simultaneously) │
|
|
184
|
-
│ │ │
|
|
185
|
-
│◀─ UDP connection established (if cone NAT) ─────────────────┤
|
|
186
|
-
│ │ │
|
|
187
|
-
│ OR (if symmetric NAT) │ │
|
|
188
|
-
│ │ │
|
|
189
|
-
├─ Fall back to HTTP ────────────────────────────────────────▶
|
|
190
|
-
│ POST /federation/message │ │
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Step 4: Fallback Relay (Symmetric NAT)
|
|
194
|
-
|
|
195
|
-
```
|
|
196
|
-
OGP Daemon A TURN Relay Server OGP Daemon B
|
|
197
|
-
│ │ │
|
|
198
|
-
├─ Allocate relay ──────────────▶ │
|
|
199
|
-
│◀─ Relay address ───────────────┤ │
|
|
200
|
-
│ (relay_ip: 9.10.11.12:4000) │ │
|
|
201
|
-
│ │ │
|
|
202
|
-
├─ Send to relay ───────────────▶ │
|
|
203
|
-
│ ├─ Forward to B ───────────────▶
|
|
204
|
-
│ │ │
|
|
205
|
-
│◀─ Response from B ─────────────┤◀─ Send via relay ───────────┤
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
**Latency impact:**
|
|
209
|
-
- Direct UDP: ~10-50ms
|
|
210
|
-
- HTTP over TCP: ~20-100ms
|
|
211
|
-
- TURN relay: ~50-200ms (double hop)
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## 🚧 Implementation Complexity
|
|
216
|
-
|
|
217
|
-
### Estimated Effort: **LARGE (L)**
|
|
218
|
-
|
|
219
|
-
**Components to implement:**
|
|
220
|
-
|
|
221
|
-
1. **STUN client** (1-2 weeks)
|
|
222
|
-
- Bind to UDP socket (18791)
|
|
223
|
-
- Send STUN Binding Request to discover public IP/port
|
|
224
|
-
- Parse STUN Binding Response (RFC 5389 / RFC 8489)
|
|
225
|
-
- Handle retries and timeouts
|
|
226
|
-
|
|
227
|
-
2. **UDP hole punching logic** (2-3 weeks)
|
|
228
|
-
- Coordinate simultaneous send between peers (timing is critical)
|
|
229
|
-
- NAT type detection (symmetric vs cone)
|
|
230
|
-
- Connection attempt timeout and fallback
|
|
231
|
-
|
|
232
|
-
3. **Rendezvous server updates** (1 week)
|
|
233
|
-
- Add STUN endpoint on UDP port 3478
|
|
234
|
-
- Store UDP port alongside TCP port in peer registry
|
|
235
|
-
- Handle dual-transport lookups
|
|
236
|
-
|
|
237
|
-
4. **TURN relay integration** (2-3 weeks)
|
|
238
|
-
- Deploy Coturn server (or use public TURN service)
|
|
239
|
-
- Implement TURN client in OGP daemon
|
|
240
|
-
- Relay allocation and authentication
|
|
241
|
-
|
|
242
|
-
5. **Dual transport coordination** (1 week)
|
|
243
|
-
- Try UDP first, fall back to HTTP
|
|
244
|
-
- Protocol negotiation handshake
|
|
245
|
-
- Handle mixed scenarios (Peer A has UDP, Peer B HTTP-only)
|
|
246
|
-
|
|
247
|
-
6. **Testing matrix** (2-3 weeks)
|
|
248
|
-
- Test all NAT type combinations (4x4 = 16 scenarios)
|
|
249
|
-
- Simulate symmetric NAT, firewall rules, packet loss
|
|
250
|
-
- Validate fallback paths work reliably
|
|
251
|
-
|
|
252
|
-
**Total estimated effort:** 9-13 weeks (2-3 months)
|
|
253
|
-
|
|
254
|
-
**Risk factors:**
|
|
255
|
-
- NAT behavior is unpredictable (ISPs change router configs)
|
|
256
|
-
- Timing synchronization issues (hole punching is timing-sensitive)
|
|
257
|
-
- TURN relay costs and maintenance burden
|
|
258
|
-
- Breaking changes to existing HTTP federation (backward compatibility risk)
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## ⚠️ Risks and Unknowns
|
|
263
|
-
|
|
264
|
-
### 1. Symmetric NAT Prevalence
|
|
265
|
-
|
|
266
|
-
**Unknown:** What % of OGP users are actually behind symmetric NAT?
|
|
267
|
-
|
|
268
|
-
- Industry estimates: ~10-15% residential, ~40% cellular/CGN
|
|
269
|
-
- OGP user base: Unknown (no telemetry data)
|
|
270
|
-
- **Mitigation:** Add telemetry to measure NAT type distribution before implementing
|
|
271
|
-
|
|
272
|
-
### 2. TURN Relay Costs
|
|
273
|
-
|
|
274
|
-
**Unknown:** How much bandwidth will relayed traffic consume?
|
|
275
|
-
|
|
276
|
-
- TURN servers charge by bandwidth (not connections)
|
|
277
|
-
- If 15% of traffic routes through relay, costs scale with user growth
|
|
278
|
-
- **Mitigation:** Self-host Coturn or use public TURN services (rate-limited, unreliable)
|
|
279
|
-
|
|
280
|
-
### 3. Firewall Interference
|
|
281
|
-
|
|
282
|
-
**Unknown:** Do corporate/school firewalls block UDP port 18791?
|
|
283
|
-
|
|
284
|
-
- Many networks whitelist HTTP (80/443) but block arbitrary UDP ports
|
|
285
|
-
- UDP hole punching may fail even with cone NAT due to firewall rules
|
|
286
|
-
- **Mitigation:** Fallback to HTTP (already implemented), so no user impact
|
|
287
|
-
|
|
288
|
-
### 4. IPv6 Considerations
|
|
289
|
-
|
|
290
|
-
**Unknown:** Does UDP hole punching work differently on IPv6?
|
|
291
|
-
|
|
292
|
-
- IPv6 has no NAT in theory, but many ISPs still use CGN (Carrier-Grade NAT)
|
|
293
|
-
- STUN/TURN specs support IPv6, but library support varies
|
|
294
|
-
- **Mitigation:** Focus on IPv4 first, add IPv6 later if needed
|
|
295
|
-
|
|
296
|
-
### 5. Mobile/Tethering Scenarios
|
|
297
|
-
|
|
298
|
-
**Unknown:** Do mobile hotspots (phone tethering) use symmetric NAT?
|
|
299
|
-
|
|
300
|
-
- Cellular networks often use symmetric NAT (40%+ based on research)
|
|
301
|
-
- Mobile users may be disproportionately blocked by UDP hole punching
|
|
302
|
-
- **Mitigation:** HTTP fallback works fine for mobile users
|
|
303
|
-
|
|
304
|
-
### 6. Library Ecosystem Immaturity
|
|
305
|
-
|
|
306
|
-
**Risk:** No battle-tested Node.js library for UDP hole punching exists
|
|
307
|
-
|
|
308
|
-
- Would need to implement custom logic on top of basic STUN client
|
|
309
|
-
- Debugging NAT traversal issues is notoriously difficult
|
|
310
|
-
- **Mitigation:** Use werift (WebRTC stack) despite complexity, or write custom implementation
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
|
|
314
|
-
## 🔗 References
|
|
315
|
-
|
|
316
|
-
### Research Papers
|
|
317
|
-
- [Peer-to-Peer Communication Across NATs (Bryan Ford)](https://pdos.csail.mit.edu/papers/p2pnat.pdf)
|
|
318
|
-
- [UDP Hole Punching - Wikipedia](https://en.wikipedia.org/wiki/UDP_hole_punching)
|
|
319
|
-
- [A New Method for Symmetric NAT Traversal](https://www.researchgate.net/publication/228411948_A_New_Method_for_Symmetric_NAT_Traversal_in_UDP_and_TCP)
|
|
320
|
-
|
|
321
|
-
### Implementation Guides
|
|
322
|
-
- [How NAT Traversal Works (Tailscale)](https://tailscale.com/blog/how-nat-traversal-works)
|
|
323
|
-
- [NAT Traversal Visual Guide (DEV Community)](https://dev.to/dev-dhanushkumar/nat-traversal-a-visual-guide-to-udp-hole-punching-1936)
|
|
324
|
-
- [Understanding NAT Types (DH2i)](https://support.dh2i.com/docs/Archive/kbs/general/understanding-different-nat-types-and-hole-punching/)
|
|
325
|
-
|
|
326
|
-
### Libraries and Tools
|
|
327
|
-
- [nodertc/stun (GitHub)](https://github.com/nodertc/stun) — RFC 5389 STUN client/server
|
|
328
|
-
- [werift (npm)](https://www.npmjs.com/package/werift) — WebRTC stack for TypeScript/Node.js
|
|
329
|
-
- [udp-hole-puncher (npm)](https://www.npmjs.com/package/udp-hole-puncher) — Dedicated hole punching library
|
|
330
|
-
- [xkore (npm)](https://www.npmjs.com/search?q=nat+traversal) — Newest NAT traversal library (2 months old)
|
|
331
|
-
- [coturn (GitHub)](https://github.com/coturn/coturn) — Open-source TURN server
|
|
332
|
-
|
|
333
|
-
### STUN/TURN Standards
|
|
334
|
-
- [RFC 5389: Session Traversal Utilities for NAT (STUN)](https://www.rfc-editor.org/rfc/rfc5389.html)
|
|
335
|
-
- [RFC 8489: STUN (obsoletes RFC 5389)](https://www.rfc-editor.org/rfc/rfc8489.html)
|
|
336
|
-
- [RFC 5766: Traversal Using Relays around NAT (TURN)](https://www.rfc-editor.org/rfc/rfc5766)
|
|
337
|
-
- [RFC 8656: TURN (obsoletes RFC 5766)](https://datatracker.ietf.org/doc/rfc8656/)
|
|
338
|
-
|
|
339
|
-
### Deployment Resources
|
|
340
|
-
- [Coturn Setup Guide (Gabriel Tanner)](https://gabrieltanner.org/blog/turn-server/)
|
|
341
|
-
- [WebRTC STUN Server Integration (VideoSDK)](https://www.videosdk.live/developer-hub/stun-turn-server/webrtc-stun-server)
|
|
342
|
-
- [STUN/TURN Server in Azure (Microsoft)](https://learn.microsoft.com/en-us/gaming/azure/reference-architectures/stun-turn-server-in-azure)
|
|
343
|
-
|
|
344
|
-
---
|
|
345
|
-
|
|
346
|
-
## 🎬 Next Steps (If Reconsidered)
|
|
347
|
-
|
|
348
|
-
**Do NOT proceed with implementation until:**
|
|
349
|
-
|
|
350
|
-
1. **User research** — Survey OGP users: Are they blocked by NAT? What % use tunnels vs direct IP?
|
|
351
|
-
2. **Telemetry** — Add NAT type detection to OGP daemon, collect anonymous stats for 30 days
|
|
352
|
-
3. **Cost analysis** — Estimate TURN relay costs based on actual traffic patterns
|
|
353
|
-
4. **Prototype** — Build minimal UDP hole punch prototype (no TURN) and test with 10-20 users
|
|
354
|
-
5. **Decision point** — If >50% of users benefit AND TURN costs are acceptable, proceed with full implementation
|
|
355
|
-
|
|
356
|
-
**Until then:** Focus on improving HTTP rendezvous server reliability and user experience.
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
|
|
360
|
-
## Appendix: NAT Type Detection
|
|
361
|
-
|
|
362
|
-
For future reference, here's how to detect NAT type using STUN:
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
import dgram from 'dgram';
|
|
366
|
-
|
|
367
|
-
async function detectNATType(): Promise<'full-cone' | 'restricted' | 'port-restricted' | 'symmetric'> {
|
|
368
|
-
const socket = dgram.createSocket('udp4');
|
|
369
|
-
|
|
370
|
-
// Test 1: Basic STUN binding to STUN server A
|
|
371
|
-
const { ip: publicIP1, port: publicPort1 } = await stunBinding(socket, 'stun.l.google.com', 19302);
|
|
372
|
-
|
|
373
|
-
// Test 2: STUN binding to STUN server B (different IP)
|
|
374
|
-
const { ip: publicIP2, port: publicPort2 } = await stunBinding(socket, 'stun1.l.google.com', 19302);
|
|
375
|
-
|
|
376
|
-
// If public ports differ, it's symmetric NAT
|
|
377
|
-
if (publicPort1 !== publicPort2) {
|
|
378
|
-
return 'symmetric';
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Test 3: Request STUN server to respond from different port
|
|
382
|
-
const respondsFromDifferentPort = await stunBindingWithPortChange(socket, 'stun.l.google.com', 19302);
|
|
383
|
-
|
|
384
|
-
if (respondsFromDifferentPort) {
|
|
385
|
-
return 'full-cone'; // Accepts packets from any IP:port
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Test 4: Request response from different IP
|
|
389
|
-
const respondsFromDifferentIP = await stunBindingWithIPChange(socket, 'stun.l.google.com', 19302);
|
|
390
|
-
|
|
391
|
-
if (respondsFromDifferentIP) {
|
|
392
|
-
return 'restricted'; // Accepts packets from any port on same IP
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return 'port-restricted'; // Only accepts packets from same IP:port
|
|
396
|
-
}
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
**Note:** This is pseudo-code. Actual implementation requires RFC 5780 (NAT Behavior Discovery).
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Project Intent Testing
|
|
2
|
-
|
|
3
|
-
This repo now includes a runnable local project-intent harness:
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm run test:project-intents
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
The harness creates two isolated local gateways with separate `OGP_HOME` directories, federates them over localhost, and exercises the real project commands:
|
|
10
|
-
|
|
11
|
-
- `federation request`
|
|
12
|
-
- `federation approve`
|
|
13
|
-
- `project create`
|
|
14
|
-
- `project contribute --local-only`
|
|
15
|
-
- `project request-join`
|
|
16
|
-
- `project send-contribution`
|
|
17
|
-
- `project query-peer`
|
|
18
|
-
- `project status-peer`
|
|
19
|
-
|
|
20
|
-
## What It Verifies
|
|
21
|
-
|
|
22
|
-
The automated run checks these behaviors:
|
|
23
|
-
|
|
24
|
-
1. Two local daemons can boot independently.
|
|
25
|
-
2. Federation approval completes between them.
|
|
26
|
-
3. The project owner can create a local project and persist local contributions.
|
|
27
|
-
4. A non-member peer cannot query the project before joining.
|
|
28
|
-
5. The peer can join the project through `project.join`.
|
|
29
|
-
6. The joined peer can send a remote contribution through `project.contribute`.
|
|
30
|
-
7. The joined peer can query the owner project through `project.query`.
|
|
31
|
-
8. The status request path for `project.status` succeeds at the transport level.
|
|
32
|
-
|
|
33
|
-
## Useful Variants
|
|
34
|
-
|
|
35
|
-
Keep the temp state and logs for inspection:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm run test:project-intents -- --keep-state
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Use a custom root or ports:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
npm run test:project-intents -- \
|
|
45
|
-
--root /tmp/ogp-project-intent-test \
|
|
46
|
-
--alpha-port 18990 \
|
|
47
|
-
--beta-port 18991
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Skip the TypeScript rebuild when `dist/` is already current:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npm run test:project-intents -- --skip-build
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Manual Checks
|
|
57
|
-
|
|
58
|
-
If you want to replay the flow by hand, the harness prints the exact commands it used. These are the most valuable checks:
|
|
59
|
-
|
|
60
|
-
1. Membership isolation:
|
|
61
|
-
`project query-peer` should fail before `project request-join`.
|
|
62
|
-
2. Membership grant:
|
|
63
|
-
`project request-join` should create or update the project on the requester and add the remote member on the owner.
|
|
64
|
-
3. Data flow:
|
|
65
|
-
`project send-contribution` should create a new contribution on the owner gateway.
|
|
66
|
-
4. Remote visibility:
|
|
67
|
-
`project query-peer` should return the contribution after join succeeds.
|
|
68
|
-
5. Local persistence:
|
|
69
|
-
`projects.json` under each `OGP_HOME` should reflect the expected project and topic state.
|
|
70
|
-
|
|
71
|
-
## Interpreting Success
|
|
72
|
-
|
|
73
|
-
Project intents are working if all of the following are true:
|
|
74
|
-
|
|
75
|
-
- both daemons answer `/.well-known/ogp`
|
|
76
|
-
- both peers end up `approved` in `peers.json`
|
|
77
|
-
- the owner `projects.json` contains the remote member after join
|
|
78
|
-
- the owner `projects.json` contains the remote contribution after send
|
|
79
|
-
- pre-join query fails and post-join query succeeds
|
|
80
|
-
|
|
81
|
-
## Known Testing Nuance
|
|
82
|
-
|
|
83
|
-
`project status-peer` currently confirms that the request was sent, but it is not the best content-verification command because the CLI does not format the returned status payload. Treat it as a transport-path check, and use `project query-peer`, `project status`, `projects.json`, and daemon logs for stronger validation.
|
|
84
|
-
|
|
85
|
-
For controlled runs, `project contribute --local-only` is still useful when you want to inspect local state before any federation traffic. The default auto-sync path now limits fan-out to approved peers who are explicit members of the project.
|
|
86
|
-
|
|
87
|
-
## File Transfer
|
|
88
|
-
|
|
89
|
-
OGP project intents do not currently implement first-class file transfer. Small structured metadata is fine, but real file movement would need explicit protocol support such as:
|
|
90
|
-
|
|
91
|
-
- file manifests with name, size, MIME type, and hash
|
|
92
|
-
- signed download URLs
|
|
93
|
-
- chunking or streaming for larger payloads
|
|
94
|
-
- size limits and approval controls
|
|
95
|
-
- storage and retention rules
|
|
96
|
-
|
|
97
|
-
For now, the practical pattern is to transfer references, hashes, and URLs through project intents rather than raw file contents.
|