Skip to content

Update embedded dnsmasq to v2.93rc1#2890

Open
DL6ER wants to merge 102 commits into
developmentfrom
update/dnsmasq
Open

Update embedded dnsmasq to v2.93rc1#2890
DL6ER wants to merge 102 commits into
developmentfrom
update/dnsmasq

Conversation

@DL6ER
Copy link
Copy Markdown
Member

@DL6ER DL6ER commented May 11, 2026

What does this implement/fix?

Update embedded dnsmasq to v2.93rc1

Highlights

Security

(all of these have already been merged into master and are released separately)

  • CVE-2026-2291 - heap overflow via long domain names (fixed by reworked storage allocation for domain names).
  • CVE-2026-4890 - DNSSEC denial-of-service via crafted NSEC bitmap (infinite loop in window iteration).
  • CVE-2026-4891 - crash via crafted RRSIG with truncated rdlen.
  • CVE-2026-4892 - buffer overflow in privileged DHCP helper with oversized DHCPv6 CLIDs.
  • CVE-2026-4893 - EDNS Client Subnet validation bypass with --add-subnet.
  • CVE-2026-5172 - heap OOB read in extract_addresses() via crafted RR rdlen.

DNSSEC correctness

  • Wildcard validation corner case for queries that match a wildcard but require no non-existence proof.
  • DNSSEC validation no longer fails when replies carry spurious RRSIGs from unsigned zones.
  • Signed CNAME replies to DS queries are now accepted as proof that no DS exists, fixing DS/zone-break detection.

DHCP and inotify

  • Fix DHCPv6 regression introduced in 2.92 that broke setups using a DHCP relay.
  • inotify watches are now created after privilege drop, so file permission checks match the runtime user.

Further fixes and improvements made by the Pi-hole team

  • dump: check lseek() return in pcap record-counting loop.
  • domain: fix strncat buffer-size argument in is_rev_synth().
  • lease: check parse_hex() return value before use as length.
  • edns0: bounds-check option length before memcmp in check_source().
  • rfc3315: fix integer underflow / heap overflow in log6_opts STATUS_CODE.
  • dhcp-common: fix OOB reads in DHCPv6 option_string() decoders.
  • dhcp-common: bounds-check label index before reading in OT_RFC1035_NAME decoder.
  • rfc2131: fix off-by-one in BOOTP filename netid NUL termination.
  • helper: fix OOB read in grab_extradata_lua bounds check.
  • prettyprint_time(): NUL-terminate buf when t == 0.
  • rand64() must share global outleft with rand16() / rand32().
  • reply_query(): move fd-match guard out of loop.
  • expand_workspace_real(): zero the correct byte count.

Related issue or feature (if applicable): N/A

Pull request in docs with documentation (if applicable): N/A


By submitting this pull request, I confirm the following:

  1. I have read and understood the contributors guide, as well as this entire template. I understand which branch to base my commits and Pull Requests against.
  2. I have commented my proposed changes within the code.
  3. I am willing to help maintain this change if there are issues with it later.
  4. It is compatible with the EUPL 1.2 license
  5. I have squashed any insignificant commits. (git rebase)

Checklist:

  • The code change is tested and works locally.
  • I based my code and PRs against the repositories development branch.
  • I signed off all commits. Pi-hole enforces the DCO for all contributions
  • I signed all my commits. Pi-hole requires signatures to verify authorship
  • I have read the above and my PR is ready for review.

simonkelley and others added 30 commits May 11, 2026 19:12
A malformed DHCP request can cause out-bounds memory reads, and probably SEGV.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
…ions.

A general rewrite and consolidation of the code that determines
if an incoming TCP connection is allowed, based on --address and --interface.

This was prompted by a bug found by Sławomir Zborowski where a TCP
connection for a valid IPv4 address on one interface which arrived
via a second interface which didn't have an IPv4 address would be
wrongly rejected.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
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.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
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.

