Skip to content

Commit 09ba23d

Browse files
hyperpolymathclaude
andcommitted
feat(groove/transport): IPv6-only mode, IPv4 sunset, strip-and-upgrade
Add Section 7 to TRANSPORT.adoc — IPv6 transition strategy: - IPv6-only binding RECOMMENDED for localhost (every Groove-capable OS has ::1, no reason to keep 127.0.0.1) - IPv4 sunset headers: Groove-IPv6-Preferred, Groove-IPv4-Sunset, Groove-Upgrade-To (mirrors HSTS pattern) - Strip-and-upgrade: accept IPv4 as doorbell, redirect data plane to IPv6 immediately. Zig FFI handles the translation. - IPv6 strict mode: no IPv4 socket at all (RECOMMENDED for new deploys) - Client behaviour: cache IPv6 preference, never fall back after successful IPv6 connection - LAN strategy: IPv6 link-local multicast (ff02::fb) exclusively, IPv4 LAN sunset on same timeline Updated summary table to reflect IPv6-first stance. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 715c4f7 commit 09ba23d

1 file changed

Lines changed: 149 additions & 6 deletions

File tree

groove-protocol/spec/TRANSPORT.adoc

Lines changed: 149 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,18 +269,161 @@ MUST NOT fail if IPv6 probes return network-unreachable errors.
269269
On dual-stack systems (the common case), the binding and probing rules
270270
in Sections 1 and 2 apply. IPv6 is preferred, IPv4 is the fallback.
271271

272-
== 7. Summary
272+
== 7. IPv6 Transition and IPv4 Sunset
273+
274+
=== 7.1. IPv6-Only Mode (RECOMMENDED for Localhost)
275+
276+
For localhost Groove (the default scope), IPv6-only binding is RECOMMENDED.
277+
Every operating system capable of running Groove has a functional IPv6
278+
loopback (`::1`). There is no legitimate reason to use IPv4 loopback for
279+
local Groove discovery.
280+
281+
**Startup procedure:**
282+
283+
. Probe `::1` — attempt to bind a test socket to `[::1]:0`
284+
. If successful → bind to `[::1]:PORT` only. Do not create an IPv4 socket.
285+
. If unsuccessful (no IPv6 stack) → fall back to `127.0.0.1:PORT` and emit
286+
a deprecation warning to the system log.
287+
. Report the binding mode in the Groove Manifest:
288+
289+
[source,a2ml]
290+
----
291+
@groove-manifest(version="0.1.0"):
292+
@system(id="my-service", version="0.1.0")
293+
@transport:
294+
@binding(protocol="ipv6", address="::1", port=6473)
295+
@ipv4-sunset(date="2027-01-01", status="deprecated")
296+
@end
297+
@end
298+
----
299+
300+
=== 7.2. IPv4 Sunset Headers
301+
302+
During a transition period, a Groove service that still accepts IPv4
303+
connections MUST include sunset headers signalling that IPv4 support will
304+
be removed:
305+
306+
[source,http]
307+
----
308+
HTTP/1.1 200 OK
309+
Content-Type: application/groove+a2ml
310+
Groove-IPv6-Preferred: [::1]:6473
311+
Groove-IPv4-Sunset: 2027-01-01
312+
Groove-Upgrade-To: ipv6
313+
Sunset: Sat, 01 Jan 2027 00:00:00 GMT
314+
----
315+
316+
[cols="2,3"]
317+
|===
318+
| Header | Purpose
319+
320+
| `Groove-IPv6-Preferred`
321+
| The IPv6 endpoint the client SHOULD use for all subsequent traffic
322+
323+
| `Groove-IPv4-Sunset`
324+
| The date after which IPv4 will no longer be accepted (ISO 8601)
325+
326+
| `Groove-Upgrade-To`
327+
| Directive to the client to upgrade its connection to IPv6
328+
329+
| `Sunset` (RFC 8594)
330+
| Standard HTTP sunset header for the IPv4 endpoint
331+
|===
332+
333+
This follows the same pattern as HTTP Strict Transport Security (HSTS):
334+
the client is told to upgrade, and all subsequent connections use the
335+
preferred transport.
336+
337+
=== 7.3. Strip-and-Upgrade on Arrival
338+
339+
When a Groove service receives an IPv4 connection and IPv6 is available,
340+
the service SHOULD perform a strip-and-upgrade:
341+
342+
. Accept the IPv4 connection (refusing causes a confusing connection error)
343+
. Read the Groove request
344+
. Respond with the manifest including `Groove-Upgrade-To: ipv6` header
345+
. For connection handshake (`POST /.well-known/groove/connect`):
346+
accept the connection but return the IPv6 endpoint for all data-plane
347+
traffic
348+
. All subsequent data-plane traffic uses IPv6 exclusively
349+
. The IPv4 socket serves only as a discovery doorbell — the real
350+
conversation happens on IPv6
351+
352+
[source]
353+
----
354+
Client (IPv4) Groove Service
355+
│ │
356+
│──── GET /.well-known/groove ────────→ │ ← IPv4 accepted (doorbell)
357+
│ │
358+
│←── 200 OK + Groove-Upgrade-To: ipv6 ──│ ← "Come to the IPv6 entrance"
359+
│ │
360+
│──── POST /connect (on [::1]:6473) ──→ │ ← IPv6 connection (real door)
361+
│ │
362+
│←──────── Connected (IPv6) ────────────│ ← All subsequent traffic is IPv6
363+
----
364+
365+
=== 7.4. IPv6 Strict Mode
366+
367+
Groove services MAY support an IPv6 strict mode where IPv4 connections are
368+
refused entirely:
369+
370+
[source,a2ml]
371+
----
372+
@transport:
373+
@binding(protocol="ipv6-strict", address="::1", port=6473)
374+
@ipv4(status="disabled")
375+
@end
376+
----
377+
378+
In strict mode:
379+
380+
. No IPv4 socket is created
381+
. IPv4 probes receive no response (connection refused)
382+
. The manifest declares `ipv4.status = "disabled"`
383+
384+
This is RECOMMENDED for new deployments. Legacy compatibility mode
385+
(dual-stack or strip-and-upgrade) is available for transition.
386+
387+
=== 7.5. Client Behaviour
388+
389+
Groove clients (including browser extension harnesses) MUST:
390+
391+
. Probe `[::1]` first for all local discovery
392+
. Respect `Groove-Upgrade-To: ipv6` headers by reconnecting on IPv6
393+
. Cache the IPv6 preference for the duration of the session
394+
. NOT fall back to IPv4 after a successful IPv6 connection
395+
. Fall back to IPv4 ONLY if IPv6 probing produces no results AND the
396+
`Groove-IPv4-Sunset` header is absent or the sunset date has not passed
397+
398+
=== 7.6. LAN IPv6 Forward Strategy
399+
400+
For LAN discovery, IPv6 provides inherent advantages:
401+
402+
. **Link-local addresses** (`fe80::...`) exist on every interface without
403+
DHCP — zero-configuration addressing
404+
. **mDNS multicast** over `ff02::fb` is cleaner than IPv4 `224.0.0.251`
405+
. **No NAT** — IPv6 link-local addresses are directly reachable on the
406+
segment without NAT traversal
407+
408+
Groove services offering LAN discovery SHOULD use IPv6 link-local multicast
409+
exclusively. IPv4 LAN discovery (mDNS over `224.0.0.251`) is OPTIONAL and
410+
SHOULD be sunset on the same timeline as IPv4 loopback.
411+
412+
== 8. Summary
273413

