Skip to content

feat: answer CNAME, MX and TXT from the record set - #10

Merged
ralyodio merged 1 commit into
mainfrom
feat/sync-bridge-from-moshcode
Aug 3, 2026
Merged

feat: answer CNAME, MX and TXT from the record set#10
ralyodio merged 1 commit into
mainfrom
feat/sync-bridge-from-moshcode

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Brings this bridge level with the registry, which can now publish four record types (moshcoder/moshcode#241) and whose own resolver already answers them (moshcoder/moshcode#242).

What was wrong

The socket gated on A/AAAA and returned an honest empty NOERROR for everything else. So an owner could publish an MX in the Pit, see it listed on their name, and get nothing from dig MX — with no way to tell a record that isn't served from one they typed wrong.

What changed

CNAME, MX and TXT are answered out of the ?records=1 the registry already exposes.

  • TXT splits at 255 bytes on byte boundaries. Long values are normal rather than exceptional — a DKIM key never fits in one string — and splitting on characters cuts a multi-byte one in half so neither piece decodes. There's a test that publishes 60 emoji and requires the value back whole.
  • MX carries its preference first, as the wire format requires.
  • A record whose rdata won't encode is dropped, not thrown. This reads JSON over HTTP from a registry that may be a different version than the bridge; one bad row must not take down the answers beside it.
  • Oversized replies are trimmed to 512 bytes and marked TC, rather than dropping every answer — this bridge speaks UDP only, so a client told to retry over TCP finds nobody home.
  • A published CNAME now answers the address question it was invisible to. A name pointed at a hostname has no address to give (targetAddress returns null for one on purpose — this bridge does not do clearnet DNS), so it was NODATA and looked exactly like a typo. The extra round trip happens only when the name is here and has no address, so a name that already resolves pays nothing.

Note the CNAME is answered only when one is actually published, not synthesized from any hostname target — that keeps the existing NODATA behaviour for a hostname or :8080 target exactly as its tests require.

Compatibility

records appears on a resolveName result only when asked for, so every existing caller sees the shape it always did. buildResponse, answerPolicy and answerFor are untouched.

This matters beyond this repo: moshcode vendors this file as src/dns.mjs and has a drift test that compares the two. Keeping these shapes stable is what lets that test stay meaningful.

Tests

14 new in test/dns-records.test.mjs, decoding rdata back off the wire rather than counting answers — an MX with its preference in the wrong order produces a reply of exactly the right shape that no client can use.

Full suite: 82/82 pass (68 existing, unchanged).

Note on versions

package.json said 0.2.1 while npm has 0.2.2 published — the repo was behind what shipped. Bumped to 0.3.0, which clears both. I have not published to npm; that's yours to run when you're happy with this.

🤖 Generated with Claude Code

The Pit publishes four record types. This bridge answered one of them: the
socket gated on A/AAAA and returned an honest empty NOERROR for everything
else, so an owner could publish an MX, see it listed on their names, and
get nothing back from `dig MX` — with no way to tell a record that is not
served from one they typed wrong.

Answered now, out of the `?records=1` the registry already exposes:

  - TXT is split into 255-byte strings on BYTE boundaries. Long values are
    normal rather than exceptional (a DKIM key never fits in one), and
    splitting on characters cuts a multi-byte one in half so neither piece
    decodes.
  - MX carries its preference first, as the wire format requires.
  - A record whose rdata will not encode is dropped rather than throwing.
    This reads JSON over HTTP from a registry that may be a different
    version than the bridge, and one bad row must not take down the
    answers beside it.
  - Oversized replies are trimmed to what fits in 512 bytes and marked
    truncated, rather than dropping every answer: this bridge speaks UDP
    only, so a client that retries over TCP finds nobody home.

A published CNAME now also answers the address question it was invisible
to. A name pointed at a hostname has no address to give, and targetAddress
returns null for one on purpose — the bridge does not do clearnet DNS — so
it was NODATA and looked exactly like a typo. Handing back the CNAME lets
the client chase it through its own resolver, which is the party that may.
That second lookup happens only when the name is here and has no address,
so a name that already resolves pays nothing for it.

`records` appears on a resolveName result only when it was asked for, so
every existing caller sees the shape it always did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio marked this pull request as ready for review August 3, 2026 08:15
@ralyodio
ralyodio merged commit e0d006e into main Aug 3, 2026
1 check passed
@ralyodio
ralyodio deleted the feat/sync-bridge-from-moshcode branch August 3, 2026 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant