feat(net): IPv6 GUA exposure tri-state (disabled/LAN/LAN+WAN)#3368
Merged
Conversation
dr-bonez
reviewed
Jun 30, 2026
helix-nine
added a commit
that referenced
this pull request
Jun 30, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
dr-bonez
reviewed
Jun 30, 2026
dr-bonez
reviewed
Jun 30, 2026
dr-bonez
previously approved these changes
Jun 30, 2026
9 tasks
helix-nine
added a commit
that referenced
this pull request
Jun 30, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
e98448b to
a4b1fc6
Compare
helix-nine
added a commit
that referenced
this pull request
Jun 30, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
a4b1fc6 to
bcf56f3
Compare
helix-nine
added a commit
that referenced
this pull request
Jul 1, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
bcf56f3 to
96fb458
Compare
helix-nine
added a commit
that referenced
this pull request
Jul 1, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
96fb458 to
1c5572e
Compare
helix-nine
added a commit
that referenced
this pull request
Jul 1, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
1c5572e to
cf634fe
Compare
helix-nine
added a commit
that referenced
this pull request
Jul 1, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
cf634fe to
5ab0cc5
Compare
helix-nine
added a commit
that referenced
this pull request
Jul 1, 2026
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
5ab0cc5 to
c729eed
Compare
… + RPC + derivation
An IPv6 global-unicast address is a single globally-routable address, so a
plain on/off toggle can't express LAN-only (firewalled) vs WAN-exposed. Give
GUAs a tri-state instead, defaulting to LAN (behavior-preserving — GUAs are
LAN-only source-filtered today).
- GuaAccess { Disabled, Lan, LanWan } + gua_access map on DerivedAddressInfo
- HostnameInfo::gua() (global-unicast detection), access_for/is_wan, GUA-aware enabled()
- set-gua-access RPC (mirrors the removed set_range_gateway_access) + i18n x5
- net_controller derivation (SSL/vhost + non-SSL) classifies WAN via is_wan(),
so a LAN+WAN GUA flows into the public set — vhost already binds the GUA and
source-filters LAN per ProxyTarget::filter()
- ts-bindings regenerated; model unit tests
Follow-up commits (this PR): PCP-v6 pinhole, non-SSL v6 forwarding (lxcbr0 IPv6
+ ip6 nft table), UI tri-state control, docs/CHANGELOG.
…ing param Per @dr-bonez's review on #3368: - `gua_access` keyed by `SocketAddrV6` (type-precise — GUAs are always v6); `HostnameInfo::gua()` returns `SocketAddrV6`. - New `CliFromJsonString<T>`: a param that is structured `T` over the JSON-RPC wire (serde passthrough — no double-encoding) but a JSON-string arg on the CLI (clap `ValueParser` parses the JSON). Replaces the `address: String` + `serde_json::from_str` pattern in both `set_gua_access` and the inherited `set_address_enabled`. Pair with `#[ts(as = "HostnameInfo")]` so the binding shows the object. - UI: `set-address-enabled` now sends the `HostnameInfo` object instead of a JSON string (api.types, both toggle callers, mock). - ts-bindings regenerated.
Render IPv6 GUA addresses on the service Interfaces page with a
Disabled / LAN / LAN+WAN selector instead of the on/off toggle every other
address uses, wired to the new set-gua-access RPC.
- interface.service.ts: client-side GUA detection (matches the backend's
ipv6_is_local complement), `GatewayAddress.guaAccess`, GUA-aware `isEnabled`.
- item.component.ts: tri-state <select> for GUA rows (switch for the rest) +
onSetGuaAccess handler.
- api: serverBindingSetGuaAccess / pkgBindingSetGuaAccess (types, abstract,
live RPC, mock + mockSetGuaAccess).
- fixtures/mocks: guaAccess: {} on DerivedAddressInfo literals.
check:ui passes.
Interfaces page + CHANGELOG: the Disabled / LAN / LAN+WAN control for IPv6 global-unicast addresses (default LAN, LAN+WAN attempts a PCP pinhole).
Per @dr-bonez: parse the hostname straight to Ipv6Addr instead of IpAddr + matching IpAddr::V6. The parse is itself the discriminant, so the redundant Ipv6-metadata guard is dropped.
Per @dr-bonez: restore the `matches!(metadata, Ipv6 { .. })` guard; only the IpAddr::V6 parse dance was the redundant part.
Member
|
@helix-nine rebase this |
c729eed to
df10f6a
Compare
dr-bonez
approved these changes
Jul 1, 2026
Contributor
Author
|
Already covered — I'd rebased this onto |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on #3366 (
feat/port-range-interfaces) — base is that branch, notmaster.Gives IPv6 GUA (global-unicast) addresses on a service interface a Disabled / LAN / LAN+WAN tri-state instead of the on/off toggle every other address uses. A GUA is a single globally-routable address, so "on" must distinguish LAN-only (firewalled to the subnet) from WAN-exposed. Per @dr-bonez:
vhost::ProxyTarget::filter()).In this PR
GuaAccess { Disabled, Lan, LanWan }(defaultLan) +gua_access: BTreeMap<SocketAddrV6, GuaAccess>onDerivedAddressInfo;HostnameInfo::gua(),access_for/is_wan, GUA-awareenabled().set-gua-access(mirrors the removedset_range_gateway_access);CliFromJsonString<T>so the param is a structuredHostnameInfoover the wire but a JSON-string CLI arg (also applied to the inheritedset_address_enabled). i18n ×5.is_wan().set-gua-access(+ mock).check:uigreen.Verified:
cargo check, model unit tests, ts-bindings (no drift),check:ui.Follow-up — separate PR (per @dr-bonez, easier to review)
The v6 WAN backend forwarding, which shares the forward path and needs VM validation:
port_mapIpv4Addr→IpAddrgeneralization (UPnP stays v4-gated) + PCP-v6 pinhole for LAN+WAN GUAs (the v6 gateway is already inip_info.lan_ip).lxcbr0IPv6, container v6 discovery/storage, anip6 startosnft table (filter + LAN source-reject), a v6forward-port, andnet.ipv6.conf.all.forwarding.