Issue 191: an internal name is served to the private network only
The first fix served the dropped route to anyone who sent its name. Record why in the issue, as a progressive insight on ADR 0138, and in the to-be connectivity design.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-01
|
||||
located-in: [mesh-controller examples/route-proxy/main.go (routesFrom requires a route's public `name` and treats `internal-name` only as an alias of it)]
|
||||
located-in: [mesh-controller examples/route-proxy/main.go (routesFrom requires a route's public `name` and treats `internal-name` only as an alias of it; the handler serves every routed name to any source), mesh-catalog modules/route-proxy/module.json (the proxy is not told the private network's range)]
|
||||
fixed-by:
|
||||
amended-design: []
|
||||
amended-design: [03-DESIGN/01-to-be/08-connectivity.md]
|
||||
---
|
||||
|
||||
# 191 — A route with only an internal name is dropped as naming nothing
|
||||
|
||||
@@ -23,9 +23,43 @@ mesh before ADR 0138, when both names were always composed. It has been wrong si
|
||||
The other half of the proxy already handles the case. Certificates for a host are split by whether it
|
||||
is in the public set: hosts outside it go to the internal authority, and only hosts inside it are
|
||||
eligible for ACME. A host that is only ever an internal name falls on the correct side of both checks
|
||||
without change. Only reading the route was wrong.
|
||||
without change. For certificates, only reading the route was wrong; who may reach the route is the next section.
|
||||
|
||||
**The fix.** `routesFrom` takes a route that names either host, serves each name it carries, and
|
||||
marks only the public one as public. It still skips a route that names neither, with the same log line.
|
||||
A test proves an internal-only route is served, certified by the internal authority, and refused by
|
||||
the public one. That test fails against the code before the change.
|
||||
|
||||
## The first fix would have made the name public — 2026-10-02, from review
|
||||
|
||||
Serving the dropped route was not enough. The proxy picks a route from the name a request carries
|
||||
and never from where the request came from, and it answers public and internal names on the same
|
||||
listeners. Its public names resolve to an address the internet reaches. So once the internal-only
|
||||
route was served, any request from the internet carrying `unifi.home-server.internal` — a name of a
|
||||
fixed, guessable shape — would have reached an administration interface that reach `internal` was
|
||||
chosen to keep private. Before the fix the route was unreachable from everywhere. After it, it would
|
||||
have been reachable from everywhere. Two more leaks came with it: the proxy's answer for an unrouted
|
||||
name listed every name it serves, internal ones included, and the handshake handed a certificate
|
||||
naming the internal host to any client.
|
||||
|
||||
Nothing showed this while every routed endpoint also had a public name: its internal name exposed
|
||||
nothing the public one did not. It is a gap in the decision's wording, not only in the proxy — ADR
|
||||
0138 says the proxy *serves* the internal name without saying to whom — so it is recorded there as a
|
||||
progressive insight and in the to-be connectivity design.
|
||||
|
||||
**Where "inside" is decided.** The mesh's guard recognises the private network by the interface a
|
||||
packet arrives on, never by source address, because a source can be claimed. The proxy cannot see the
|
||||
interface, so it reads the source: the mesh's range, loopback, and the ranges of the machine's own
|
||||
container bridges, which are the same interfaces the guard names. A claimed source does not carry
|
||||
here, as a connection needs its replies, and replies to those addresses leave by the tunnel or a
|
||||
local bridge. The range reaches the proxy from the catalog as the machine's `mesh-range`, the way the
|
||||
intrusion filter already receives it. With none given, the proxy serves internal names to the machine
|
||||
alone: refused, not opened.
|
||||
|
||||
**What changed with it.** The internal name of a route that also has a public one is now served to
|
||||
the private network only, like any other internal name. Outsiders have the public name, so nothing
|
||||
they could reach is lost.
|
||||
|
||||
**Order of release.** The catalog change comes first. A proxy built from the change but started
|
||||
without the range would serve internal names to its own machine alone, and every other member of the
|
||||
mesh would lose them until the range arrived.
|
||||
|
||||
Reference in New Issue
Block a user