274414
[cols="2,3"]
275415
|===
276416
| Requirement | Specification
277417

278-
| Binding | Dual-stack `[::]:PORT` or both `127.0.0.1` and `[::1]`
279-
| Probe order | `[::1]` first, `127.0.0.1` fallback, 500ms timeout each
418+
| Localhost binding | IPv6-only `[::1]:PORT` RECOMMENDED. Dual-stack as transition.
419+
| Probe order | `[::1]` first, `127.0.0.1` fallback only if IPv6 absent
420+
| IPv4 sunset | `Groove-IPv4-Sunset` header with date, `Groove-Upgrade-To: ipv6`
421+
| Strip-and-upgrade | Accept IPv4 as doorbell, redirect data plane to IPv6
422+
| Strict mode | IPv6-strict available: no IPv4 socket created at all
280423
| CORS | `Access-Control-Allow-Origin: *` on all groove endpoints
281424
| Preflight | `OPTIONS` → `204 No Content` with CORS headers
282-
| LAN discovery | mDNS/DNS-SD over `ff02::fb`, explicit opt-in only
425+
| LAN discovery | mDNS/DNS-SD over IPv6 multicast `ff02::fb`, opt-in only
283426
| Default scope | Localhost only (loopback interface)
284-
| Data plane | Any transport, declared in Idris2 ABI
285-
| IPv6 preference | IPv6-preferred, IPv4-fallback, never single-stack
427+
| Data plane | Any transport (HTTP/WS/gRPC/WebRTC/Unix/BEAM), declared in ABI
428+
| Client behaviour | Cache IPv6 preference, never fall back after successful IPv6
286429
|===

0 commit comments

Comments
 (0)