@push.rocks/smartdns 8.2.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.smartconfig.json +10 -4
  2. package/dist_rust/rustdns-client_linux_amd64_musl +0 -0
  3. package/dist_rust/rustdns-client_linux_amd64_musl.tsrust-build.json +14 -0
  4. package/dist_rust/{rustdns-client_linux_arm64 → rustdns-client_linux_arm64_musl} +0 -0
  5. package/dist_rust/rustdns-client_linux_arm64_musl.tsrust-build.json +14 -0
  6. package/dist_rust/rustdns_linux_amd64_musl +0 -0
  7. package/dist_rust/rustdns_linux_amd64_musl.tsrust-build.json +14 -0
  8. package/dist_rust/rustdns_linux_arm64_musl +0 -0
  9. package/dist_rust/rustdns_linux_arm64_musl.tsrust-build.json +14 -0
  10. package/dist_ts/00_commitinfo_data.js +1 -1
  11. package/dist_ts_client/classes.rustdnsclientbridge.js +4 -1
  12. package/dist_ts_server/classes.dnsserver.d.ts +24 -1
  13. package/dist_ts_server/classes.dnsserver.js +391 -3
  14. package/dist_ts_server/classes.manageddnsserver.d.ts +34 -0
  15. package/dist_ts_server/classes.manageddnsserver.js +141 -0
  16. package/dist_ts_server/classes.rustdnsbridge.d.ts +31 -1
  17. package/dist_ts_server/classes.rustdnsbridge.js +34 -13
  18. package/dist_ts_server/index.d.ts +2 -0
  19. package/dist_ts_server/index.js +3 -1
  20. package/dist_ts_server/interfaces.managed.d.ts +79 -0
  21. package/dist_ts_server/interfaces.managed.js +2 -0
  22. package/dist_ts_server/plugins.d.ts +4 -1
  23. package/dist_ts_server/plugins.js +5 -2
  24. package/notices/cargo-dependencies.html +3412 -0
  25. package/notices/cfg_aliases-0.2.1-license.txt +9 -0
  26. package/notices/cfg_aliases-0.2.1-notices.txt +26 -0
  27. package/notices/compiler-builtins-license.txt +275 -0
  28. package/notices/fiat-crypto-0.2.9-copyright.txt +7 -0
  29. package/notices/group-0.13.0-copyright.txt +14 -0
  30. package/notices/inventory.json +1290 -0
  31. package/notices/llvm-libunwind-license.txt +311 -0
  32. package/notices/lru-slab-0.1.2-license.txt +7 -0
  33. package/notices/musl-copyright.txt +193 -0
  34. package/notices/quinn-0.11.9-license.txt +7 -0
  35. package/notices/quinn-proto-0.11.13-license.txt +7 -0
  36. package/notices/quinn-udp-0.5.14-license.txt +7 -0
  37. package/notices/rand-0.8.5-copyright.txt +12 -0
  38. package/notices/rand-0.9.2-copyright.txt +12 -0
  39. package/notices/rand_chacha-0.3.1-copyright.txt +12 -0
  40. package/notices/rand_chacha-0.9.0-copyright.txt +12 -0
  41. package/notices/rand_core-0.6.4-copyright.txt +12 -0
  42. package/notices/rand_core-0.9.5-copyright.txt +12 -0
  43. package/notices/ring-0.17.14-fiat-license.txt +15 -0
  44. package/notices/ring-0.17.14-license-boringssl.txt +272 -0
  45. package/notices/ring-0.17.14-license-other-bits.txt +13 -0
  46. package/notices/ring-0.17.14-license.txt +9 -0
  47. package/notices/ring-0.17.14-once-cell-license-apache.txt +201 -0
  48. package/notices/ring-0.17.14-once-cell-license-mit.txt +23 -0
  49. package/notices/ring-0.17.14-source-attributions.txt +1544 -0
  50. package/notices/rust-standard-library.html +8266 -0
  51. package/notices/rustc-hash-2.1.1-license.txt +23 -0
  52. package/notices/thiserror-2.0.18-license.txt +23 -0
  53. package/notices/thiserror-impl-2.0.18-license.txt +23 -0
  54. package/notices/tinyvec-1.10.0-license.txt +5 -0
  55. package/notices/tinyvec_macros-0.1.1-license.txt +21 -0
  56. package/notices/utf8_iter-1.0.4-copyright.txt +42 -0
  57. package/notices/valuable-0.1.1-license.txt +25 -0
  58. package/notices/web-time-1.1.0-license.txt +21 -0
  59. package/notices/zerocopy-derive-0.8.39-license.txt +26 -0
  60. package/package.json +16 -6
  61. package/readme.md +198 -1
  62. package/third-party-notices.md +96 -0
  63. package/ts/00_commitinfo_data.ts +1 -1
  64. package/dist_rust/rustdns-client_linux_amd64 +0 -0
  65. package/dist_rust/rustdns-client_linux_amd64.tsrust-build.json +0 -14
  66. package/dist_rust/rustdns-client_linux_arm64.tsrust-build.json +0 -14
  67. package/dist_rust/rustdns_linux_amd64 +0 -0
  68. package/dist_rust/rustdns_linux_amd64.tsrust-build.json +0 -14
  69. package/dist_rust/rustdns_linux_arm64 +0 -0
  70. package/dist_rust/rustdns_linux_arm64.tsrust-build.json +0 -14
  71. package/readme.hints.md +0 -290
  72. /package/{license → license.md} +0 -0
