Commit Graph
247 Commits
Author SHA1 Message Date
Simon Kelley 1269f074f8 Fix DNSSEC failure with spurious RRSIGs.
The presence of wrong RRSIG RRs in replies causes DNSSEC
validation to fail even when the RRs do not require validation
because the zone is unsigned.

This patch solves the problem and tidies up the logic.

Included is some fixes for hostname_issubdomain() which suffered
some confusions about argument order :) I've clarified that and
checked every to the function to make sure they are using the
correct argument order.

Note that, at the time of this commit, Google DNS appears to have
the same bug, so if you're using 8.8.8.8 or friends as upstream,
resolving the broken zones (eg rivcoed.org) will still fail.

Thanks to Petr Menšík for the bug report.
2026-01-15 14:41:31 +00:00
Simon Kelley f603a4f920 Fix a corner-case in DNSSEC validation with wildcards.
If we have a wildcard record *.example.com and recieve a query for
a.example.com then that's OK, but we have to check that there isn't
an actual a.example.com record. The corner case is when we get a
query for *.example.com in that case the non-existence check
is not required, but was being done.

Thanks to Jan Breig for spotting this.
2026-01-12 21:55:41 +00:00
Simon Kelley 8ddabd11bc DNSSEC validation change for reverse lookups in RFC-1918 ranges and friends.
The large public DNS services seem not to return proof-of-nonexistence
for DS records at the start of RFC-1918 in-addr.arpa domains and the their
IPv6 equivalents. 10.in-addr.arpa, 168.192.in-addr.arpa etc.

Since dnsmasq already has an option which instructs it not bother
upstream servers with pointless queries about these address ranges,
namely --bogus-priv, we extend that to enable behaviour which allows
dnsmasq to assume that insecure NXDOMAIN replies for these domains
are expected and to assume that the domains are legitimately unsigned.

This behaviour only matters when some address range is directed to
another upstream server using --rev-server. In that case it allows
replies from that server to pass DNSSEC validation. Without such a
server configured, queries are never sent upstream so they are never
validated and the new behaviour is moot.
2025-05-09 21:46:50 +01:00
Simon Kelley d390dc0338 Implement RFC6672 para 5.3.2. check for DNAME.
Also fix overflow checking of NSEC type maps.
2025-03-15 16:47:55 +00:00
Simon Kelley 105c25e561 Fix DNSSEC and DNAME.
Do the correct things to validate replies which
include a DNAME record.

Thanks to Graham Clinch for pointing this out.
2025-03-15 09:05:47 +00:00
Simon Kelley 57f0489f38 Redesign the interaction between DNSSEC vaildation and per-domain servers.
This should just work in all cases now. If the normal chain-of-trust exists into
the delegated domain then whether the domain is signed or not, DNSSEC
validation will function normally. In the case the delgated domain
is an "overlay" on top of the global DNS and no NS and/or DS records
exist connecting it to the global dns, then if the domain is
unsigned the situation will be handled by synthesising a
proof-of-non-existance-of-DS for the domain and queries will be
answered unvalidated; this action will be logged. A signed domain
without chain-of-trust can be validated if a suitable trust-anchor
is provided using --trust-anchor.

Thanks to Uwe Kleine-König for prompting this change, and contributing
valuable insights into what could be improved.
2025-03-14 15:12:45 +00:00
Simon Kelley 6e6a45a7d9 Bump copyrights to 2025. 2025-01-23 17:08:39 +00:00
Simon Kelley 995a16ca0c Implement "DNS-0x20 encoding".
This provides extra protection against reply-spoof attacks.

Since DNS queries are case-insensitive, it's possible to randomly flip
the case of letters in a query and still get the correct answer back.
This adds an extra dimension for a cache-poisoning attacker to guess
when sending replies in-the-blind since it's expected that the
legitimate answer will have the same pattern of upper and lower case
as the query, so any replies which don't can be ignored as
malicious.

