Repository navigation
Releases: fr34aky/fips-pub-domains
Release list
fips-pub-domains 0.2.6
Changed
-
With
plain_probe: false(and for aTxtSourcewith no probe) the
validated lookup releases the legacy answer on the first upstream's
"no record", as the probe does (TxtSource::lookup_with); the decision
still waits for every upstream, validated answers outranking the rest.
Before, the setting also gave up the early release. -
The daemon polls a lookup once before fetching the legacy answer
alongside it: a name whose decision is cached (or that is not a
hostname, or asks for a record type that is never over fips) is
answered without a parallel upstream query.
Added
pubdom_core::unavailable_ttl(retry_in): the TTL cap for the legacy
answer of an unavailable name, for every host to share.
fips-pub-domains 0.2.5
Changed
- A bound name whose servers do not answer, with no zone record (or a
target node that answers no echo), now ends in
LookupResult::Unavailable { retry_in }: the daemon hands out the
legacy answer with its TTLs capped at the time to the next attempt
(at least 5 s) instead of the upstream's, and a failed server is
retried after 20 s instead of 5 minutes (still tripling per failure up
to 3 hours). A node that just joined the mesh has no session to the
server yet, so its first lookup used to fail step 3 and the
application kept the legacy address for minutes; a server down for
hours, on the other hand, does not make the application ask every few
seconds. A target node the local node could not register is
remembered for 30 s, like a failed echo.
fips-pubdom lookupprints the case. Library hosts must match the new
variant (fips2go: map it to the short-lived legacy answer).
Added
plain_probe: false(daemon config,ResolverConfig::plain_probe)
turns the plain probe of 0.2.4 off: every_fips-dnslookup is
validated again, so a forged "no record" for a signed domain sends a
first visit to the mesh relays instead of the legacy answer — at the
cost of a validated denial per first lookup of an ordinary name.
Defaulttrue, unchanged behaviour.
fips-pub-domains 0.2.4
Changed
-
The first lookup of an ordinary name no longer waits for a DNSSEC
proof that it has no_fips-dnsrecord. A domain with no pin is asked
plainly first, every candidate domain and every upstream at once; the
validated lookup runs only where a record exists. The daemon fetches
the legacy answer alongside and hands it out — short-lived, 5 s — as
soon as one upstream has denied the record for every domain the name
could belong to; the decision waits for the others and is cached.
Measured on the reference machine: 0.5–1 s per first lookup before;
after, a median of 171 ms where the first upstream alone takes 54 ms —
what is left is mostly that upstream answering the forwarded query.
An answer released early is asked for again by the stub after its 5 s.
Pinned domains are still validated every time: forgetting a pin takes
a denial as strong as the pin. The price: on a first visit, a forged
plain "no record" now ends the lookup with the legacy answer, where a
forged denial of a signed domain used to fail validation and send the
resolver to the mesh relays, which could still bind the domain from
the claim's DNSSEC proof or from attestations.TxtSource::probeandResolver::denied_by_an_upstreamare the
library side; aTxtSourcewithout a probe behaves as before. -
MaybeTxt::set_timeout: a host that knows the Internet is gone can
shorten the TXT lookup's wait (the phone does, from Android's network
validation) so a first offline lookup fails into the mesh path within
its budget — rather than skip the lookup, which would also skip it on a
network that works but was never validated. -
On the resolved and NetworkManager backends the daemon follows its
upstreams file as the resolver rewrites it, so a network change is
picked up within a second instead of at the next 30 s poll (kept as
the fallback, which also sets the watch up late if the directory did
not exist at start). The directory is watched, since both resolvers
rename a new file into place.
Fixed
-
A daemon that started before the network had upstreams answered
SERVFAIL until the next 30 s poll — at boot, half a minute of "site not
available". A query that finds no upstreams now re-reads the upstreams
file first. -
A key that claims a domain is no witness for it: its attestations no
longer count toward k, for itself or for a sibling server. With
witnesses drawn from the nodes a client knows (the phone's Mesh names),
the servers themselves are routinely on the list, and a claim vouched
for by its author — or two claimants vouching for each other — would
have been its own proof.fips-pubdom attestrefuses to run from a
key that claims the domain, andverifymarks such attestations. -
The daemon's upstreams and
setup's snapshot readresolv.confas
glibc does: anameserverline must start the line and be followed by a
space or tab, and the address ends at;or#. An indented line, which
the system resolver ignores, no longer becomes an upstream. The dnsmasq
backend reads dnsmasq's resolv file as dnsmasq does, indented lines
included.
fips-pub-domains 0.2.3
Added
-
fips-pubdomd setupon Linux beyond systemd-resolved: NetworkManager
without resolved (dns=nonedrop-in, the daemon on port 53 in
resolv.conf, NM's own server list followed for the upstreams), a
standalone dnsmasq (no-resolvandserver=to the daemon, the servers
of its resolv file snapshotted), and a plainresolv.conf(the daemon on
port 53, the previousnameserverlines snapshotted; refused when
something else manages the file).--backend auto(the default) detects
the arrangement,setuprecords it, andteardownundoes the recorded
one without being told, restoring resolv.conf and the config to what
they were. The NetworkManager backend is verified live. -
Attestations (kind 37198, spec §3.2, phase 3): a client lists the
witnesses it trusts (witnesses,attestation_thresholdin the config)
and, offline, resolves a domain it has no pin and no proof for once k
of them attest a server; the binding is pinned asattested, the
weakest method, and replaced by the next online verification. Only the
configured witnesses' events are fetched, from mesh relays only, and a
verification older than 30 days does not count.fips-pubdom attest <domain> --key …makes a node a witness: it verifies the record online (DNSSEC
or two agreeing resolvers) and publishes one attestation naming the
domain's servers;fips-pubdom attestations <domain>shows what the
witnesses published, andverifylists them with the decision.
fips-pub-domains 0.2.2
Fixed
- A lookup that overran its budget left the application on the legacy
address for the upstream record's whole TTL: on the phone, a parked
wildcard's 300 s maderelay.example.orglook as if it never resolved
over fips. The legacy answer forwarded during an overrun now carries TTLs
of at most 5 s (OVERRUN_TTL_SECS,synth::clamp_ttls), and the daemon
lets the overrunning lookup finish in the background, as the phone
already did, so the stub's next query is answered from its decision. - Cold lookups paid the full 2 s relay timeout whenever one relay in the
pool stayed quiet, because the fetch waited for every relay's EOSE. Each
relay is now asked on its own subscription; after a TXT hit, once one
has delivered a claim the others get 750 ms, then the fetch returns.
Offline every relay is still heard, so a conflict between claims stays
visible.
Added
- docs/operators.md: how to remove a server from a domain — in which order,
and why its claim must be published once more without a DNSSEC proof
(hosters that re-sign a changed record with the same signature date
otherwise leave offline clients with two proofs they cannot order).
fips-pub-domains 0.2.1
Fixed
- The
fips-pubdom-serversystemd unit never started: systemd expands
%sinExecStartto the service user's shell and$zitself, so the
server was told to load a zone file named/bin/sh. The command no
longer needs a specifier and escapes the shell's variables; zone paths
may contain spaces, relay URLs are not glob-expanded, and with no zone
file the unit stops once instead of restarting forever. Existing
installs must copy the unit again (sudo install -m644 packaging/systemd/fips-pubdom-server.service /etc/systemd/system/ && sudo systemctl daemon-reload); the upgrade steps in docs/install.md
now include this.
Changed
- The server unit runs as an unprivileged dynamic user in group
fips
instead of root.
fips-pub-domains 0.2.0
Fixed
- A pinned server that the TXT record no longer names is now unpinned even
when the claim of the server it names instead did not reach us (with a
record as strong as the pin, as before). It used to stay pinned and
answer the next offline lookup. - The failover backoff now actually grows (5 min, 15, 45, … up to 3 h); a
server that stayed down was retried every 5 minutes. - A name answered by its domain server itself no longer needs an ICMPv6
echo for the record types that follow from the cache; where echo is
blocked, A went to the public address while AAAA went to the mesh. The
answer counts as proof for two minutes; after that the server is asked
again instead of pinged, and only if that fails is the node pinged. - Only address types (A, AAAA, ANY, CNAME) of a bound name go over fips,
and HTTPS/SVCB get NODATA; MX, TXT, SRV and every other type stay legacy
DNS. Under a wildcard zone they were answered empty, which broke mail
and SPF lookups from machines running the daemon. - Upstream resolvers that disagree on the
_fips-dnsrecord: once any
answer validated, only validated answers count (a validated denial
included), so a forged or stale unsigned answer cannot outvote a signed
zone; a tie is no longer broken by list order but treated as disputed —
pins keep resolving, an unpinned domain stays legacy and is asked again a
minute later. - DNSSEC status was judged from single records: a TXT denial counted as
validated whenever its SOA did, and a record whenever any TXT record did.
For an unsigned domain, one bad upstream could then fake a validated
answer — replaying the TLD's signed SOA or opt-out NSEC3, or putting an
unvalidated CNAME in front of a signed name — and bind an attacker's key
at DNSSEC strength or unpin every server. Answers are now judged as a
whole, and a validated denial must be for the name asked and proven by a
validated NSEC/NSEC3 without opt-out. - A denial from a signed zone using more NSEC3 iterations than the
validator accepts (insecure by RFC 9276) counted as a failed upstream,
sending the domain down the offline path; it is an unvalidated denial.
Every form of answer that fails DNSSEC validation counts like no answer,
and is logged as such. - Re-verifying an unchanged binding no longer rewrites the pin file and
logs "binding verified and pinned" each time. - The reachability echo could panic on a scheduling delay; the daemon's
and server's socket loops spun at full CPU on a persistent error. fips-pubdom-serversaid "Invalid secret key" when the key file merely
could not be read (afips.keywith mode 600 and a user outside the
fipsgroup); it now says so, and also accepts a 32-byte raw key file.
Changed
ProofVerifier::verifytakes the time to check signatures at.
Removed
ResolverConfig.upstreams(never read), and with it the argument of
Config::resolver_config. fips2go sets the field and drops that line at
its next pin bump.
Added
-
DNSSEC proofs in claims (spec §3.1, §5.5): for a DNSSEC-signed
domain,fips-pubdom-serverattaches the signed_fips-dnsTXT record
and its DNSKEY/DS chain to the root to the claim, checks it as a client
would, and re-publishes before the signatures expire (halfway through the
remaining validity, every 24 h at the latest). A client with no pin and
no DNS — only a relay on the mesh — verifies the domain from the proof
alone against the built-in root keys, and pins it asdnssec; the newest
proven record decides which claims are servers. If collecting the chain
fails, the server keeps the last one while it is valid (after a restart,
from its own claim on the relays) and retries hourly; once the record no
longer names the server's key, the claim goes out without a proof.--dnspicks the resolvers the chain is
collected from,--no-dnssec-proofturns it off,dnssec: falseon the
client ignores proofs.fips-pubdom verifyshows each claim's proof. -
Redundant servers (spec §5.3): every key the TXT record names and
that claims the domain is pinned as a server; step 3 asks them in pin
order, fails over when one does not answer, and retries a failed server
after a backoff (5 min, tripling per failure, at most 3 h). Zone records
from any pinned server are accepted.fips-pubdom verifyandpins list
show the whole set. The pin file's format is unchanged — it was already a
list; a file from before simply has one server per domain. -
Zone records (kind 37199, spec §3.3): the domain server publishes the
names it serves next to its claim — at start, every 24 h, and whenever a
zone file changes — and a client whose step 3 gets no answer from the
server resolves the name from that record instead, so names pointing at
other nodes keep working while the domain's server is down. Every target
reached this way has to answer an echo, the server's own node included.
fips-pubdom zone <domain>shows the record;publish --dry-runprints
both events.
fips-pub-domains 0.1.0
Added
- The protocol (docs/spec.md): a signed Nostr claim
(kind 37197, placeholder) binds a domain to the fips node that serves it;
a_fips-dns.<domain>TXT record verifies the binding, DNSSEC when the
zone is signed; names under the domain are asked of that node over the
mesh as ordinary DNS and answeredCNAME <npub>.fips.; the application
gets the node'sfd…address with the public addresses suppressed.
Verified bindings are pinned and keep resolving offline. Unverified
claims are refused. Relays are asked about a domain only after its TXT
record vouched for it, or offline — then relays on the mesh first. pubdom-core: the policy with no I/O — identities and mesh addresses,
Public Suffix List rules, the TXT record, claims and zone records with
size limits, pins with an anti-rollback table, the verification
precedence and the offline path, DNS synthesis.pubdom-resolve: the TXT verifier (one hickory resolver per upstream,
agreement counted; DNSSEC validation), the relay client with public and
mesh relay sets, the mesh transport trait with a kernel implementation
(UDP, TCP on truncation, ICMPv6 echo as the reachability check), the JSON
pin file, and the resolver with per-domain and per-name single-flight.fips-pubdom-server: the domain's mesh DNS server on the node's fips
address (default port 5355) from a hot-reloaded zone file withself,
legacyand wildcard entries; publishes the claim and prints the TXT
record to add.fips-pubdomd: the desktop resolver in front of all DNS,setup/
teardownfor systemd-resolved (a drop-in that resets the global pool;
.fipsforwarded to fips's responder), upstreams followed through
/run/systemd/resolve/resolv.conf, a warning when a link search domain
would shadow bound names.fips-pubdom:lookup,verify(every input to a decision),claims,
pins.- Android: the same library crates inside fips2go's VPN DNS proxy, with
the mesh query and the echo over a smoltcp stack (fips2go PR #55). - Packaging: systemd units, the fips firewall drop-in.
- Documentation: spec, NIP draft, architecture, install, operator and
daemon guides, Android, platforms, the live test ladder with its
results, roadmap, design history.