@@ -1,14 +0,0 @@
1
- {
2
- "format": "tsrust.build-provenance.v2",
3
- "binarySha256": "b2d37952a49874fc35b8ee7bdd5d4c794458dd93e1f2c315425351aa111f2c49",
4
- "buildInfo": {
5
- "projectName": "@push.rocks/smartdns",
6
- "projectVersion": "8.2.0",
7
- "gitCommit": "f3f7861802c8b26d517dd454add13e1bb0909c7b",
8
- "gitDirty": false,
9
- "builtAt": "2026-08-22T20:55:25.226Z",
10
- "tsrustVersion": "1.10.0",
11
- "binary": "rustdns",
12
- "target": "linux_arm64"
13
- }
14
- }
package/readme.hints.md DELETED
@@ -1,290 +0,0 @@
1
- # smartdns - Implementation Hints
2
-
3
- ## Architecture Overview
4
-
5
- The smartdns library is structured into three main modules:
6
-
7
- 1. **Client Module** (`ts_client/`) - DNS client functionality
8
- 2. **Server Module** (`ts_server/`) - DNS server with Rust backend
9
- 3. **Main Module** (`ts/`) - Re-exports both client and server
10
- 4. **Rust Module** (`rust/`) - High-performance DNS server binary
11
-
12
- ## Rust Backend Architecture (v8.0+)
13
-
14
- The DNS server's network I/O, packet parsing/encoding, and DNSSEC signing run in Rust.
15
- TypeScript retains handler registration, ACME orchestration, and the public API.
16
-
17
- ### Rust Crate Structure
18
- - `rustdns` - Main binary with IPC management loop (`--management` flag)
19
- - `rustdns-protocol` - DNS wire format parsing/encoding, record types
20
- - `rustdns-server` - Async UDP + HTTPS DoH servers (tokio, hyper, rustls)
21
- - `rustdns-dnssec` - ECDSA P-256 / ED25519 key generation and RRset signing
22
-
23
- ### IPC Flow
24
- ```
25
- DNS Query -> Rust (UDP/HTTPS) -> Parse packet
26
- -> Try local resolution (localhost)
27
- -> If handler needed: emit "dnsQuery" event to TypeScript
28
- -> TypeScript runs minimatch handlers and authorizes DNSKEY, sends "dnsQueryResult" back
29
- -> Rust builds response, signs DNSSEC if requested, sends packet
30
- ```
31
-
32
- ### Key Files
33
- - `ts_server/classes.rustdnsbridge.ts` - TypeScript IPC bridge wrapping smartrust.RustBridge
34
- - `ts_server/classes.dnsserver.ts` - DnsServer class (public API, delegates to Rust bridge)
35
- - `rust/crates/rustdns/src/management.rs` - IPC management loop
36
- - `rust/crates/rustdns/src/resolver.rs` - DNS resolver with callback support
37
-
38
- ## Client Module (Smartdns class)
39
-
40
- ### Key Features:
41
- - DNS record queries (A, AAAA, TXT, MX, etc.)
42
- - Support for multiple DNS providers (Google DNS, Cloudflare)
43
- - DNS propagation checking with retry logic
44
- - DNSSEC verification support
45
- - Both HTTP-based (DoH) and Node.js DNS resolver fallback
46
-
47
- ### Implementation Details:
48
- - Uses Cloudflare's DNS-over-HTTPS API as primary resolver
49
- - Falls back to Node.js DNS module for local resolution
50
- - Implements automatic retry logic with configurable intervals
51
- - Properly handles quoted TXT records and trailing dots in domain names
52
-
53
- ### Key Methods:
54
- - `getRecordsA()`, `getRecordsAAAA()`, `getRecordsTxt()` - Type-specific queries
55
- - `getRecords()` - Generic record query with retry support
56
- - `checkUntilAvailable()` - DNS propagation verification
57
- - `getNameServers()` - NS record lookup
58
- - `makeNodeProcessUseDnsProvider()` - Configure system DNS resolver
59
-
60
- ## Server Module (DnsServer class)
61
-
62
- ### Key Features:
63
- - Full DNS server supporting UDP and HTTPS (DoH) protocols
64
- - DNSSEC implementation with multiple algorithms
65
- - Dynamic handler registration for custom responses
66
- - Let's Encrypt integration for automatic SSL certificates
67
- - Wildcard domain support with pattern matching
68
-
69
- ### DNSSEC Implementation:
70
- - Supports ECDSA (algorithm 13), ED25519 (algorithm 15), and RSA (algorithm 8)
71
- - Automatic DNSKEY and DS record generation
72
- - RRSIG signature generation for authenticated responses
73
- - Key tag computation following RFC 4034
74
-
75
- ### Let's Encrypt Integration:
76
- - Automatic SSL certificate retrieval using DNS-01 challenges
77
- - Dynamic TXT record handler registration for ACME validation
78
- - Certificate renewal and HTTPS server restart capability
79
- - Domain authorization filtering for security
80
-
81
- ### Handler System:
82
- - Pattern-based domain matching using minimatch
83
- - Support for all common record types
84
- - **Multiple Handler Support**: As of v7.4.2+, multiple handlers can contribute records of the same type
85
- - Handler chaining for complex scenarios
86
- - Automatic SOA response for unhandled queries
87
-
88
- ### Multiple Records Support (v7.4.2+):
89
- - Server now processes ALL matching handlers for a query (previously stopped after first match)
90
- - Enables proper multi-NS record support for domain registration
91
- - Supports round-robin DNS with multiple A/AAAA records
92
- - Allows multiple TXT records (SPF, DKIM, domain verification)
93
- - Each handler contributes its record to the response
94
-
95
- ## Key Dependencies
96
-
97
- - `dns-packet`: DNS packet encoding/decoding (wire format, used by TS fallback path)
98
- - `acme-client`: Let's Encrypt certificate automation
99
- - `minimatch`: Glob pattern matching for domains
100
- - `@push.rocks/smartrust`: TypeScript-to-Rust IPC bridge
101
- - `@tsclass/tsclass`: Type definitions for DNS records
102
-
103
- ## Testing Insights
104
-
105
- The test suite demonstrates:
106
- - Mock ACME client for testing Let's Encrypt integration
107
- - Self-signed certificate generation for HTTPS testing
108
- - Unique port allocation to avoid conflicts
109
- - Proper server cleanup between tests
110
- - Both UDP and HTTPS query validation
111
-
112
- ## Common Patterns
113
-
114
- 1. **DNS Record Types**: Internally mapped to numeric values (A=1, AAAA=28, etc.)
115
- 2. **Error Handling**: Graceful fallback and retry mechanisms
116
- 3. **DNSSEC Workflow**: Zone → Key Generation → Signing → Verification
117
- 4. **Certificate Flow**: Domain validation → Challenge setup → Verification → Certificate retrieval
118
-
119
- ## Performance Considerations
120
-
121
- - Client implements caching via DNS-over-HTTPS responses
122
- - Server can handle concurrent UDP and HTTPS requests
123
- - DNSSEC signing is performed on-demand for efficiency
124
- - Handler registration is O(n) lookup but uses pattern caching
125
-
126
- ## Security Notes
127
-
128
- - DNSSEC provides authentication but not encryption
129
- - DoH (DNS-over-HTTPS) provides both privacy and integrity
130
- - Let's Encrypt integration requires proper domain authorization
131
- - Handler patterns should be carefully designed to avoid open resolvers
132
-
133
- ## Recent Improvements (v7.4.3)
134
-
135
- 1. **DNSSEC RRset Signing**: Fixed to properly sign entire RRsets together instead of individual records
136
- 2. **SOA Record Serialization**: Implemented proper SOA record encoding for DNSSEC compatibility
137
- 3. **Configurable Primary Nameserver**: Added `primaryNameserver` option to customize SOA mname field
138
-
139
- ## Recent Improvements (v7.4.8)
140
-
141
- 1. **MX Record DNSSEC Support**: Implemented MX record serialization for DNSSEC signing
142
- - MX records consist of a 16-bit preference value followed by the exchange domain name
143
- - Properly serializes both components for DNSSEC signature generation
144
- - Enables mail exchange records to be authenticated with DNSSEC
145
-
146
- ## Authority Model (server)
147
-
148
- Authority comes from **configuration**, never from the presence of a handler.
149
-
150
- - `authoritativeZones` is the single source of truth for the `aa` bit. Omission
151
- falls back to `[dnssecZone]`; an explicit empty array means no authority.
152
- `setAuthoritativeZones()` validates and copies a replacement set synchronously,
153
- so listeners stay up while subsequent queries see the new authority.
154
- - DNSKEY queries for `dnssecZone` cross the TypeScript query callback before
155
- Rust synthesizes the signed RRset. This keeps built-in DNSSEC answers inside
156
- the same live authority boundary; an empty set cannot leak an authoritative
157
- DNSKEY answer from the fixed Rust configuration.
158
- - `registerHandler(pattern, types, handler, options?)` takes
159
- `options.authority`:
160
- - `'authoritative'` (default) — the handler only contributes for names inside
161
- a configured zone. A match outside every zone is **suppressed**, not
162
- answered, and reported on the `refused` event. A registration that cannot
163
- match any configured zone also logs a warning once, at registration time.
164
- - `'non-authoritative'` — the handler may answer any matching name, but the
165
- response never carries `aa` and is never DNSSEC-signed. This is the mode
166
- for split-horizon / private-route overlays.
167
- - `aa` is a per-message flag, so a single non-authoritative contribution
168
- downgrades the whole response.
169
-
170
- Why this matters: before v8, registering a handler *was* the public claim of
171
- authority. A private-route overlay registered for a domain delegated elsewhere
172
- made the public nameserver answer with `aa` and an RFC1918 address, while
173
- refusing every other query type for the same name. Both halves came from the
174
- same defect — two disagreeing sources of truth.
175
-
176
- ### Response outcomes
177
-
178
- `TDnsQueryResponseKind` maps one-to-one onto the wire:
179
-
180
- | kind | rcode | `aa` | authority section |
181
- | --- | --- | --- | --- |
182
- | `answer` | 0 | yes | — |
183
- | `nonAuthoritativeAnswer` | 0 | no | — |
184
- | `authoritativeNegative` (NODATA) | 0 | yes | zone SOA |
185
- | `authoritativeNameError` (NXDOMAIN) | 3 | yes | zone SOA |
186
- | `refused` | 5 | no | — |
187
- | `servfail` | 2 | no | — |
188
-
189
- NXDOMAIN is only emitted when the name provably does not exist: no handler
190
- pattern matches it for any type, it is not the apex of a configured zone, no
191
- configured zone sits below it, and no handler pattern is anchored strictly
192
- below it (literal `.name` suffix, or a wildcard that matches a probe label —
193
- mid-label wildcards such as `x.*.example.com` are not fully inverted by this
194
- check and can still leave an ancestor at NXDOMAIN). The apex always exists
195
- (it answers its own SOA), and a name with covered descendants is an empty
196
- non-terminal — both get NODATA, because NXDOMAIN denies the entire subtree
197
- (RFC 8020) and a wrong one lets aggressive negative caching darken the zone.
198
- A catch-all pattern such as `'*'` therefore suppresses NXDOMAIN entirely —
199
- that is deliberate.
200
-
201
- The zone apex answers its own SOA even with no registered SOA handler; an
202
- authoritative server that cannot answer SOA for its own zone breaks negative
203
- caching and resolver heuristics.
204
-
205
- One deliberate exception to the table: RFC 6761 localhost handling (when
206
- `enableLocalhostHandling` is on) answers `localhost` A/AAAA with `aa` set even
207
- though `localhost` is outside every configured zone — special-use names are
208
- authoritative by definition, not by delegation.
209
-
210
- ## Handler Lifecycle
211
-
212
- - `registerHandler` returns an `IDnsHandlerRegistration` with a unique `id` and
213
- an `unregister()` that removes **only** that registration.
214
- - `unregisterHandlerById(id)` and `unregisterHandlersByOwner(owner)` are the
215
- precise teardown primitives; `listHandlers()` exposes the current set for
216
- leak checks.
217
- - `unregisterHandler(pattern, types)` is retained and unchanged: it still
218
- removes *every* handler matching that pattern/type pair. It cannot distinguish
219
- two consumers sharing a key — prefer the handle.
220
- - ACME authorization follows the same rule: `filterAuthorizedDomains` /
221
- `retrieveSslCertificate` admit exactly the domains inside a configured
222
- authoritative zone. Handler registrations play no part — a DNS-01 challenge
223
- for an out-of-zone domain could never validate, because its challenge TXT
224
- handler would be suppressed.
225
-
226
- ## Transport And Protocol Notes
227
-
228
- - **EDNS0**: a request carrying an OPT record always gets an OPT back
229
- (RFC 6891 6.1.1), advertising `DNS_ADVERTISED_UDP_PAYLOAD` (1232). Requests
230
- without OPT get no OPT. Client-advertised payload sizes are clamped up to 512
231
- so a hostile OPT cannot force pathological truncation.
232
- - **Truncation**: UDP responses are truncated to the client's advertised payload
233
- size with the TC bit set, so resolvers retry over TCP. Without this, oversized
234
- datagrams were emitted and silently dropped by real networks. Truncation is
235
- size arithmetic, never a re-encode per dropped record — the encoder does not
236
- compress names, so record sizes are additive (`DnsPacket::encoded_len`).
237
- `processRawDnsPacketAsync(packet, 'udp')` declares the same UDP bound for the
238
- manual path (`handleUdpMessage` passes it automatically); without the hint no
239
- size bound is applied, which is correct for TCP and DoH framing. Manual packet
240
- work runs through a bounded task set so the management loop remains available
241
- for handler callbacks and their results. The TypeScript bridge mirrors the
242
- Rust task bound by admitting at most 256 pending `processPacket` requests;
243
- excess requests fail before serialization with
244
- `ERR_RUST_BRIDGE_REQUEST_LIMIT`, while control methods remain unbounded.
245
- - **RA** is cleared on every path — this server never recurses.
246
- - **RDATA validation** fails closed: a handler returning an unencodable value
247
- (for example a non-IPv4 string for an A record) produces SERVFAIL and an error
248
- log, rather than a malformed record on the wire.
249
- - **SOA serial** is fixed for the lifetime of the server process and passed to
250
- Rust via `soaSerial`, so apex answers and negative authorities agree.
251
-
252
- ## Observability
253
-
254
- - `query` events carry `responseKind`, `authorityZone` and `suppressedHandlers`.
255
- - `refused` events fire for every refusal and every suppressed handler match,
256
- carrying the handler `id`, `domainPattern` and `owner`. Wire this up: the
257
- original incident was invisible for weeks because nothing surfaced it.
258
-
259
- ## Server Lifecycle
260
-
261
- - `start()` and `stop()` share a serialized lifecycle queue. Each caller keeps
262
- its own operation result, and a rejection does not poison later operations.
263
- - Repeated `start()` calls are idempotent at the `DnsServer` facade. Rust also
264
- rejects duplicate active `start` commands, so low-level bridge callers cannot
265
- replace listeners while detached HTTPS connection work still exists.
266
- - `stop()` awaits confirmed Rust child closure before clearing ownership and
267
- legacy server markers. A failed termination retains them so cleanup can be
268
- retried safely.
269
- - If an operation and confirmed cleanup both fail, both errors are preserved in
270
- an `AggregateError`. A failed stop command is suppressed only after process
271
- closure has been confirmed.
272
- - A server may be started again after a confirmed stop; smartrust activates a
273
- fresh process generation on the same bridge.
274
- - Packet IPC is admitted only while no lifecycle operation is queued and the
275
- facade state, ownership marker, and bridge liveness all agree. Certificate
276
- updates use the same queue so they cannot race startup or shutdown.
277
-
278
- ## Known Limitations
279
-
280
- 1. **Handler Deduplication**: If the same handler is registered multiple times, it will contribute duplicate records (this may be desired behavior for some use cases)
281
- 2. **NXDOMAIN under catch-all patterns**: see the authority model above.
282
- 3. **SOA serial does not track zone changes** — it is a process-lifetime
283
- constant, not a change counter. Secondaries driven by AXFR/IXFR are not
284
- supported.
285
- ## Static Rust Binaries
286
-
287
- - The Rust binaries in `dist_rust/` are statically linked (static-pie) via `"static": true` in the `@git.zone/tsrust` block of `.smartconfig.json` (tsrust >= 1.4.1). They run on both glibc (Debian/Ubuntu) and musl (Alpine) systems.
288
- - tsrust injects `RUSTFLAGS="-C target-feature=+crt-static"` only into its own per-target cargo invocations and verifies the result (no `PT_INTERP` ELF header). Keep `rust/.cargo/config.toml` free of `rustflags` entries: the injected env variable would replace them, and a repo-wide `rustflags` would also break plain `cargo test`/`cargo check` (proc-macros cannot build with `+crt-static` on linux-gnu without an explicit `--target`).
289
- - `pnpm run test:rust` runs the Rust unit tests; plain `cargo test` in `rust/` works as well.
290
- - Verify linkage manually with `ldd dist_rust/<binary>_linux_amd64` → "statically linked".
File without changes