The amount of extra entropy clearly depends on the number
of a-z and A-Z characters in the query, and this implementation puts a
hard limit of 32 bits to make rescource allocation easy. This about
doubles entropy over the standard random ID and random port
combination.
2025-01-19 21:54:58 +00:00
Simon Kelley e5e8c14d87 Large refactor of EDNS0 UDP packet size handling.
This was kinda strange before, with a lot of cargo-cult copied code,
and no clear strategy.

Now it works like this:

When talking upstream we always add a pseudoheader, and set the
UDP packet size to --edns-packet-max unless we've had problems
talking to a server, when it's reduced to 1280 if that fixes things.

Answering queries from downstream, we get the answer (either from
upstream or local data) If local data won't fit the advertised size
(or 512 if there's not pseudoheader) return truncated. If upstream
returns truncated, do likewise. If upstream is OK, but the answer is
too big for downstream, truncate the answer.
2024-11-23 22:38:41 +00:00
Simon Kelley e778a28eee Remove obsolete comment. 2024-11-22 22:42:50 +00:00
Simon Kelley b5ac983bf6 Fix wrong transaction ID when retrying DNSSEC queries. 2024-11-21 15:09:14 +00:00
Simon Kelley 550c368ade Treat cache insertion failure of DNSKEY and DS records as
another resource problem and fail validation with suitable logging.
2024-03-27 16:00:06 +00:00
renmingshuai ccff85ad72 [PATCH] Fix error introduced in 51471cafa5
Signed-off-by: renmingshuai <renmingshuai@huawei.com>
2024-02-21 00:24:25 +00:00
Simon Kelley 3ae7f1ab0d Add --dnssec-limits option. 2024-02-12 23:11:35 +00:00
Simon Kelley 39de57499e Better allocation code for DS digest cache. 2024-02-12 23:11:35 +00:00
Simon Kelley 3c91bca943 Better stats and logging from DNSSEC resource limiting. 2024-02-12 23:11:35 +00:00
Simon Kelley 76bceb06c4 Overhaul data checking in NSEC code. 2024-02-12 23:11:35 +00:00
Simon Kelley 6f23a0a75e Rework validate-by-DS to avoid DoS vuln without arbitrary limits.
By calculating the hash of a DNSKEY once for each digest algo,
we reduce the hashing work from (no. DS) x (no. DNSKEY) to
(no. DNSKEY) x (no. distinct digests)

The number of distinct digests can never be more than 255 and
it's limited by which hashes we implement, so currently only 4.
2024-02-12 23:11:35 +00:00
Simon Kelley c5aa221e44 Parameterise work limits for DNSSEC validation. 2024-02-12 23:11:35 +00:00
Simon Kelley bfefd6e38c Fix error introduced in 635bc51cac3d5d7dd49ce9e27149cf7e402b7e79 2024-02-12 23:11:35 +00:00
Simon Kelley 59d30390c9 Measure cryptographic work done by DNSSEC. 2024-02-12 23:11:34 +00:00
Simon Kelley 51471cafa5 Update NSEC3 iterations handling to conform with RFC 9276. 2024-02-12 23:11:34 +00:00
Simon Kelley 40595f80d9 Protection against pathalogical DNSSEC domains.
An attacker can create DNSSEC signed domains which need a lot of
work to verfify. We limit the number of crypto operations to
avoid DoS attacks by CPU exhaustion.
2024-02-12 23:11:34 +00:00
Simon Kelley d4a6f3a93e Fix logic error in signed RR handling.
In extract_addresses() the "secure" argument is only set if the
whole reply is validated (ie the AD bit can be set). Even without
that, some records may be validated, and should be marked
as such in the cache.

Related, the DNS doctor code has to update the flags for individual
RRs as it works, not the global "secure" flag.
2024-02-02 21:36:56 +00:00
Simon Kelley 31c91b40bd Handle SERVFAIL responses to DS queries better.
On 15/5/2023 8.8.8.8 was returning SERVFAIL for a query on ec.europa.eu

ec.europa.eu is not a domain cut, that happens at jrc.ec.europa.eu. which
does return a signed proof of non-existance for a DS record.
Abandoning the search for a DS or proof of non existence at ec.europa.eu
renders everything within that domain BOGUS, since nothing is signed.

This code changes behaviour on a SERVFAIL to continue looking
deeper for a DS or proof of its nonexistence.
2023-05-17 12:20:50 +01:00
Simon Kelley df242de5c6 Bump copyrights to 2023. 2023-04-05 12:34:34 +01:00
Simon Kelley 638c7c4d20 Add --cache-rr to enable caching of arbitrary RR types. 2023-03-23 17:15:35 +00:00
Petr Menšík 02f8754339 fixup! Handle DS records for unsupported crypto algorithms. 2022-11-22 22:51:11 +00:00
Simon Kelley 9ed3ee67ec Handle DS records for unsupported crypto algorithms correctly.
Such a DS, as long as it is validated, should allow answers
in the domain is attests to be returned as unvalidated, and not
as a validation error.
2022-11-16 16:49:30 +00:00
Simon Kelley f65d210012 Fix outdated comment. 2022-05-26 14:49:10 +01:00
Simon Kelley ebd8350300 Fix DNSSEC failure to validate unsigned NoDATA replies.
A reply with an empty answer section would not always be checked
for either suitable NSEC records or proof of non-existence of
the relevant DS record.
2022-01-13 00:12:07 +00:00
Simon Kelley 8285d335f4 Fix error introduced in 11c52d032b 2022-01-12 23:05:25 +00:00
Petr Menšík 4ac517e4ac Fix coverity issues in dnssec.c
Error: CHECKED_RETURN (CWE-252): [#def26]
dnsmasq-2.86rc3/src/dnssec.c:727: check_return: Calling "extract_name" without checking return value (as is done elsewhere 9 out of 10 times).
dnsmasq-2.86rc3/src/dnssec.c:459: example_checked: Example 1: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)".
dnsmasq-2.86rc3/src/dnssec.c:269: example_checked: Example 2: "extract_name(header, plen, &state->ip, state->buff, 1, 0)" has its value checked in "extract_name(header, plen, &state->ip, state->buff, 1, 0)".
dnsmasq-2.86rc3/src/dnssec.c:569: example_checked: Example 3: "extract_name(header, plen, &p, keyname, 1, 0)" has its value checked in "extract_name(header, plen, &p, keyname, 1, 0)".
dnsmasq-2.86rc3/src/rfc1035.c:648: example_checked: Example 4: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)".
dnsmasq-2.86rc3/src/rfc1035.c:787: example_checked: Example 5: "extract_name(header, qlen, &p1, name, 1, 0)" has its value checked in "extract_name(header, qlen, &p1, name, 1, 0)".
 #  725|         /* namebuff used for workspace above, restore to leave unchanged on exit */
 #  726|         p = (unsigned char*)(rrset[0]);
 #  727|->       extract_name(header, plen, &p, name, 1, 0);
 #  728|
 #  729|         if (key)