Signed-off-by: Dominik <dl6er@dl6er.de>
FreeBSD 15.0 has added Linux-compatible inotify support, so
enable it by looking if the version matches. Since FreeBSD inotify has
seen a few bug fixes in 2025H2, so only enable it if
__FreeBSD_version >= 1500068.  The latter can be checked through
osreldate.h or sys/param.h; the latter defines more macros that clash
with dnsmasq's, such as MIN and MAX, so use the former.

Signed-off-by: Dominik <dl6er@dl6er.de>
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.

Signed-off-by: Dominik <dl6er@dl6er.de>
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.

Signed-off-by: Dominik <dl6er@dl6er.de>
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.

Signed-off-by: Dominik <dl6er@dl6er.de>
A CNAME reply to a DNSSEC query was confusing the validation logic.
It now accepts a signed CNAME reply to a DS query as proof that no DS
exists at the domain. This fixes the DS/zone break detection logic.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
This was functionally correct, but every call
malloced a new buffer and freed the previous one, rather
than only doing that when the buffer needed expansion.

Signed-off-by: Dominik <dl6er@dl6er.de>
Log all blocks malloced and all blocks freed.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
This fixes the plethora of 64k buffers that got allocated when doing
DNSSEC over TCP.

By using the UDP buffer is pass the query into tcp_talk() and
allowing tcp_talk to allocate its output buffer one the size
of the reply is known, we only need to allocate as much memory as
is required. The final reply to the TCP query still needs the 64k
buffer because answer_request() and answer_auth() are not capable
of extending their output buffers.

Signed-off-by: Dominik <dl6er@dl6er.de>
In the DNS TCP code, there are a couple of places where
we have a buffer containing a message which we need to
send via TCP. The DNS protocol is that this is sent as
<16-bit length in network order><message>

Making two write calls, one for the length and one
for the message causes the TCP stack to send two packets,
one for each. A single packet containing both is
preferable from a performance POV.

Implement a scatter-gather version of our read_write()
wrapper and use it where necessary to send TCP DNS messages.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
…p of free/strdup

Signed-off-by: Dominik <dl6er@dl6er.de>
This almost certainly never worked and was never use, and
it's rendered obsolete in RFC 9915.

Signed-off-by: Dominik <dl6er@dl6er.de>
Anything sent by a client must be multicast. A relay can unicast
to a server.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
While this won't do harm on systems that do 2's completement,
it triggers the compilers' undefined-behavior sanitizer and
fixes sanitizer error such as the one below (where the 1694... will
vary) and is distracting while debugging.

dnssec.c:1427:12: runtime error: left shift of 1694604366 by 1 places
cannot be represented in type 'int'

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
If iovcnt is exhausted and the first vector element's operation
is satisfied, the while loop will read past the end of the
iovec array.  This triggers the address sanitizer and leads to
undefined program state.  Avoid reading too far.

Signed-off-by: Dominik <dl6er@dl6er.de>
Signed-off-by: Dominik <dl6er@dl6er.de>
DL6ER and others added 20 commits May 11, 2026 19:48
After copying the 128-byte DHCP file field into dhcp_buff2, the
sentinel was written to index 129 instead of 128.  The byte at
index 128 was therefore left holding stale data from the previous
DHCP exchange, so a client that fills the entire file field with
non-NUL bytes would produce a 129-character netid tag whose last
byte is heap garbage.  In theory this allows incorrect netid-tag
matching; in practice it requires the client to know the heap
state of a prior transaction and BOOTP use is uncommon.

Security: very-low-severity heap-content exposure that could
influence DHCP option selection via tag mismatch; no memory
corruption or crash.

Signed-off-by: Dominik <dl6er@dl6er.de>
…ME decoder

In option_string(), the RFC1035-name label decoder sets i = l (the
position past the current label) and then reads val[i] to decide
whether to append a '.' separator — but without first checking that
i < opt_len.  If the last label ends exactly at the option boundary
(no NUL terminator), i == opt_len and val[i] reads one byte beyond
the option data.

