Commit Graph
249 Commits
Author SHA1 Message Date
Simon Kelley 77d4749a5e Fix DNSSEC frec use-after-free in TCP validation path.
Full credit to Jerry Tom <goonsomeway@gmail.com> for finding this.

When DNSSEC validation falls back to TCP (via a forked child process),
the parent uses a uid-based check to detect whether a frec has been
freed and reused before the child returns. It doesn't, however check for
the more likely scenario which is that the frec has simply been
freed via the timeout path in get_new_frec(). This leads to a
use-after-free on an already freed frec.
2026-05-29 17:24:54 +01:00
Simon Kelley 228d7ff964 Remove arbitrary limit on config file line lengths.
Stop using the namebuff buffer to read config file
lines. This reduced in size in
014e909f78 and caused
regressions. We now resize the buffer as needed,
so there is no practical limit.

Use the same code to remove the same limit when reading
/etc/ethers and /etc/resolv.conf. Also when copying output
from the lease-change script into the log.

Thanks to Kevin Darbyshire-Bryant for finding the regresssion.
2026-05-16 21:37:11 +01:00
Simon Kelley 014e909f78 Rework storage allocation for domain names. CVE-2026-2291
This is the stable release fix for CVE-2026-2291

Dnsmasq recieves and sends domain names within DNS packets in RFC-1035
format, a string of counted labels terminated by a zero length label.
Internally to dnsmasq, domain names are represented as zero-terminated C strings
with the labels seperated by '.' characters, like the normal presentation
format for domain names.

The RFC-1035 limit for a domain name in wire format is 255 octets, and
when converted to presentation format, this makes a string of
maximum 253 characters. However dnsmasq needs to be able to
represent any 8-bit character within a label, and this causes
problems with /000 (which would terminate the c-string early) and
'.' (which would terminate a label early). To avoid this, dnsmasq
escapes both of these characters, which means that they take two bytes
in the string. The domain name with must charaters in it has four labels
and the 255 octet wire length limits these four labels to a total of
250 characters. The other five octets are the four label length bytes
and the zero length byte terminator. If all 250 characters need escaping
that makes the maximum length of the dnsmasq internal format 503
characters (250 escaped characters in labels, amd three dots between
four labels) Since this format is zero-terminated c-string, buffers
have to be allocated as 504 bytes.

This arrangement grew in a somewhat ad-hoc manner and early dnsmasq
didn't do the escaping trick, and didn't really differentiate between
the lengths of the wire format and the presentation format, since
they were very similar. It also, for reasons lost in time, inherited
a defintion for MAXDNAME from early BIND headers, set at 1025 bytes.
This value was used as the buffer size for both wire and presentation
formats.

This patch makes everything consistent. It declares two constants

MAXDNAME 255     /* max size of wire format domain name */
MAXDNAMESTR 503  /* max size of internal format created from a 255 octet wire format name */

All internal name buffers are allocated as MAXDNAMESTR+1 bytes,
to hold a maximum size internal format name and zero termination.