Error: CHECKED_RETURN (CWE-252): [#def27]
dnsmasq-2.86rc3/src/dnssec.c:1020: check_return: Calling "extract_name" without checking return value (as is done elsewhere 7 out of 8 times).
dnsmasq-2.86rc3/src/auth.c:140: example_checked: Example 1: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/dnssec.c:771: example_checked: Example 2: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/hash-questions.c:57: example_checked: Example 3: "extract_name(header, plen, &p, name, 1, 4)" has its value checked in "extract_name(header, plen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/rfc1035.c:1028: example_checked: Example 4: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
dnsmasq-2.86rc3/src/rfc1035.c:1438: example_checked: Example 5: "extract_name(header, qlen, &p, name, 1, 4)" has its value checked in "extract_name(header, qlen, &p, name, 1, 4)".
 # 1018|
 # 1019|     p = (unsigned char *)(header+1);
 # 1020|->   extract_name(header, plen, &p, name, 1, 4);
 # 1021|     p += 4; /* qtype, qclass */
 # 1022|
2021-09-11 22:08:25 +01:00
Dominik DL6ER e0ce3c12f2 Add all current RR types to the table of type names used for query logging.
This patch also changes the method of calling querystr() such that
it is only called when logging is enabled, to eliminate any
possible performance problems from searching the larger table.
2021-09-10 23:13:53 +01:00
Simon Kelley cac9ca38f6 Treat ANY queries the same as CNAME queries WRT to DNSSEC on CNAME targets. 2021-09-08 21:21:22 +01:00
Dominik DL6ER e7ccd95c04 Add EDE return when no matching key found. 2021-07-09 22:12:42 +01:00
Simon Kelley 6261aba026 Initial implementation of RFC-8914 extended DNS errors. 2021-06-26 00:38:01 +01:00
Simon Kelley 11c52d032b Initial changes for extended DNS error codes. 2021-06-21 17:37:46 +01:00
Simon Kelley 8ebdc364af Optimise sort_rrset for the case where the RR type no canonicalisation. 2021-01-22 18:50:43 +00:00
Simon Kelley 059aded070 Optimse RR digest calculation in DNSSEC.
If an RR is of a type which doesn't need canonicalisation,
bypass the relatively slow canonicalisation code, and insert
it direct into the digest.
2020-12-16 15:49:02 +00:00
Simon Kelley 2d765867c5 Use SHA-256 to provide security against DNS cache poisoning.
Use the SHA-256 hash function to verify that DNS answers
received are for the questions originally asked. This replaces
the slightly insecure SHA-1 (when compiled with DNSSEC) or
the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
2020-12-16 15:49:02 +00:00
Simon Kelley 4e96a4be68 Fix remote buffer overflow CERT VU#434904
The problem is in the sort_rrset() function and allows a remote
attacker to overwrite memory. Any dnsmasq instance with DNSSEC
enabled is vulnerable.
2020-12-16 15:47:42 +00:00
Simon Kelley 532246fc9e Tweak to DNSSEC logging. 2020-04-04 18:50:56 +01:00
Kevin Darbyshire-Bryant c65b77c87f dnssec: add hostname info to insecure DS warning
Make the existing "insecure DS received" warning more informative by
reporting the domain name reporting the issue.

This may help identify a problem with a specific domain or server
configuration.

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2020-02-11 21:32:56 +00:00
Simon Kelley 2a8710ac2f Update copyrights to 2020. 2020-01-05 16:40:06 +00:00
Simon Kelley 19b0e3bf21 Check for REFUSED and SERVFAIL replies to DNSKEY queries. 2019-10-12 21:54:37 +01:00
Simon Kelley e24abf28a2 Fix botch in ae7a3b9d2e
Loop variable must count up from zero, now we're using it as
an array index.
2019-09-03 22:48:39 +01:00
Simon Kelley 69a0477b74 DNSSEC: unsigned RRs in the auth section are not bogus.
Even if they are in a signed zone.
2019-09-03 16:49:02 +01:00
Simon Kelley ae7a3b9d2e DNSSEC: implement RFC-4036 para 5.3.3. rules on TTL values. 2019-09-03 14:40:47 +01:00
Simon Kelley fef2f1c75e DNSSEC: Unsigned RRs in auth section proving that a DS doesn't exist are OK.
In a reply proving that a DS doesn't exist, it doesn't matter if RRs
in the auth section _other_ than NSEC/NSEC3 are not signed. We can't
set the AD flag when returning the query, but it still proves
that the DS doesn't exist for internal use.

As one of the RRs which may not be signed is the SOA record, use the
TTL of the NSEC record to cache the negative result, not one
derived from the SOA.

Thanks to Tore Anderson for spotting and diagnosing the bug.
2019-08-29 21:59:00 +01:00