The read lands inside the packet buffer so no crash occurs, but the
out-of-bounds byte (typically the next DHCPv6 option's type field)
could produce a spurious trailing '.' in --log-dhcp output when a
client sends a domain-search/nis-domain option without a trailing NUL.

Security: OOB read of 1 byte from a network-supplied DHCPv6 packet;
reachable only with --log-dhcp enabled; no memory corruption, crash,
or meaningful information disclosure.

Signed-off-by: Dominik <dl6er@dl6er.de>
Two decoders in option_string() read beyond the end of the supplied
option-value buffer when a malformed DHCPv6 option is received:

1. OT_RFC1035_NAME: after advancing i past the last label (i = l),
   val[i] was read at line 885 to decide whether to append a '.'.
   If the label ends exactly at opt_len, i == opt_len and val[i]
   is one byte past the option data.  Fixed by guarding with
   i < opt_len before the read.

2. OT_CSTRING: the loop opened with while(1) and called GETSHORT
   (a 2-byte read) before checking that two bytes remained, so a
   1- or 0-byte option value caused an immediate 1-byte OOB read.
   Additionally, if the length field exceeded the remaining option
   data the inner body-copy loop read past the end.  Fixed by
   changing the loop condition to while(i+2 <= opt_len) and adding
   a check that the body fits before copying.

Both reads land inside the received packet buffer (no crash), but
they allow a DHCPv6 client to cause dnsmasq to read unrelated packet
bytes and emit them in syslog output.

Security: OOB reads of up to option-length bytes from a
network-supplied DHCPv6 packet; reachable only with --log-dhcp
enabled; no memory corruption, crash, or sensitive data disclosure
beyond adjacent packet bytes.

Signed-off-by: Dominik <dl6er@dl6er.de>
…CODE

In log6_opts(), the OPTION6_STATUS_CODE branch did:
  memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
  daemon->namebuff[len + opt6_len(opt) - 2] = 0;

Two bugs:
1. Integer underflow: if opt6_len(opt) < 2, the subtraction wraps to a
   huge size_t, making memcpy write gigabytes and crash with SIGSEGV.

2. Heap overflow: no upper-bound check.  opt6_len() can return up to
   65535, but daemon->namebuff is only (MAXDNAME*2)+1 = 2051 bytes.
   A STATUS_CODE payload larger than ~2045 bytes would overflow the
   heap buffer.

Exploitability: log6_opts() is only ever called on daemon->outpacket,
the outgoing DHCPv6 reply built by dnsmasq itself — NOT on incoming
client packets.  Consequently, these bugs are NOT directly triggerable
by a remote attacker under the current code.  The fix is defensive:
put_opt6_short() (which writes STATUS_CODE options in outgoing packets)
always produces opt6_len >= 2, so neither bug fires in practice today.
However, the unchecked arithmetic is a latent hazard that could become
exploitable if future refactoring passes incoming option data through
log6_opts():
- Guard the block with opt6_len(opt) >= 2 to prevent underflow.
- Cap slen to the remaining space in daemon->namebuff.

Signed-off-by: Dominik <dl6er@dl6er.de>
The EDNS0 option iteration loop read a 2-byte len field from the
packet and used it directly in:
  opt.scope_netmask = p[3];          // requires len >= 4
  memcmp(p, &opt, len)               // reads len bytes from packet

Neither access was guarded against len exceeding the remaining RDATA.
A crafted DNS reply whose OPT RDATA contains a CLIENT_SUBNET option
with an oversized len field would cause memcmp to read past the end of
the packet buffer, leaking heap memory.

Risk: currently the only caller that reaches this branch is
forward.c:process_reply(), which (before the companion fix) passed an
OPT-RR-scoped plen that made skip_name() return NULL first, so the
unsafe code was never reached.  With that companion fix applied the
path is live: a rogue upstream server or on-path attacker can craft a
reply with a malformed CLIENT_SUBNET len and trigger the OOB read,
potentially leaking adjacent heap contents.

Fix: break out of the loop if the option body would extend past the
RDATA boundary.

Signed-off-by: Dominik <dl6er@dl6er.de>
parse_hex() returns -1 on malformed input.  Three call sites in
read_leases() used the return value directly as a length argument
without checking for the error sentinel:

  opt_len  → lease_set_vendorclass() / lease_set_agent_id()
              whine_malloc(-1) attempts a ~4 GB allocation, likely
              crashing the process.

  hw_len   → lease_set_hwaddr()
              memcpy(lease->hwaddr, hwaddr, (size_t)-1) performs an
              ~18 EB write, causing an immediate crash.

  clid_len → lease_set_hwaddr() (same path as hw_len)

Exploitation requires a corrupted or attacker-controlled lease file;
it is not directly network-triggerable.  However, any process that can
write to the lease file (e.g. a compromised helper) can crash or
potentially gain code execution in the dnsmasq process at next startup
or lease-file re-read.

Fix: mirror the existing duid path (which already guards its
parse_hex call) by checking for < 0.  For opt_len, skip the record
(continue) to match the "invalid line" behaviour.  For hw_len and
clid_len, treat the failure as a zero-length field so the lease is
still created with the correct address.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
strncat(dst, src, n) truncates src to n bytes, but n should be the
remaining space in dst, not the total buffer size.  Passing MAXDNAME
as n allowed the combined prefix + address + "." + domain to overflow
the MAXDNAME-byte namebuff if c->domain was close to MAXDNAME chars.

Replace MAXDNAME with MAXDNAME - strlen(name) - 1 at each call site
(lines 178-179 for IPv4, 204 for the IPv6 hex-fragment loop, 208-209
for the IPv6 suffix) so the append is always bounded by actual
remaining capacity.

Security implications: strncat(name, c->domain, MAXDNAME) passes the
full buffer size instead of remaining space. Overflow requires a local
admin to configure a --synth-domain with a domain name > ~960 chars.
The actual exploitable window is narrow: the admin would need a
--synth-domain with a domain name close to 1024 chars (which check_name
permits) combined with a non-trivial prefix or IPv6 address.
Not remotely exploitable.

Signed-off-by: Dominik <dl6er@dl6er.de>
When --dump-file points to an existing pcap file, dump_init_file()
counts the existing records by reading each pcap record header and
seeking past the payload.  The lseek() return value was not checked:
if it fails (e.g. EOVERFLOW on a 32-bit build with a very large
incl_len, or any other seek error) the file position does not advance,
the next read_write() call reads the same header again, and the loop
spins forever — hanging daemon startup.

Fix: break out of the loop on lseek failure.  An undercount of
existing records is harmless; a hanging startup is not.

Signed-off-by: Dominik <dl6er@dl6er.de>
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.
Report from Royce M <royce@xchglabs.com>.

Location: dnssec.c:1290-1306, dnssec.c:1450-1463

The bitmap window iteration advances by p[1] instead of p[1]+2
(missing the 2-byte window header). With bitmap_length=0, both rdlen and p are
unchanged, causing an infinite loop and dnsmasq stops responding to all queries.

Bug is reachable before RRSIG validation
(confirmed by the source comment at line 2125), so no valid
DNSSEC signatures are needed.
Bug report from Royce M <royce@xchglabs.com>

This avoids crafted packets which give a value for rdlen _less_
then the space taken up by the fixed data and the signer's name
and engender a negative calculated length for the signature.
Bug reported bt Royce M <royce@xchglabs.com>

Location: helper.c:265-270
DHCPv6 CLIDs can be up to 65535 bytes. When --dhcp-script is configured,
the helper hex-encodes raw CLID bytes via sprintf("%.2x") into daemon->packet (5131 bytes).
A 1000-byte CLID writes ~3000 bytes. The helper process retains root privileges.

Note: log6_packet() correctly caps CLID to 100 bytes for logging, but the helper code path was missed.
Bug report from Royce M <royce@xchglabs.com>

Location: forward.c:713, edns0.c:421

With --add-subnet enabled, process_reply() passes the OPT record
length (~23 bytes) instead of the packet length to check_source().
All internal bounds checks fail, and the function always returns 1.
ECS source validation per RFC 7871 Section 9.2 is completely bypassed.
Thanks to Hugo Martinez Ray for spotting this.

The value of rdlen for an RR can be a lie, allowing the
call to extract_name() at rfc1025.c:952 to advance the value of p1
past the calculated end of the record. The makes the calculation
of bytes remaining in the RR underflow to a huge number and results
in a massive heap OOB read and certain crash.
Thanks to Royce M <royce@xchglabs.com> for spotting this.
In find_soa() extract_name() is called with extrabytes=0 when parsing NS
record names, which means it only validates that the DNS name fits
within the packet but does not check that 10 additional bytes exist for
the type/class/TTL/rdlen fixed fields. Lines 546-549 then
unconditionally read these 10 bytes via GETSHORT/GETLONG macros. An
attacker controlling a DNS zone can craft a NXDOMAIN response where the
NS record name extends to the packet boundary, causing a 10-byte
out-of-bounds read past the valid packet data (CWE-125, CVSS 5.3
Medium). The read stays within the over-allocated packet buffer in
default configurations, limiting crash risk, but accesses data outside
the logical packet boundary. Under certain conditions, the overread may
access stale heap data from prior transactions.

The fix is straightforward: change the extrabytes
argument from 0 to 10, consistent with other call sites in
the same file.

Credit is due to do litli for finding this problem.
Signed-off-by: Dominik <dl6er@dl6er.de>
# Conflicts:
#	CMakeLists.txt
#	src/dnsmasq/dnsmasq.h
#	src/dnsmasq/dnssec.c
Copilot AI review requested due to automatic review settings May 11, 2026 20:09
@DL6ER DL6ER requested a review from a team as a code owner May 11, 2026 20:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the embedded dnsmasq tree to pi-hole-v2.93rc1, bringing in multiple upstream security fixes (several CVEs), DNSSEC correctness improvements, DHCP/inotify fixes, and a set of Pi-hole-specific hardening changes. It also updates FTL glue/build/test code to accommodate the newer dnsmasq and newer nettle digest APIs.

Changes:

  • Bump embedded dnsmasq to v2.93rc1 and incorporate upstream DNSSEC/DHCP/inotify changes plus Pi-hole patches.
  • Adjust FTL + build tooling for updated dependency APIs (notably nettle digest prototype changes) and add a debug build-type toggle in build.sh.
  • Update tests and warning allow-lists to match updated dnsmasq log strings.

Reviewed changes

Copilot reviewed 58 out of 58 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
CMakeLists.txt Bumps embedded dnsmasq version reference to pi-hole-v2.93rc1.
build.sh Forces -DCMAKE_BUILD_TYPE=Debug when using debug mode.
src/CMakeLists.txt Adds CMake configure-time logging for optional crypto/IDN libraries.
src/FTL.h Protects system headers from macro redefinitions (push/pop free/strdup).
src/api/2fa.c Updates nettle HMAC digest call for nettle v4+ API.
src/config/password.c Updates nettle SHA256 digest calls for nettle v4+ API.
src/files.c Updates SHA256 digest call for nettle v4+ API; adds nettle version header include.
src/dnsmasq/arp.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/auth.c Embedded dnsmasq authoritative-answer logic tweaks (offset handling, NS/SOA building).
src/dnsmasq/bpf.c Embedded dnsmasq update: BSD ARP enumeration improvements incl. IPv6 handling.
src/dnsmasq/blockdata.c Embedded dnsmasq update: safer realloc usage for internal scratch buffer.
src/dnsmasq/cache.c Embedded dnsmasq update: cache/hosts name storage and allocation tracking refactor.
src/dnsmasq/config.h Embedded dnsmasq update: constants/macros updates (incl. HAVE_INOTIFY for FreeBSD 15+).
src/dnsmasq/conntrack.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/crypto.c Embedded dnsmasq update: nettle digest API wrapper + realloc fixes.
src/dnsmasq/dbus.c Embedded dnsmasq update: buffer size constant updates.
src/dnsmasq/dhcp-common.c Embedded dnsmasq update: bounds checks in DHCP option decoding + buffer size constant updates.
src/dnsmasq/dhcp-protocol.h Embedded dnsmasq update (copyright year bump).
src/dnsmasq/dhcp.c Embedded dnsmasq update: minor control-flow fix + buffer size constant updates.
src/dnsmasq/dhcp6-protocol.h Embedded dnsmasq update (copyright year bump).
src/dnsmasq/dhcp6.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/dns-protocol.h Embedded dnsmasq update: redefine MAXDNAME/MAXDNAMESTR and add EDE code.
src/dnsmasq/dnsmasq.c Embedded dnsmasq update: inotify init timing, DS duplicate handling, DNSSEC TCP timeout plumbing.
src/dnsmasq/dnsmasq.h Embedded dnsmasq update: new options/events/constants, malloc logging, signature changes.
src/dnsmasq/dnssec.c Embedded dnsmasq update: multiple DNSSEC validation correctness and robustness improvements.
src/dnsmasq/domain-match.c Embedded dnsmasq update: guard qsort() when serverarray is NULL.
src/dnsmasq/domain.c Embedded dnsmasq update: string length fixes and safer concatenation sizing.
src/dnsmasq/dump.c Embedded dnsmasq update: check lseek() during pcap record counting.
src/dnsmasq/edns0.c Embedded dnsmasq update: option-length bounds check in check_source().
src/dnsmasq/files.c Embedded dnsmasq update: (via other files) buffer size constant updates.
src/dnsmasq/forward.c Embedded dnsmasq update: DNSSEC validation retry logic, TCP refactor, new warning, and EDE remapping.
src/dnsmasq/helper.c Embedded dnsmasq update: buffer sizing and bounds checks in helper extradata parsing.
src/dnsmasq/inotify.c Embedded dnsmasq update: error reporting via event pipe + init signature change.
src/dnsmasq/ip6addr.h Embedded dnsmasq update (copyright year bump).
src/dnsmasq/lease.c Embedded dnsmasq update: parse_hex return checks and buffer size macro update.
src/dnsmasq/log.c Embedded dnsmasq update: preserve existing log file mode while ensuring group-writable.
src/dnsmasq/loop.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/metrics.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/metrics.h Embedded dnsmasq update (copyright year bump).
src/dnsmasq/netlink.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/network.c Embedded dnsmasq update: buffer size macro alignment and minor comment tweak.
src/dnsmasq/nftset.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/option.c Embedded dnsmasq update: new options + DHCP vendor/user class parsing updates.
src/dnsmasq/outpacket.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/pattern.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/poll.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/radv-protocol.h Embedded dnsmasq update (copyright year bump).
src/dnsmasq/radv.c Embedded dnsmasq update: buffer size macro updates and bounds logic.
src/dnsmasq/rfc1035.c Embedded dnsmasq update: name extraction hardening + bounds checks and function signature update.
src/dnsmasq/rfc2131.c Embedded dnsmasq update: DHCP logging buffer size update + off-by-one fix + memset fix.
src/dnsmasq/rfc3315.c Embedded dnsmasq update: DHCPv6 relay behavior fixes and multiple bounds/correctness updates.
src/dnsmasq/rrfilter.c Embedded dnsmasq update: workspace expansion refactor and escape handling adjustments.
src/dnsmasq/slaac.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/tftp.c Embedded dnsmasq update: safer string operations and traversal check improvements.
src/dnsmasq/ubus.c Embedded dnsmasq update (copyright year bump).
src/dnsmasq/util.c Embedded dnsmasq update: name-length checks, safer copy semantics, read/writev refactor, malloc logging hooks.
test/dnsmasq_warnings Updates expected warning strings for the updated dnsmasq log messages.
test/test_final.bats Updates warning allowlist regex for updated DNSSEC warning wording/casing.
test/zone_update.py Makes the zone-update test utility configurable via CLI args (proto/port/server).
Comments suppressed due to low confidence (1)

test/zone_update.py:37

  • The UDP/TCP branches use tab indentation, and the script no longer handles invalid proto values (it will silently do nothing). Since this is used from the test suite, it would be safer to use consistent spaces for indentation and to restore an else that prints an error and exits non-zero when proto is not udp or tcp.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/zone_update.py
Comment on lines +17 to +22
# Usage: python3 zone_update.py [proto = tcp] [port = 5300] [server = 127.0.0.1]

# Get the protocol, server, and port from command line arguments or use defaults
proto = sys.argv[1] if len(sys.argv) > 1 else 'tcp'
port = int(sys.argv[2]) if len(sys.argv) > 2 else 53
server = sys.argv[3] if len(sys.argv) > 3 else '127.0.0.1'
Comment thread src/api/2fa.c
Comment on lines 19 to +40
// TOTP+HMAC
#include <nettle/hmac.h>
#include <nettle/sha1.h>

static uint32_t hotp(const uint8_t *key, size_t key_len, const uint64_t counter, const uint8_t digits)
{
// Initialize HMAC-SHA1 (RFC 2104)
// TOTP uses HMAC-SHA1 (RFC 6238, section 5.1)
struct hmac_sha1_ctx ctx;
hmac_sha1_set_key(&ctx, key_len, key);

// Convert counter to big endian
const uint64_t counter_be = htobe64(counter);

// Compute HMAC-SHA1
hmac_sha1_update(&ctx, sizeof(counter_be), (uint8_t*)&counter_be);
uint8_t out[SHA1_DIGEST_SIZE];
#if NETTLE_VERSION_MAJOR >= 4
hmac_sha1_digest(&ctx, out);
#else
hmac_sha1_digest(&ctx, SHA1_DIGEST_SIZE, out);

#endif
Comment thread src/dnsmasq/option.c
Comment on lines +4611 to +4615
{
new->len = parse_hex(comma, (unsigned char *)arg, strlen(arg), NULL, NULL);
new->data = opt_malloc(new->len);
memcpy(new->data, arg, new->len);
}
Comment thread src/dnsmasq/util.c
Comment on lines +207 to +209
/* length of final label and terminaton added */
if (!idn_encode && wiresize + dotgap + 2 > MAXDNAME)
return 0; /* wire representation too long */
Comment thread src/dnsmasq/util.c
Comment on lines +279 to +282

/* IDN library doesnt call our malloc wrapper, so log this by steam */
if (ret)
malloc_log(ret, strlen(ret)+1);
Comment on lines +25 to +36
/* Dnsmasq handles domains names internally as NULL-terminated C strings.
The '.' characters in these strings are significant as label-seperators.
'.' and /0 characters _within_ labels are escaped and take up two
characters to allow labels to contain arbitrary characters.

The maximum length of a domain name in wire format is 255 bytes.
and the maximum length of this when coverted to a <label>.<label> string
is 253 characters. Reasoning: the wire format representation of a
label is one byte length followed by up to length characters so each of
these labels except the last takes the same space since the length is
replaced by the '.' seperator.
The last label doesn't have the "." so it takes one less character
characters to allow labels to contain arbitrary characters.

The maximum length of a domain name in wire format is 255 bytes.
and the maximum length of this when coverted to a <label>.<label> string
503 characters.
*/
#define MAXDNAME 255 /* Maximum size of a domain name in wire format */
#define MAXDNAMESTR 503 /* Maximum size of dnsmasq c-string representaion of a domain name. */
Copy link
Copy Markdown
Member

@yubiuser yubiuser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is already in master, hasn't this already added to development by #2889

@DL6ER
Copy link
Copy Markdown
Member Author

DL6ER commented May 11, 2026

Master received v2.92.2 which is only few targetted patches on top of the older v2.92. This has all the v2.93 code in it (many more but not as critical fixes).

@github-actions
Copy link
Copy Markdown

This pull request has conflicts, please resolve those before we can evaluate the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.