Names parsed out of incoming packets are rejected if their
wire format is greater than 255 bytes, which ensures that
their internal representation cannot exceed 503 characters.
Names inserted into outgoing packets are failed similarly if
they exceed 255 bytes. (this would in theory be possible
for a legal internal-representaion name if it has at least
one unescaped character in a label.
2026-05-10 21:49:39 +01:00
Simon Kelley 36d081e374 Fix buffer overlow in log_query()
The addition of "(not supported)" to logs of DS and DNSKEY replies
overflows the buffer used to construct the string.

Re-arrange things to avoid this, and add checks to avoid the same  problem
if the logging calls change in the future.

Thanks to Yiwei Hou for finding this.

The problem exists is DNSSEC is enabled and query logging is also
enabled. The overwrite is of bounded length and the bytes
written are not in control of an attacker, so this is not considered
a likely remote-execution vector.
2026-04-21 22:14:41 +01:00
Simon Kelley cfc2244c2a Bump copyrights to 2026. 2026-04-08 12:08:18 +01:00
Simon Kelley e0bec3342b Move logging on TCP timeout from child process to main process.
Callong my_syslog from a signal handler is not good.

Thanks to Dominik Derigs for spotting this.
2026-03-30 20:23:56 +01:00
Simon Kelley 32a54fc8a5 Remove duplicate configured trust anchors.
Well-known trust anchors can turn up in multiple config files.

Leaving the duplicates makes logging messy and costs some
CPU checking the same DS twice.
2026-02-16 22:20:05 +00:00
Simon Kelley ceab392c60 Improve memory allocation for /etc/hosts etc.
Clearing and reloading the DNS cache involved freeing and re-allocating
many small memory blocks. Doing this frequently with a significant
number of static DNS configuraions or DHCP leases could result
in excessive heap fragmentation and memory use.

This patch extends the pool memory allocation technique used
else where to this memory. On cache clear, the memory is not
freed, but added to a pool of useable but unused data structures
which get re-used to store the new data.
2026-02-05 13:26:08 +00:00
Simon Kelley 8eb36844a0 Log SERVFAIL from usptream servers.
If we're doing DNSSEC validation and fail because the upstream
reply to our query is SERVFAIL, log this as the reason in
validation result line.

This will make maintainers lives easier when they get reports
of "wrong" validation failure, which is sometimes an upstream problem.
2026-01-18 12:50:57 +00:00
Pavel Bozhko 8fa68a6e1e The only_failed argument has been added to the log-queries parameter.
This may be useful for embedded systems for example:
log-queries without only_failed places a heavy load on the
NAND flash memory. At the same time, logging requests
is necessary to troubleshoot network issues.
2026-01-16 15:33:59 +00:00
Simon Kelley c090f1d17b Terminate TCP child processes that arise from UDP truncated replies.
These can't be held forever by a client that opens a connection and
then sends nothing, but we can still be DoSsed by a server which
accepts a connection and never replies.

If the TCP process times out, it sends that information to the
parent so that the UDP query can be unblocked. As the TCP
timeout is 150s it's highly unlikely that any client will
still be waiting, but the point is to free resources.
2025-12-07 15:00:29 +00:00
Simon Kelley ff30fa4b91 Fix caching bug with negative records.
To provoke this bug, at least the following must be true.

A reply must be a CNAME.
The target of the CNAME must not exist for the queried RR (a No Data reply).
The No Data reply must include an SOA record in the NS section.
The query must take place over TCP.

The result is the caching of a CNAME whose target is the
name of the SOA record, instead of the No data record.

If there is a RR at this target, then a subsequent query for that
RRtype will get a qrong reply.

Thanks to the testers extraordinaire at Pi-Hole for spotting this
and providing enough information to chase it down.
2025-08-11 16:53:40 +01:00
Simon Kelley 6ce7f2d55a Fix regression in 9e67099ce7
Logging queries lost the RRtype.

Revert to e.g. query[A] example.com
2025-06-06 23:29:31 +01:00
Simon Kelley c7a909ad65 Add RRtypes HHIT and BRID to the table. 2025-05-21 15:03:51 +01:00
Simon Kelley b0aa604fcc Tidy-up of TCP-child pipe handling code.
Functionality is unchanged, but the code is easier to read and understand.

Also fix memory leak of blocks when cache insert fails.
2025-05-11 15:30:30 +01:00
Simon Kelley 98189ff988 Fix problems with ipset or nftset and TCP DNS transport.
If DNS is happening over TCP, the query is handled by a forked
process. Of ipset ot nftset is configured, this might include
inserting addresses in the *sets. Before this update, that
was done by the forked process using handles inherited from the
parent "master" process.

This is inherently racy. If the master process or another
child process tries to do updates at the same time, the
updates can clash and fail.

To see this, you need a busy server doing lots of DNS
queries over TCP, and ipset or nftset configured.

Going forward, we use the already established pipe to send the
updates from the child back to the master process, which
serialises them.
2025-05-08 16:07:19 +01:00
Simon Kelley a458c2bfb0 Tidy up pipe-to-parent code in DNS TCP path. 2025-04-23 12:14:00 +01:00
Simon Kelley 9e67099ce7 Tidy up replies to non-QUERY DNS opcodes in auth mode. 2025-04-22 18:07:24 +01:00
Rob Gill cfa1313e1f Log format error from upstream as 'FORMERR'
Signed-off-by: Rob Gill <rrobgill@protonmail.com>

At the moment if a misformatted query is reported by the upstream server
it is not clear from the log.
Other error codes from RFC1035 (server failure, not implemented,
refused) are logged with text, but format error is logged merely as "1".

Such that an upstream reporting a format error is presently logged as eg:
Apr 20 12:01:55 dnsmasq[3023]: reply error is 1

After this patch they are logged informatively, eg:
Apr 20 12:48:40 dnsmasq[3023]: reply error is FORMERR

This is a two line fix, FORMERR is already defined in dns-protocol.h.
2025-04-20 22:38:43 +01:00
Simon Kelley e3a2c8dadf Add --log-queries=auth option. 2025-04-20 22:20:52 +01:00
Simon Kelley ae57f84061 Do a better job of 942a35f517 2025-04-18 14:01:14 +01:00
Opty 942a35f517 Silence compiler warnings. 2025-04-16 16:00:47 +01: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 bb8811d472 Convert DNS names in logs to all lower case.
0x20 encoding makes them look odd, otherwise.
2025-01-20 15:25:26 +00:00
Matthias Andree f162d344c0 cache: Fix potential NULL deref in arcane situations. 2025-01-08 23:34:12 +00:00
DL6ER 3ac11cdd98 Add newly assigned RRTYPE DSYNC
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 15:19:00 +00:00
DL6ER 5d49fa112d Add newly assigned RRTYPEs NXNAME, CLA, and IPN
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 15:18:56 +00:00
DL6ER d29d19e654 Add newly assigned RRTYPE WALLET (262)
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 15:18:47 +00:00
Simon Kelley ab177cb153 Improve handling of non-QUERY DNS requests.
We can't answer and shouldn't forward non-QUERY DNS requests.

This patch fixes handling such requests from TCP connections; before
the connection would be closed without reply.

It also changes the RCODE in the answer from REFUSED to NOTIMP and
provides clearer logging.
2024-12-13 23:00:21 +00:00
Simon Kelley 32a8f3e009 Finesse TCP timeouts for upstream connections.
Timeouts for TCP connections to non-responive servers are very long.
This in not appropriate for DNS connections.

Set timeouts for connection setup, sending data and recieving data.
The timeouts for connection setup and sending data are set at 5 seconds.
For recieving the reply this is doubled, to take into account the
time for usptream to actually get the answer.

Thanks to Petr Menšík for pointing out this problem, and finding a better
and more portable solution than the one in place heretofore.
2024-11-25 23:18:07 +00:00
Simon Kelley 0338aa4586 Don't log bogus source address when doing fast retry. 2024-10-13 00:09:26 +01:00
Simon Kelley d15d371051 Handle truncated response UDP-to-TCP to downstream queries when validating.
A relatively common situation is that the reply to a downstream query
will fit in a UDP packet when no DNSSEC RRs are present, but overflows
when the RRSIGS, NSEC ect are added. This extends the automatic
move from UDP to TCP to downstream queries which get truncated replies,
in the hope that once stripped of the DNSSEC RRs, the reply can be returned
via UDP, nwithout making the downstream retry with TCP.

If the downstream sets the DO bit, (ie it wants the DNSSEC RRs, then
this path is not taken, since the downstream will have to get a truncated
repsonse and retry to get a correct answer.
2024-10-12 22:32:21 +01:00
Simon Kelley e9a7cd0a50 Fix DNSSEC work counting when swapping from UDP to TCP 2024-10-04 17:20:33 +01:00
Simon Kelley f5cdb007d8 Improve handling of truncated replies to DNSSEC queries.
Heretofore, when a validating the result of an external query triggers
a DNSKEY or DS query and the result of that query is truncated, dnsmasq
has forced the whole validation process to move to TCP by returning a
truncated reply to the original requestor. This forces the original
requestor to retry the query in TCP mode, and the DNSSEC subqueries
also get made via TCP and everything works.

Note that in general the actual answer being validated is not large
enough to trigger truncation, and there's no reason not to return that
answer via UDP if we can validate it successfully. It follows that
a substandard client which can't do TCP queries will still work if the
answer could be returned via UDP, but fails if it gets an artifically
truncated answer and cannot move to TCP.

This patch teaches dnsmasq to move to TCP for DNSSEC queries when
validating UDP answers. That makes the substandard clients mentioned
above work, and saves a round trip even for clients that can do TCP.
2024-10-04 17:20:33 +01:00
Simon Kelley 3c91bca943 Better stats and logging from DNSSEC resource limiting. 2024-02-12 23:11:35 +00:00
Simon Kelley 06945c4b77 Update EDE code -> text conversion. 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 a827127c77 Handle caching SOA for negative PTR queries.
Also deal with the fact that a root SOA is a thing.
2024-02-03 20:46:23 +00:00
Simon Kelley b5820d1fd8 Bump copyright to 2024. 2024-01-13 22:20:04 +00:00
Damian Sawicki 69877f565a Add information on process-forking for TCP connections to metrics.
Add the relevant information to the metrics and to the output of
dump_cache() (which is called when dnsmasq receives SIGUSR1).
Hence, users not collecting metrics will still be able to
troubleshoot with SIGUSR1. In addition to the current usage,
dump_cache() contains the information on the highest usage
since it was last called.
2023-11-30 15:55:51 +00:00
Simon Kelley 568fb02449 Fix use-after-free in cache_remove_uid().
Thanks to Kevin Darbyshire-Bryant for the bug report.
2023-11-13 22:08:08 +00:00
Dominik Derigs 1fe9d2ba45 Add RESINFO RR-type to the table of RR-type names. 2023-11-04 16:52:09 +00:00
Simon Kelley ca8d04a8ff Cache zero-TTL DNS replies when stale-caching is enabled. 2023-10-09 21:15:13 +01:00
Simon Kelley 1419de285f Log truncated DNS replies. 2023-05-17 23:19:30 +01:00
Simon Kelley df242de5c6 Bump copyrights to 2023. 2023-04-05 12:34:34 +01:00
Simon Kelley b14aa762ff Fix long-term bug in TCP caching code which would lose NXDOMAIN.
A NXDOMAIN answer recieved over TCP by a child process would
be correctly sent back to the master process which would then
fail to insert it into the cache.
2023-04-01 22:03:49 +01:00
Simon Kelley a78487a4df Use a simpler arrangement for the all_addr union to avoid
the compiler padding it with an extra 8 bytes.

Use the F_KEYTAG flag in a a cache record to discriminate between
an arbitrary RR stored entirely in the addr union and one
which has a point to block storage.
2023-04-01 21:35:26 +01:00
Simon Kelley 3a601d06bd Fix copy-n-paste error in 138e1e2a2d 2023-04-01 00:50:29 +01:00
Simon Kelley 138e1e2a2d Optimse memory use for arbitrary-RR caching.
RRs 13 bytes or less don't need to allocate block storage.
2023-03-31 17:44:02 +01:00