dnsruby 1.74.0 → 2.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +16 -4
- data/DNSSEC +3 -2
- data/EXAMPLES +1 -1
- data/README.md +370 -64
- data/RELEASE_NOTES.md +302 -1
- data/Rakefile +0 -3
- data/demo/axfr.rb +24 -6
- data/demo/rubydig.rb +0 -2
- data/dnsruby.gemspec +5 -4
- data/lib/dnsruby/cache.rb +279 -47
- data/lib/dnsruby/code_mapper.rb +35 -8
- data/lib/dnsruby/code_mappers.rb +63 -49
- data/lib/dnsruby/config.rb +75 -4
- data/lib/dnsruby/deadline_queue.rb +75 -0
- data/lib/dnsruby/dnssec.rb +148 -45
- data/lib/dnsruby/ipv6.rb +45 -5
- data/lib/dnsruby/key_cache.rb +202 -35
- data/lib/dnsruby/message/decoder.rb +85 -19
- data/lib/dnsruby/message/encoder.rb +27 -16
- data/lib/dnsruby/message/header.rb +8 -12
- data/lib/dnsruby/message/message.rb +53 -22
- data/lib/dnsruby/message/section.rb +12 -34
- data/lib/dnsruby/name.rb +5 -2
- data/lib/dnsruby/packet_sender.rb +645 -203
- data/lib/dnsruby/presentation.rb +147 -0
- data/lib/dnsruby/query_control.rb +132 -0
- data/lib/dnsruby/recursor.rb +795 -339
- data/lib/dnsruby/resolver.rb +468 -186
- data/lib/dnsruby/resource/CAA.rb +67 -16
- data/lib/dnsruby/resource/DLV.rb +6 -0
- data/lib/dnsruby/resource/DNSKEY.rb +108 -16
- data/lib/dnsruby/resource/DS.rb +27 -28
- data/lib/dnsruby/resource/HTTPS.rb +16 -0
- data/lib/dnsruby/resource/IN.rb +19 -0
- data/lib/dnsruby/resource/MX.rb +2 -2
- data/lib/dnsruby/resource/NSEC.rb +6 -10
- data/lib/dnsruby/resource/NSEC3.rb +55 -19
- data/lib/dnsruby/resource/NSEC3PARAM.rb +4 -6
- data/lib/dnsruby/resource/RR.rb +108 -65
- data/lib/dnsruby/resource/RRSIG.rb +5 -5
- data/lib/dnsruby/resource/RRSet.rb +38 -22
- data/lib/dnsruby/resource/SRV.rb +2 -2
- data/lib/dnsruby/resource/SVCB.rb +775 -0
- data/lib/dnsruby/resource/TSIG.rb +266 -231
- data/lib/dnsruby/resource/TXT.rb +34 -42
- data/lib/dnsruby/resource/domain_name.rb +1 -1
- data/lib/dnsruby/resource/generic.rb +31 -0
- data/lib/dnsruby/resource/generic_cache.rb +384 -0
- data/lib/dnsruby/resource/generic_constants.rb +79 -0
- data/lib/dnsruby/select_thread.rb +979 -291
- data/lib/dnsruby/serial_time.rb +25 -0
- data/lib/dnsruby/single_resolver.rb +25 -6
- data/lib/dnsruby/single_verifier.rb +1620 -530
- data/lib/dnsruby/transport_clock.rb +9 -0
- data/lib/dnsruby/update.rb +8 -6
- data/lib/dnsruby/validation_budget.rb +143 -0
- data/lib/dnsruby/validator_thread.rb +139 -58
- data/lib/dnsruby/version.rb +1 -1
- data/lib/dnsruby/zone_reader.rb +196 -129
- data/lib/dnsruby/zone_transfer.rb +157 -25
- data/lib/dnsruby.rb +7 -2
- data/test/ci_watchdog.rb +33 -0
- data/test/fixtures/org-ds-2026-11-05.zone +5 -0
- data/test/fixtures/root-dnskey-2026-11-05.zone +7 -0
- data/test/fork_test_helper.rb +37 -0
- data/test/local_dns_server.rb +57 -0
- data/test/soak_server.rb +152 -0
- data/test/socket_helpers.rb +26 -0
- data/test/spec_helper.rb +8 -13
- data/test/tc_attempt_configuration.rb +137 -0
- data/test/tc_caa.rb +2 -2
- data/test/tc_cache_keys.rb +36 -0
- data/test/tc_cancelled_send_capacity.rb +158 -0
- data/test/tc_dnssec_alias_validation.rb +289 -0
- data/test/tc_dnssec_budget.rb +489 -0
- data/test/tc_dnssec_cache_bounds.rb +197 -0
- data/test/tc_dnssec_cache_lifetime.rb +615 -0
- data/test/tc_dnssec_denial_proofs.rb +285 -0
- data/test/tc_dnssec_recursion_limits.rb +186 -0
- data/test/tc_dnssec_recursor_review_fixes.rb +351 -0
- data/test/tc_dnssec_trust_anchors.rb +286 -0
- data/test/tc_dnssec_trust_races.rb +147 -0
- data/test/tc_dnssec_wildcard_proofs.rb +249 -0
- data/test/tc_ds.rb +5 -5
- data/test/tc_edns_retry_regressions.rb +255 -0
- data/test/tc_escapedchars.rb +8 -0
- data/test/tc_final_review_fixes.rb +167 -0
- data/test/tc_final_transport_contracts.rb +104 -0
- data/test/tc_generic_cache.rb +852 -0
- data/test/tc_header.rb +26 -0
- data/test/tc_ipv6.rb +120 -0
- data/test/tc_key_cache_identity.rb +382 -0
- data/test/tc_malformed_tcp.rb +712 -0
- data/test/tc_name.rb +99 -5
- data/test/tc_nameserver_bootstrap.rb +322 -0
- data/test/tc_nsec.rb +4 -45
- data/test/tc_nsec3.rb +17 -1
- data/test/tc_pipeline_retirement.rb +358 -0
- data/test/tc_pipeline_retry.rb +462 -0
- data/test/tc_pipeline_send.rb +663 -0
- data/test/tc_protocol_review_fixes.rb +95 -0
- data/test/tc_query_control.rb +90 -0
- data/test/tc_record_codec_contracts.rb +107 -0
- data/test/tc_record_regressions.rb +225 -0
- data/test/tc_recur.rb +1 -0
- data/test/tc_recursor_address_fallback.rb +169 -0
- data/test/tc_recursor_limits.rb +139 -0
- data/test/tc_release_auxiliary_fixes.rb +288 -0
- data/test/tc_release_configuration_fixes.rb +612 -0
- data/test/tc_release_dnssec_completion.rb +405 -0
- data/test/tc_release_dnssec_fixes.rb +305 -0
- data/test/tc_release_negative_cache.rb +327 -0
- data/test/tc_release_recursor_cache.rb +212 -0
- data/test/tc_release_review_transport.rb +372 -0
- data/test/tc_release_review_transport_native.rb +56 -0
- data/test/tc_release_transport.rb +906 -0
- data/test/tc_release_transport_fixes.rb +196 -0
- data/test/tc_release_zone_defaults.rb +157 -0
- data/test/tc_release_zone_ttls.rb +39 -0
- data/test/tc_res_config.rb +42 -20
- data/test/tc_res_opt.rb +21 -1
- data/test/tc_resolver.rb +21 -19
- data/test/tc_resolver_concurrency.rb +383 -0
- data/test/tc_resolver_configuration_contracts.rb +31 -0
- data/test/tc_resolver_validation.rb +211 -0
- data/test/tc_review_cache.rb +163 -0
- data/test/tc_review_code_mapper.rb +279 -0
- data/test/tc_review_control_deadlines.rb +169 -0
- data/test/tc_review_followup_transport.rb +583 -0
- data/test/tc_review_packet_contracts.rb +369 -0
- data/test/tc_review_presentation.rb +213 -0
- data/test/tc_review_record_compatibility.rb +101 -0
- data/test/tc_review_transport_fixes.rb +195 -0
- data/test/tc_review_transport_native.rb +415 -0
- data/test/tc_review_validation_priming.rb +178 -0
- data/test/tc_rr-opt.rb +5 -2
- data/test/tc_rr-unknown.rb +19 -0
- data/test/tc_rr.rb +14 -0
- data/test/tc_rrset_grouping.rb +50 -0
- data/test/tc_rrset_review_fixes.rb +58 -0
- data/test/tc_rrsig.rb +21 -1
- data/test/tc_scoped_ipv6.rb +153 -0
- data/test/tc_scoped_ipv6_select.rb +157 -0
- data/test/tc_scoped_ipv6_transport.rb +329 -0
- data/test/tc_selector_wakeup.rb +42 -0
- data/test/tc_soak.rb +118 -196
- data/test/tc_socket_helpers.rb +90 -0
- data/test/tc_supporting_lookup_limits.rb +252 -0
- data/test/tc_svcb.rb +1043 -0
- data/test/tc_svcb_signed_target.rb +145 -0
- data/test/tc_svcb_transport.rb +120 -0
- data/test/tc_tcp.rb +69 -43
- data/test/tc_tcp_pipelining.rb +95 -204
- data/test/tc_transport_fork.rb +179 -0
- data/test/tc_tsig.rb +2 -2
- data/test/tc_tsig_api.rb +251 -0
- data/test/tc_tsig_rfc8945.rb +357 -0
- data/test/tc_v2_release_dnssec.rb +442 -0
- data/test/tc_v2_release_transport.rb +304 -0
- data/test/tc_v2_zone_transfer_native.rb +58 -0
- data/test/tc_zone_reader.rb +217 -1
- data/test/tcp_pipelining_server.rb +150 -0
- data/test/ts_offline.rb +77 -6
- data/test/ts_online.rb +2 -1
- metadata +105 -10
- data/.coveralls.yml +0 -2
data/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,307 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## v2.0.0
|
|
4
|
+
|
|
5
|
+
Dnsruby 2.0 adds SVCB and HTTPS records and support for Ed25519 and Ed448 DNSSEC
|
|
6
|
+
signatures. It makes queries, TCP connections, zone transfers and DNSSEC
|
|
7
|
+
validation more reliable. It also bounds caches and validation work, updates
|
|
8
|
+
the root trust anchors, and improves performance when many queries are in
|
|
9
|
+
progress.
|
|
10
|
+
|
|
11
|
+
Most existing query code can stay as it is. Before upgrading, check the Ruby
|
|
12
|
+
requirement, TSIG settings and record persistence described below, followed by
|
|
13
|
+
any DNSSEC or timeout settings your application uses.
|
|
14
|
+
|
|
15
|
+
### Compatibility with 1.74.0
|
|
16
|
+
|
|
17
|
+
* **Ruby 3.0 or later is required.** Upgrade older Ruby installations before
|
|
18
|
+
installing Dnsruby 2.0.
|
|
19
|
+
* **TSIG now defaults to HMAC-SHA256.** If you previously omitted the algorithm
|
|
20
|
+
and your server uses HMAC-MD5, update the key on both sides or select MD5
|
|
21
|
+
explicitly: `resolver.tsig = key_name, secret, 'hmac-md5'`. Explicit MD5
|
|
22
|
+
settings still work, but MD5 is prohibited by RFC 8945 section 6. Selecting it
|
|
23
|
+
logs one warning per process at WARN level; the default log level is FATAL.
|
|
24
|
+
SHA-1 remains supported, and SHA-256 is recommended. There is no automatic
|
|
25
|
+
fallback to another algorithm. See [updating TSIG keys](README.md#updating-tsig-keys)
|
|
26
|
+
for SHA-256 settings that also work with 1.74.0.
|
|
27
|
+
* **Automatically generated record classes no longer support Marshal/YAML
|
|
28
|
+
persistence.** Unknown type/class pairs now use a cache of at most 256 classes,
|
|
29
|
+
and those classes are no longer permanent Ruby constants. Ordinary named
|
|
30
|
+
classes such as `Dnsruby::RR::IN::A` are unaffected. Records and classes your
|
|
31
|
+
application holds remain usable even after their automatic `ClassHash` entry
|
|
32
|
+
is evicted. To customise a generated class, keep the result of
|
|
33
|
+
`Dnsruby::RR.get_class(type, klass)` and use `class_eval`. For a fixed set of
|
|
34
|
+
application-defined types that needs permanent names and normal Marshal
|
|
35
|
+
behavior, call `Dnsruby::RR::Generic.create(type, klass)` before creating records. These
|
|
36
|
+
explicit registrations stay in memory: do not use them for arbitrary types
|
|
37
|
+
received from the network. The 256-class limit excludes explicit registrations
|
|
38
|
+
and objects retained by your application or the response cache.
|
|
39
|
+
* **DNSSEC uses current algorithm policy.** Resolver validation treats SHA-1
|
|
40
|
+
signing algorithms 5 and 7 as unsupported under RFC 9905. Answers relying
|
|
41
|
+
solely on them become `INSECURE`, meaning they are not protected by an
|
|
42
|
+
accepted DNSSEC chain. Explicit cryptographic verification and historical
|
|
43
|
+
record decoding remain available. DSA algorithms 3 and 6 are also
|
|
44
|
+
unsupported for validation, as required by RFC 8624. An authenticated
|
|
45
|
+
delegation with only unsupported DS algorithms or digests is insecure; a
|
|
46
|
+
mixed set still requires validation through a supported DS. Within an
|
|
47
|
+
authenticated DS set, SHA-256 takes precedence over SHA-1. `DS.from_key` now
|
|
48
|
+
defaults to SHA-256 and rejects new DS records using SHA-1 digests or signing
|
|
49
|
+
algorithms 5 or 7. RSA keys with noncanonical encodings or sizes outside the
|
|
50
|
+
protocol limits are rejected. See [DNSSEC algorithm policy](README.md#dnssec-algorithm-policy).
|
|
51
|
+
Ed25519 and Ed448 validation require version 3.0 or later of the `openssl` gem and
|
|
52
|
+
an OpenSSL provider that supports it. Otherwise it follows the same rules
|
|
53
|
+
as other unsupported algorithms.
|
|
54
|
+
* **DNSSEC validation has work and time limits.** The defaults are 64 signature
|
|
55
|
+
attempts, 100,000 work units and five seconds per answer, including queries
|
|
56
|
+
needed to follow the chain of trust. A limit raises `ValidationLimitError`,
|
|
57
|
+
a subclass of `VerifyError`; it never turns a failed validation into an
|
|
58
|
+
insecure answer. Up to four workers validate responses at once, with another
|
|
59
|
+
64 responses waiting. Applications with unusual validation workloads can
|
|
60
|
+
[adjust these limits](README.md#dnssec-validation-limits).
|
|
61
|
+
* **Recursive lookups have shared discovery limits.** A complete lookup now
|
|
62
|
+
defaults to 30 seconds, 128 transmission attempts, 256 discovery work units
|
|
63
|
+
and eight address-discovery worker threads. Supporting lookups share these
|
|
64
|
+
limits, and repeated dependencies on the same path are skipped. A shorter
|
|
65
|
+
Resolver timeout still takes precedence. Applications can configure
|
|
66
|
+
`Recursor#recursion_limits`; work or transmission exhaustion raises
|
|
67
|
+
`RecursionLimitError`. See [recursive lookup limits](README.md#recursive-lookup-limits).
|
|
68
|
+
* **Retries, failures and transfers have bounded lifetimes.** For each question,
|
|
69
|
+
RFC 9520 limits attempts to three per server address and transport, including
|
|
70
|
+
protocol retries; `retry_times` values above three are capped. Completed
|
|
71
|
+
failures are cached for one second, so an immediate repeat may return the
|
|
72
|
+
same error without a new exchange. The total `query_timeout` now includes
|
|
73
|
+
local DNSSEC validation. Reusable TCP connections close after ten idle
|
|
74
|
+
seconds by default; set `tcp_idle_timeout` to a positive number of seconds
|
|
75
|
+
to change this. Connections with outstanding queries stay open. ZoneTransfer
|
|
76
|
+
allows 30 seconds by default to read or write each complete frame; increase
|
|
77
|
+
`io_timeout` for slower transfers. Its optional `transfer_timeout` limits a
|
|
78
|
+
complete attempt with one server. See [response caching and retries](README.md#response-caching-and-retries)
|
|
79
|
+
and [zone transfer deadlines](README.md#zone-transfer-deadlines).
|
|
80
|
+
* **The default EDNS UDP payload size is 1232 bytes, down from 4096.** This
|
|
81
|
+
reduces fragmentation risk but can cause more TCP retries. Explicit sizes
|
|
82
|
+
such as 4096 still work. DNSSEC raises smaller limits to 1220 bytes, the
|
|
83
|
+
minimum in RFC 4035 section 4.1. The 1232-byte default is permitted by
|
|
84
|
+
RFC 10001 section 3.2.
|
|
85
|
+
* **SVCB and HTTPS are now parsed records.** Types 64 and 65 use their registered
|
|
86
|
+
names in text output and expose `priority`, `target` and `params`. Their
|
|
87
|
+
`data` and `rdata` readers return binary RDATA snapshots reflecting those
|
|
88
|
+
fields, and `rdlength` reports the length. To replace the data, use `data=`,
|
|
89
|
+
`rdata=` or `RR.create` with `rdata:`. The original decoded `@rdata` remains
|
|
90
|
+
available for existing callers such as JSONDNS, but this private field does
|
|
91
|
+
not track later edits. Malformed escapes are rejected. ALPN and DoC path
|
|
92
|
+
lists permit only escaped commas and backslashes at their second escape
|
|
93
|
+
layer; the `mandatory`, `port`, `ipv4hint`, `ech` and `ipv6hint` mnemonics
|
|
94
|
+
do not permit presentation escapes. Numeric `keyNNNNN` forms still accept
|
|
95
|
+
escaped wire octets. [PR #222](https://github.com/alexdalitz/dnsruby/pull/222).
|
|
96
|
+
* **Some invalid names and numeric values are now rejected.** DNS names longer
|
|
97
|
+
than 255 wire octets raise `ResolvError`, including some 256- and 257-octet
|
|
98
|
+
names previously accepted. Numeric type/class constructors and RRSIG
|
|
99
|
+
type-covered setters require values in 0–65535.
|
|
100
|
+
[PR #223](https://github.com/alexdalitz/dnsruby/pull/223).
|
|
101
|
+
* **Numeric and IPv6 text remain predictable.** Numeric spellings retain their
|
|
102
|
+
presentation on each object but no longer register global aliases or change
|
|
103
|
+
a code's preferred name. Explicit `Types.add_pair` and `Classes.add_pair`
|
|
104
|
+
aliases still work. Existing `IPv6#to_s`, `#inspect` and record presentations
|
|
105
|
+
keep their 1.74.0 output; use `IPv6#to_s_canonical` for RFC 5952 formatting.
|
|
106
|
+
* **The simpleidn range is now `>= 0.2.1`, `< 0.4.0`.** Updating from 0.2.x can
|
|
107
|
+
change Unicode-to-DNS name conversion. Check the results if your application
|
|
108
|
+
depends on exact converted names.
|
|
109
|
+
[PR #224](https://github.com/alexdalitz/dnsruby/pull/224).
|
|
110
|
+
|
|
111
|
+
Zone files now resolve relative `$ORIGIN` directives and SOA names against the
|
|
112
|
+
current origin, including names with an escaped final dot. TXT records preserve
|
|
113
|
+
UTF-8 and escaped bytes through wire encoding, and their 255-octet string limit
|
|
114
|
+
is checked before writing. ZoneReader treats nonnumeric escapes literally under
|
|
115
|
+
DNS zone-file rules, including `\n` as `n`; direct `RR::TXT.parse` and
|
|
116
|
+
`RR.create` retain their legacy C-style escapes for compatibility. Escaped
|
|
117
|
+
whitespace also works in `$ORIGIN`, MX and NSEC names.
|
|
118
|
+
DS, CDS and DLV records preserve private algorithm
|
|
119
|
+
numbers and unknown digest numbers. Name compression also keeps literal dots
|
|
120
|
+
inside labels distinct from the dots that separate labels.
|
|
121
|
+
|
|
122
|
+
### More reliable queries and transfers
|
|
123
|
+
|
|
124
|
+
* TCP pipelining handles concurrent sends, immediate replies, partial writes
|
|
125
|
+
and disconnected servers. Connection setup, writes and waiting for a pipeline
|
|
126
|
+
slot all respect the controlling query's deadline and cancellation. Malformed
|
|
127
|
+
replies no longer interrupt other queries or cause endless TCP retries.
|
|
128
|
+
UDP reads cannot block after a readiness notification, and changes to TCP
|
|
129
|
+
pipelining take effect consistently on subsequent attempts. Updating a source
|
|
130
|
+
port pool no longer briefly exposes an empty pool to concurrent sends.
|
|
131
|
+
Invalid replacements leave the previous configuration intact, and an occupied
|
|
132
|
+
port no longer prevents a send from trying the other configured ports.
|
|
133
|
+
Each attempt retains one transport configuration snapshot through connection
|
|
134
|
+
setup, reply matching and caching. Adding an explicit source port replaces
|
|
135
|
+
the default `[0]` pool; zero cannot be mixed with explicit ports.
|
|
136
|
+
A zero retry delay keeps every scheduled nameserver attempt.
|
|
137
|
+
[#155](https://github.com/alexdalitz/dnsruby/issues/155).
|
|
138
|
+
* Cancellation and timeouts wake waiting queries promptly, including while
|
|
139
|
+
validation or nameserver discovery is running. Late replies or callbacks
|
|
140
|
+
cannot complete an expired query or affect a later query that reuses its ID.
|
|
141
|
+
Once validation starts, another nameserver's reply cannot replace the accepted
|
|
142
|
+
answer. Closing a client's completion Queue no longer interrupts other
|
|
143
|
+
resolvers. After `fork`, the child uses fresh connections and query state;
|
|
144
|
+
the parent's pending work remains with the parent.
|
|
145
|
+
* Ordinary queries reject replies with the wrong ID, opcode or query/response
|
|
146
|
+
flag; `send_raw` retains its existing behavior. UDP-to-TCP fallback still
|
|
147
|
+
respects `no_tcp` and `ignore_truncation`. Retrying without optional EDNS keeps
|
|
148
|
+
the current transport, and TCP can handle a FORMERR reply without a question;
|
|
149
|
+
UDP still requires a matching question. Queries requiring local DNSSEC
|
|
150
|
+
validation keep EDNS enabled. Setting DO on an existing OPT preserves its
|
|
151
|
+
payload size, options and other flags.
|
|
152
|
+
* Hostname nameservers no longer cause recursive configuration hangs. Existing
|
|
153
|
+
queries continue while replacement nameservers are resolved, and concurrent
|
|
154
|
+
configuration changes are preserved. IPv6 link-local nameservers accept
|
|
155
|
+
interface zones such as `fe80::1%eth0`, including in `resolv.conf`. Recursive
|
|
156
|
+
discovery tries other nameservers and address families after ordinary lookup
|
|
157
|
+
failures, within the same cancellation and validation limits. A Recursor
|
|
158
|
+
honors the transport and source settings of its supplied Resolver and applies
|
|
159
|
+
its query timeout to the complete lookup. Changes to DNSSEC root hints take
|
|
160
|
+
effect on subsequent lookups. Root hints are also refreshed when all their
|
|
161
|
+
cached addresses expire, including during a lookup. Root NS TTLs separately
|
|
162
|
+
bound bootstrap reuse, partial priming replies trigger discovery of missing
|
|
163
|
+
root addresses, and zero-TTL priming addresses remain usable by their current
|
|
164
|
+
lookup. Ancestor lookup preserves escaped label boundaries and relative names.
|
|
165
|
+
[#179](https://github.com/alexdalitz/dnsruby/issues/179),
|
|
166
|
+
[#184](https://github.com/alexdalitz/dnsruby/issues/184),
|
|
167
|
+
[PR #221](https://github.com/alexdalitz/dnsruby/pull/221).
|
|
168
|
+
* A SingleResolver keeps only its selected server after initialization and
|
|
169
|
+
later `server=` changes. A Resolver with `retry_times = 0` completes with
|
|
170
|
+
a timeout immediately instead of leaving an empty retry plan waiting.
|
|
171
|
+
* Zone transfers complete partial writes, check response envelopes and require
|
|
172
|
+
matching opening and closing SOAs. TSIG transfers authenticate the whole
|
|
173
|
+
sequence, permit up to 99 unsigned messages between signatures and reject
|
|
174
|
+
decreasing signed timestamps. Reusing a ZoneTransfer gives each request a
|
|
175
|
+
fresh signing time unless one was set explicitly.
|
|
176
|
+
|
|
177
|
+
### Authentication, DNSSEC and caching
|
|
178
|
+
|
|
179
|
+
* Positive answers are kept separate for different upstream servers, ports,
|
|
180
|
+
source settings and query options. Truncated replies are not cached. A
|
|
181
|
+
recursor follows one delegation that encloses the question and still accepts
|
|
182
|
+
valid sibling glue from the parent zone.
|
|
183
|
+
|
|
184
|
+
* TSIG queries always require a fresh authenticated exchange and bypass the
|
|
185
|
+
shared response cache. Unsigned replies and invalid MACs are ignored while
|
|
186
|
+
waiting for a valid reply; if none arrives, the timeout reports the
|
|
187
|
+
authentication error. Authenticated BADTIME and BADTRUNC replies report the
|
|
188
|
+
server's error. Queries are prepared before signing, including when the key
|
|
189
|
+
is set on a Message; already signed messages retain their headers and OPT
|
|
190
|
+
record. Verification checks the MAC before timestamps and truncation policy,
|
|
191
|
+
and uses the Original ID as required by RFC 8945. Valid truncated MACs are
|
|
192
|
+
supported; `mac_length` sets the signing length and minimum accepted length
|
|
193
|
+
in octets. Malformed TSIG records are rejected, and key secrets are no longer
|
|
194
|
+
written to the log.
|
|
195
|
+
* Root trust anchors include KSK-2024 (38696) and remove revoked KSK-2010
|
|
196
|
+
(19036). `Dnssec.reset` restores the current anchors.
|
|
197
|
+
`Dnssec.clear_trusted_keys` clears learned keys and DS/DLV anchors while
|
|
198
|
+
retaining configured DNSKEY anchors. Removing or expiring a configured anchor
|
|
199
|
+
also removes keys learned from it. Keys sharing a tag can coexist, and an
|
|
200
|
+
unusable matching key does not prevent another from validating the answer.
|
|
201
|
+
DS matching accepts the same owner name with or without a trailing dot,
|
|
202
|
+
including when the DS is a configured trust anchor.
|
|
203
|
+
Learned DNSKEY and DS records have size limits, and validation looks up only
|
|
204
|
+
matching candidates. DS anchors now honor their requested expiration times,
|
|
205
|
+
just as DNSKEY anchors do. Direct RRset verification can try another trusted
|
|
206
|
+
verifier when the first has no suitable key.
|
|
207
|
+
[#225](https://github.com/alexdalitz/dnsruby/issues/225).
|
|
208
|
+
* Signed aliases can lead to authenticated unsigned zones and correctly return
|
|
209
|
+
`INSECURE`. CNAME and DNAME chains validate through to the terminal answer,
|
|
210
|
+
including negative answers, wildcard NODATA and NSEC3 Opt-Out delegations.
|
|
211
|
+
A synthesized CNAME must match its signed DNAME; valid responses that omit
|
|
212
|
+
the synthesized CNAME also work. Cross-zone aliases discover the target's
|
|
213
|
+
chain within the same validation budget. An unsigned delegation requires
|
|
214
|
+
authenticated proof: lookup failures cannot become insecure results.
|
|
215
|
+
A provisional insecure classification never suppresses a required record's
|
|
216
|
+
verification error; unsigned alias responses check every required owner and
|
|
217
|
+
the terminal name. Signed records discover their signer zones without extra
|
|
218
|
+
DS queries for each record owner.
|
|
219
|
+
Signer zones, DNSKEY Zone Key flags and DS owner/class bindings are checked.
|
|
220
|
+
A key authenticating a DNSKEY RRset must also be present in that set.
|
|
221
|
+
Missing NSEC or RRSIG bitmap bits do not prove those types absent.
|
|
222
|
+
NSEC3 records with unsupported flags are ignored as denial proofs while
|
|
223
|
+
supported records remain usable.
|
|
224
|
+
* Signed Additional records are verified when their keys are available.
|
|
225
|
+
Unverifiable signed extras are removed without rejecting an independently
|
|
226
|
+
authenticated answer. Unsigned glue remains available without acquiring
|
|
227
|
+
authentication metadata from records in another section; unverified extras
|
|
228
|
+
do not enter the trusted-key cache. Validation and cancellation limits still
|
|
229
|
+
apply to optional data.
|
|
230
|
+
* Validated answers and cached copies expire according to their original
|
|
231
|
+
receipt time, signatures and chain of trust. Revalidation does not renew
|
|
232
|
+
those lifetimes, and failed or BOGUS validation is never cached as successful.
|
|
233
|
+
Trying another verifier preserves a successful insecure result's authenticated
|
|
234
|
+
lifetime, so negative answers can still be cached under the default policy.
|
|
235
|
+
Bounded negative caches use the SOA lifetime required by RFC 2308; failure
|
|
236
|
+
caches follow RFC 9520. Entries respect the question class, configuration and
|
|
237
|
+
trust changes. Cancellation, raw messages, UPDATE and TSIG bypass these new
|
|
238
|
+
negative and failure caches. Recursive delegation caches are also bounded,
|
|
239
|
+
and delegation and glue-address lifetimes are tracked separately. Cached
|
|
240
|
+
child routes cannot outlive the parent route through which they were learned;
|
|
241
|
+
parent-cache eviction alone does not discard an already admitted child.
|
|
242
|
+
* Changing a DNSKEY's key or algorithm clears its cached public key.
|
|
243
|
+
`verify_rrset` accepts a single DS/DLV anchor as well as an RRSet. NSEC3 and
|
|
244
|
+
NSEC3PARAM correctly handle unsigned length octets and retain salt lengths.
|
|
245
|
+
|
|
246
|
+
### Records, parsing and performance
|
|
247
|
+
|
|
248
|
+
* SVCB and HTTPS work in DNS messages and zone files, including relative targets,
|
|
249
|
+
numeric `keyNNNNN` parameters and escaped text. IPv6 hints use RFC 5952 text.
|
|
250
|
+
* CAA accepts extensible alphanumeric tags and empty or binary values, including
|
|
251
|
+
an empty `issue` value. Wire decoding preserves the value independently of
|
|
252
|
+
presentation parsing. Private RRSIG algorithm numbers round-trip unchanged.
|
|
253
|
+
Decoded CAA records retain the historical String form of `rdata`, including
|
|
254
|
+
comparisons with text-created records and existing JSONDNS serialization.
|
|
255
|
+
Received ordinary TTLs with their high bit set become zero under RFC 2181;
|
|
256
|
+
OPT fields and TSIG's zero-TTL rule retain their special handling. Mandatory
|
|
257
|
+
names require their wire encoding, while valid empty UPDATE markers still
|
|
258
|
+
round-trip. DS, CDS and DLV equality and hashing agree for digest case variants.
|
|
259
|
+
* Zone-file TTLs and SOA intervals accept combined time suffixes such as
|
|
260
|
+
`1h30m`. Both class-before-TTL and TTL-before-class formats work. Quoted,
|
|
261
|
+
escaped and multiline values preserve their punctuation, Unicode and binary
|
|
262
|
+
character strings, including single-quoted TXT and SPF values. An explicit
|
|
263
|
+
record TTL leaves the `$TTL` default in place for later records. Relative
|
|
264
|
+
names in KX, NSEC, NXT, RRSIG, IPSECKEY and HIP data now use the zone origin.
|
|
265
|
+
Zone files also accept RFC 3597 hexadecimal data for known record types
|
|
266
|
+
without changing its bytes.
|
|
267
|
+
* Query scheduling, retries and cancellation avoid repeatedly scanning every
|
|
268
|
+
pending query. TCP reply matching is faster when many queries share a
|
|
269
|
+
connection. DNSSEC reuses canonical data and verifies reusable DS, DNSKEY
|
|
270
|
+
and wildcard proof sets once per message. Cache hits spend less time holding
|
|
271
|
+
the cache lock, and record parsing and numeric lookups allocate fewer
|
|
272
|
+
temporary objects. Unknown-record class handling and replacement no longer
|
|
273
|
+
accumulate memory or slow garbage collection on Ruby 3.0–3.2.
|
|
274
|
+
Name compression shares immutable label copies between suffixes, reducing
|
|
275
|
+
allocations while preserving case and escaped label boundaries.
|
|
276
|
+
RRset grouping uses an index and avoids cloning unrelated records. It
|
|
277
|
+
preserves section order and TTL normalization, and charges validation work
|
|
278
|
+
while grouping records and checking duplicates.
|
|
279
|
+
Canonical RRset sorting also avoids repeated duplicate scans, and binary
|
|
280
|
+
message decoding avoids temporary one-byte strings while retaining bounds
|
|
281
|
+
checks, compression safeguards and legacy nonbinary input behavior.
|
|
282
|
+
* Recursive answers now complete CNAME and DNAME chains within the original
|
|
283
|
+
lookup's deadline and work limits. Zero-TTL nameserver addresses are usable
|
|
284
|
+
during the lookup that obtained them without entering shared caches. DNSSEC
|
|
285
|
+
work and time limits are shared across the lookup's network hops, parallel
|
|
286
|
+
address discovery and final answer validation.
|
|
287
|
+
* DNSSEC validation evaluates applicable trust anchors before accepting a
|
|
288
|
+
provisional insecure result. RRSIG validity and learned-key expiration use
|
|
289
|
+
the serial-number arithmetic required for timestamps that cross the
|
|
290
|
+
32-bit boundary.
|
|
291
|
+
* SRV targets, DNAME targets, RRSIG signer names and NSEC successor names are
|
|
292
|
+
encoded without name compression. Valid empty UPDATE prerequisites and
|
|
293
|
+
deletions work for all applicable record types. Zone-file owner names retain
|
|
294
|
+
escaped spaces and quotes. Decoding reuses validated compression suffixes
|
|
295
|
+
within each packet while keeping returned names independently mutable.
|
|
296
|
+
* `RRSet#add` accepts another RRSet, and deleting signatures keeps the signature
|
|
297
|
+
count correct. Bulk duplicate checks avoid repeatedly encoding every record
|
|
298
|
+
already in a set while preserving mutable record behavior.
|
|
299
|
+
* Replacing a SingleResolver's server preserves concurrent configuration
|
|
300
|
+
changes. TCP replies report their byte size. Zone transfers retain verified
|
|
301
|
+
BADTIME and BADTRUNC diagnostics and no longer allocate unused IXFR state
|
|
302
|
+
for each received record.
|
|
303
|
+
|
|
304
|
+
|
|
3
305
|
## v1.74.0
|
|
4
306
|
|
|
5
307
|
* Resolve all configured nameservers in parallel
|
|
@@ -293,4 +595,3 @@
|
|
|
293
595
|
* Minor bug fixes
|
|
294
596
|
* IPSECKEY RR added
|
|
295
597
|
* Clients can now manipulate Name::Labels
|
|
296
|
-
|
data/Rakefile
CHANGED
data/demo/axfr.rb
CHANGED
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
# output, and stores the zone to a file. If the zone has already been
|
|
32
32
|
# stored in a file, axfr will read the file instead of performing a
|
|
33
33
|
# zone transfer.
|
|
34
|
+
#
|
|
35
|
+
# Records with dynamically generated classes cannot be stored with Marshal.
|
|
36
|
+
# Such transfers are printed without updating the cache; use -f to transfer
|
|
37
|
+
# again if an older cache exists. Unreadable legacy dynamic-record caches are
|
|
38
|
+
# ignored and the zone is transferred again.
|
|
34
39
|
#
|
|
35
40
|
# Zones will be stored in a directory hierarchy. For example, the
|
|
36
41
|
# zone transfer for foo.bar.com will be stored in the file
|
|
@@ -68,7 +73,7 @@ unless (1..2).include?(ARGV.length)
|
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
|
|
71
|
-
require '
|
|
76
|
+
require 'getoptlong'
|
|
72
77
|
require 'dnsruby'
|
|
73
78
|
|
|
74
79
|
|
|
@@ -134,16 +139,22 @@ end
|
|
|
134
139
|
# ------------------------------------------------------------------------------
|
|
135
140
|
|
|
136
141
|
if FileTest.exist?(zonefile) && !opt_f
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
begin
|
|
143
|
+
zoneref = File.open(zonefile, 'rb') { |file| Marshal.load(file) }
|
|
144
|
+
if zoneref.nil?
|
|
145
|
+
raise RuntimeError, "couldn't retrieve zone from #{zonefile}: #{$!}\n"
|
|
146
|
+
end
|
|
147
|
+
rescue ArgumentError => error
|
|
148
|
+
raise unless error.message.match?(/\Aundefined class\/module Dnsruby::RR::Generic::Type\d+_Class\d+\z/)
|
|
149
|
+
warn "Cannot read dynamic records from #{zonefile}; transferring the zone again."
|
|
150
|
+
opt_f = true
|
|
140
151
|
end
|
|
141
152
|
|
|
142
153
|
# ----------------------------------------------------------------------
|
|
143
154
|
# Check the SOA serial number if desired.
|
|
144
155
|
# ----------------------------------------------------------------------
|
|
145
156
|
|
|
146
|
-
if opt_s
|
|
157
|
+
if opt_s && !opt_f
|
|
147
158
|
serial_file = serial_zone = nil
|
|
148
159
|
|
|
149
160
|
zoneref.each do |rr|
|
|
@@ -185,7 +196,14 @@ if opt_f
|
|
|
185
196
|
if zoneref.nil?
|
|
186
197
|
raise RuntimeError, "couldn't transfer zone\n"
|
|
187
198
|
end
|
|
188
|
-
|
|
199
|
+
begin
|
|
200
|
+
cache = Marshal.dump(zoneref)
|
|
201
|
+
rescue TypeError => error
|
|
202
|
+
raise unless error.message.start_with?("can't dump anonymous class")
|
|
203
|
+
warn "Zone transferred but dynamic records cannot be cached; #{zonefile} was not changed. Use -f to transfer again."
|
|
204
|
+
else
|
|
205
|
+
File.binwrite(zonefile, cache)
|
|
206
|
+
end
|
|
189
207
|
end
|
|
190
208
|
|
|
191
209
|
# ------------------------------------------------------------------------------
|
data/demo/rubydig.rb
CHANGED
|
@@ -60,8 +60,6 @@ if ARGV[0] =~ /^@/
|
|
|
60
60
|
else
|
|
61
61
|
puts "Setting nameserver : #{nameserver}"
|
|
62
62
|
resolver.nameserver = (nameserver.sub(/^@/, ''))
|
|
63
|
-
resolver.dnssec = true
|
|
64
|
-
resolver.do_validation = true
|
|
65
63
|
puts "nameservers = #{resolver.config.nameserver}"
|
|
66
64
|
zone_transfer.server = (nameserver.sub(/^@/, ''))
|
|
67
65
|
end
|
data/dnsruby.gemspec
CHANGED
|
@@ -14,10 +14,10 @@ SPEC = Gem::Specification.new do |s|
|
|
|
14
14
|
'Dnsruby is a pure Ruby DNS client library which implements a
|
|
15
15
|
stub resolver. It aims to comply with all DNS RFCs, including
|
|
16
16
|
DNSSEC NSEC3 support.'
|
|
17
|
-
s.license = "Apache
|
|
17
|
+
s.license = "Apache-2.0"
|
|
18
18
|
|
|
19
19
|
# Add explicit Ruby version requirement
|
|
20
|
-
s.required_ruby_version = '>=
|
|
20
|
+
s.required_ruby_version = '>= 3.0.0'
|
|
21
21
|
|
|
22
22
|
s.files = `git ls-files -z`.split("\x0")
|
|
23
23
|
|
|
@@ -40,14 +40,15 @@ DNSSEC NSEC3 support.'
|
|
|
40
40
|
|
|
41
41
|
s.add_development_dependency 'rake', '>= 13.0.6'
|
|
42
42
|
s.add_development_dependency 'minitest', '~> 5.25'
|
|
43
|
+
# Retained for the legacy localdns/test_dnsserver helpers; rake soak uses stdlib.
|
|
43
44
|
s.add_development_dependency 'rubydns', '>= 2.0.2'
|
|
44
45
|
s.add_development_dependency 'nio4r', '>= 2.5.8'
|
|
45
46
|
s.add_development_dependency 'minitest-display', '>= 0.3.1'
|
|
46
47
|
s.add_development_dependency 'rdoc', '>= 6.5', '< 8.0'
|
|
47
48
|
s.add_development_dependency 'yard', '>= 0.9'
|
|
48
|
-
s.add_development_dependency '
|
|
49
|
+
s.add_development_dependency 'simplecov', '~> 0.22.0'
|
|
49
50
|
|
|
50
51
|
s.add_runtime_dependency 'base64', '>= 0.2'
|
|
51
52
|
s.add_runtime_dependency 'logger', '~> 1.6'
|
|
52
|
-
s.add_runtime_dependency 'simpleidn', '
|
|
53
|
+
s.add_runtime_dependency 'simpleidn', '>= 0.2.1', '< 0.4.0'
|
|
53
54
|
end
|