Skip to content

Commit 7da71c5

Browse files
ralyodioclaude
andauthored
docs(prd): 0005 — a hosted Moshpit resolver, for devices that cannot run the bridge (#196)
A Moshpit ending is not in the ICANN root, so nothing resolves it until the client is told something. Today there is one way to be told, and it is unavailable exactly where people meet a name: a phone cannot run a daemon, a router takes a DNS server and nothing else, and the person you sent the link to has installed nothing. The fallback for all of them is /n/<name>, which works and is not resolution — the URL bar reads pit.moshcode.sh, so the name never becomes the visitor's address, which is the point of holding one. Written as a draft rather than a plan because the central tradeoff is not solvable, only disclosed: a hosted resolver sees every DNS query the device makes, not just Moshpit ones. The PRD says so in the goals, in the UI requirement, and in the risks, and states plainly that the honest outcome may be to not ship it. Deliberately not a replacement for the local bridge, which stays the recommended path wherever it can run. The infrastructure is already half-built — MOSHPIT_DNS_RESOLVERS and MOSHPIT_DOH_URL are read, validated and rendered on /pit/dns, and both are unset in production. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 22c0d6c commit 7da71c5

1 file changed

Lines changed: 192 additions & 0 deletions

File tree

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
---
2+
openprd: "0.2"
3+
id: "0005"
4+
title: A hosted Moshpit resolver, for the devices that cannot run the bridge
5+
status: Draft
6+
authors:
7+
- anthony@chovy.com
8+
created: 2026-08-01
9+
updated: 2026-08-01
10+
repo: https://github.com/moshcoder/moshcode
11+
discussion:
12+
implementation: apps/pwa/src/lib/moshpit-resolvers.mjs, apps/pwa/src/routes/moshpit.mjs, src/dns.mjs
13+
tags:
14+
- moshpit
15+
- dns
16+
- infrastructure
17+
- privacy
18+
supersedes:
19+
superseded-by:
20+
---
21+
22+
## Problem
23+
24+
A Moshpit ending is not in the ICANN root, so nothing resolves it until the
25+
client is told something. Today there is exactly one way to be told: run
26+
`moshcode dns enable`, which installs a local bridge and points the machine's
27+
resolver at it.
28+
29+
That works on a laptop or a VPS. It is unavailable on the devices where most
30+
people would actually meet a Moshpit name:
31+
32+
- a **phone**, which cannot run a daemon or edit `resolved.conf.d`
33+
- a **router**, where you can set a DNS server and nothing else
34+
- **someone else's machine** — the person you sent the link to
35+
36+
For all of them the only answer is `pit.moshcode.sh/n/<name>`, which fetches the
37+
origin server-side and hands back the page. It works, and it is not resolution:
38+
the URL bar reads `pit.moshcode.sh`, not `chovy.hacker`. The name never becomes
39+
the visitor's address, which is the entire point of holding one.
40+
41+
The infrastructure for the missing piece is already half-built and unused.
42+
`MOSHPIT_DNS_RESOLVERS` and `MOSHPIT_DOH_URL` are read, validated as real
43+
addresses, and rendered on `/pit/dns` — and both are unset in production, so the
44+
page publishes nothing. The shop window was built before the shop.
45+
46+
This PRD is deliberately **not** a replacement for the local bridge. It is the
47+
answer for clients that cannot run one, and the difference matters because the
48+
tradeoff is real and permanent: a hosted resolver sees every DNS query the
49+
device makes.
50+
51+
## Goals
52+
53+
- A Moshpit name resolves on a device that can only be handed a DNS server.
54+
- The URL bar keeps the name. `http://chovy.hacker/` stays `chovy.hacker`.
55+
- Non-Moshpit lookups are answered correctly and are not the product.
56+
- The privacy cost is stated plainly, in the UI, before anyone opts in.
57+
- An outage degrades to "Moshpit names stop working", never "the internet stops
58+
working", for as long as that is within our control.
59+
60+
## Non-Goals
61+
62+
- **Replacing the local bridge.** Where a bridge can run it stays the better
63+
answer: no third party sees the queries, no round trip, no shared outage.
64+
`moshcode dns enable` remains the recommended path and the docs say so.
65+
- **Being a general-purpose public resolver.** We are not competing with
66+
1.1.1.1. Forwarding exists so Moshpit names can resolve, not as a service.
67+
- **Logging queries for analytics.** See Requirements — this is the one place
68+
where the tempting feature is the one that kills the product.
69+
- **DNSSEC-signing the Moshpit zone.** Out of scope for v1; the endings are not
70+
in the root, so there is no chain to anchor to.
71+
72+
## Users
73+
74+
**Someone sent a link.** They open `http://seo.rank/` on a phone. Today: a
75+
browser error, or a `pit.moshcode.sh` URL. With this: the page, at its own name.
76+
77+
**A household or office.** One DNS setting on the router, and every device on
78+
the network resolves Moshpit names with nothing installed on any of them.
79+
80+
**A name holder demonstrating one.** The reason to hold `chovy.hacker` is that
81+
it is an address you can give people. Today giving it away requires asking them
82+
to install software first.
83+
84+
## Requirements
85+
86+
### R1 — Two protocols, both public
87+
88+
`Do53` (plain UDP/TCP 53) for routers and OS settings, and **DNS-over-HTTPS**
89+
for phones and browsers, which increasingly will not accept anything else.
90+
iOS and Android both accept a DoH profile; neither will run our daemon.
91+
92+
DoH is the one that unlocks phones, so it is not optional.
93+
94+
### R2 — Anycast or nothing
95+
96+
A single box is a single point of failure for the DNS of every device pointed
97+
at it. If the deployment cannot be multi-region behind one address, this ships
98+
as "best effort, do not set it as your only resolver" and says so in the UI.
99+
100+
### R3 — Forwarding is the dangerous part
101+
102+
The resolver answers Moshpit endings from the registry and forwards everything
103+
else. That forwarding is what makes it usable as a device's only DNS server —
104+
and what makes it a privacy problem, a latency tax, and a shared outage.
105+
106+
Three requirements follow, and R3.3 is the one worth arguing about:
107+
108+
- **R3.1** — the claimed-ending gate from `isOurs` applies here identically.
109+
`google.com` has two labels exactly like `blue.eggs`; only an ending someone
110+
has actually claimed is ours. An unknown ending set means *not* ours.
111+
- **R3.2** — forwarded answers are relayed unmodified. No injected records, no
112+
rewritten NXDOMAIN, no "helpful" search page. The moment a resolver edits
113+
answers it is spyware with a nice landing page.
114+
- **R3.3****no query logging beyond aggregate counters.** No per-query
115+
storage of name, source address, or the pair. This is the requirement that
116+
will be under pressure the first time someone asks "which endings are people
117+
looking up?" — and the honest answer is that we cannot know without becoming
118+
the thing the local bridge exists to avoid. Counters (queries/sec, hit rate,
119+
error rate) are fine. The tuple is not.
120+
121+
### R4 — Say the cost before the click
122+
123+
`/pit/dns` publishes the addresses. It must also state, in the same visual
124+
weight as the addresses themselves:
125+
126+
> This resolver sees every DNS lookup your device makes, not just Moshpit ones.
127+
> If you can run `moshcode dns enable`, do that instead — it keeps your lookups
128+
> on your own machine.
129+
130+
A page that lists an IP with no context gets pasted into a router by someone who
131+
has not thought about it. That is the failure mode to design against.
132+
133+
### R5 — Reuse the bridge, do not fork it
134+
135+
The hosted resolver is the same code as `src/dns.mjs` with upstreams
136+
configured, deployed. The forwarding, the ending gate, the NODATA/NXDOMAIN
137+
distinction and the AAAA support all already exist and are tested. A second
138+
implementation would drift from the first, which is the failure this codebase
139+
has already had five times over with one regex.
140+
141+
### R6 — Never the default
142+
143+
Nothing in `moshcode dns enable`, the CLI, or the extension silently points at
144+
the hosted resolver. It is a documented address a person chooses to use. A
145+
resolver that installs itself as your DNS without asking is malware behaviour
146+
regardless of intent.
147+
148+
## UX Notes
149+
150+
`/pit/dns` already renders `.pit-addrs` cards for published resolvers, so the
151+
page work is mostly copy plus the DoH URL. The order should be:
152+
153+
1. **`moshcode dns enable`** — recommended, keeps lookups local
154+
2. **`pit.moshcode.sh/n/<name>`** — works with nothing installed, URL changes
155+
3. **the hosted resolver** — for devices that cannot do (1), with R4's warning
156+
157+
Today the page has only (1) and publishes nothing for (3).
158+
159+
## Success Metrics
160+
161+
- A stock phone, given only a DoH profile, loads `http://chovy.hacker/` with
162+
`chovy.hacker` in the URL bar.
163+
- Resolver p50 latency for a forwarded (non-Moshpit) query stays within ~10ms of
164+
the device's previous resolver, or the tax is visible enough that people turn
165+
it off.
166+
- Zero per-query records in storage, demonstrable from the deployment config
167+
rather than from a policy document.
168+
169+
## Risks & Open Questions
170+
171+
**The privacy tradeoff is not fixable, only disclosed.** Anyone using this hands
172+
us their full DNS history. R3.3 and R4 are mitigations, not solutions. If that
173+
is unacceptable, the honest outcome is to not ship this and leave `/n/` as the
174+
answer for phones.
175+
176+
**Shared outage.** A device with this as its only DNS server loses the whole
177+
internet when we go down, not just Moshpit names. R2 exists for this and may
178+
well be the reason to delay.
179+
180+
**Abuse.** An open forwarding resolver is a DDoS amplifier. Rate limiting and
181+
response-size limits are required before anything is published, and this is not
182+
optional or deferrable — an open resolver is found by scanners in hours.
183+
184+
**Does the demand exist?** The cheapest version of this experiment is to publish
185+
nothing and instead measure how often `/n/` is loaded from mobile user agents.
186+
If nobody is meeting Moshpit names on phones, this is infrastructure and risk
187+
bought for an audience that is not there.
188+
189+
**Open:** does the ending gate consult the registry per query, or hold a cached
190+
ending set refreshed on an interval? Per query is simpler and always current;
191+
cached is faster and survives a registry outage. The local bridge faces the same
192+
choice and has not resolved it either.

0 commit comments

Comments
 (0)