A 'AddDhcpLease' DBus message which fails to allocate
a DHCP lease will cause dnsmasq to dereference a NULL pointer
and crash.
Allocation failure can happen if the particular
flavour (IPv4 pr IPv6) of DHCP is not configured in
this dnsmasq instance, or if the configured limit on
DHCP leases is reached or (unlikley) if dnsmasq cannot
allocate memory.
This patch provides error returns for all these situations.
This patch is inspired by a patch from
Stefan Hanreich <s.hanreich@proxmox.com> which was prompted by
a bug report from Lou Lécrivain.
This was supposed to disallow addresses which are in use by
the DHCP server, and the code works fine when only dhcp-range
is defined per broadcast domain. It's confused when there are
multiple dhcp-ranges which are valid for a particular request.
The options which cause dnsmasq to decorate a DNS query with the MAC
address on the originating client can fail when the query is sent
using TCP.
In TCP mode, dnsmasq spawns a new process to handle each TCP connection.
These child processes do not have an open netlink socket, which is
needed to read the kernel ARP table, so the process of adding the
client's MAC address as an EDNS0 option silently fails.
This is fixed by this patch by updating dnsmasq's ARP cache in the
main process just before forking the TCP-handler child process.
This ensures that the copy of the ARP cache inherited by the
TCP-handler contains the information required without the need to
read the kernel ARP table.
Thanks to Bruno Ravara for spotting and characterising this bug.
This change attempts to optimse TFTP perfomance.
It reads the next block immediately after sending a block,
in order to reduce latency between receiving an ACK and sending
the next block. Is also suppresses lseek() calls when reading
successive blocks.
This improves performance when doing transfers without windowing
and when only a single transfer is in progress at one time.
get_new_frec() garbage collects struct frec when they are
(by default) 40s old. This means that in an active dnsmasq
which is getting new queries, answers to old queries start to
be ignored soon after they hit 40s old. If there are no new
queries, get_new_frec() doesn't get called, and answers to old
queries will still be accepted for longer.
This patch stops lookup_frec() from returning old frecs which
are ready for GC. This helps avoid yet another variation
on the birthday attack, which is no particularly relevant,
given the need for an idle server.
get_new_frec() is not supposed to ever free an frec when
the force arg is set. Make this so. In theory, this fixes
a bug, but it's practically impossible to provoke and I have
no evidence that it has ever happened IRL.
TFTP fails with a timeout when the transfer exceeds 128K blocks.
The block field in an ACK packet is 16 bits, so large transfers
need to deal with this field wrapping. Testing failure meant
that it worked for the first wrap, but not for subsequent ones.
Having fixed the block number problem, file size calculations
accidentally being done in 32 bits not 64 bits then broke
transfers larger than 2G or maybe 4G.
The first problem was probably introduced in commit
ebef27f321 and has not appeared
in a stable release. The second appears to have been there forever.
Clearly, nobody is mad enough to transfer multi-gigabyte files
over TFTP.
Thanks to Jean-François JUBLIN for spotting this and supplying
useful packet dumps that made it easy to diagnose.
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.
Change the behaviour of the DHVPv6 server when a REBIND message
is received but no lease exists. Under these circumstances a new
lease is created _only_ when the --dhcp-authoritative option is
set. This matches the behavior of the DHCPv4 server.
Reading /etc/ethers assumes that dhcp-host cofig has already
been read, and that is the case for dhcp-host, but for unknown
reasons, the analogous congiguration is dhcp-hostfile was being
read after /etc/ethers.
Swap the order.
Thanks to Andreas Kuropka for spotting the problem.
servers for plain names (server=//1.2.3.4) as domain-specific.
This means that if we fail to get a DS record for such a query,
it gets given the benefit of the doubt.
Updates 57f0489f38
This fixes a problem introduced in 8a5fe8ce6b
On BSD, fdescfs is normally mounted at /dev/fd. However
if it is NOT mounted, devfs creates a directory at /dev/fd
which contains (only) the file descriptors 0,1 and 2.
Under these conditions, opendir() will succeed, and
if we proceed we will fail to close extant
file descriptors which should be closed.
Check that there is a filesystem mounted at /dev/fd
by checking that the device changes between /dev/fd
and /dev. If if doesn't, fall back to the dumb path.
Thanks to Roman Bogorodskiy for spotting the problem
and helping with diagnosis.
Not sure how that bug got in there. Very (un)lucky choice
of test data, or last-minute "it'll be fine" modification I guess.
It was late, I can't remember.
Thanks to Dominik Derrigs for spotting the problem.
The bug occurs when we ask lookup_domain() for a server for a domain
which is not a general upstream server, by setting F_DOMAINSRV in the flags.
If there are no possible servers, because there are no upstream servers
defined (for instance, at startup) then the code steps off the end of an
array and SEGVs.
The bug has been latent for some time, but
3e659bd4ec added a new call to lookup_domain()
which can actually trigger the bug if DNSSEC is enabled and a certain
amount of bad luck ensues.
Thanks to the testers extraordinaire at PiHole for reporting this.
Variable unsigned char a is defined unconditionally,
but it is only used if HAVE_LINUX_NETWORK is defined.
This triggers compiler warnings on, say, FreeBSD.
Fix by wrapping the definition in proper #ifdef.
GCC complains that writing the five-character "ODNS\0" string into
a four-element char magic[4] array truncates the NUL character.
The warning's rationale is that this is incompatible with C++, or
maybe non-intentional.
GCC 8 has added a nonstring variable attribute, clang 20.1 does
not yet support this, but clang's Git head does.
Add an ATTRIBUTE_NONSTRING macro, currently only defined on GCC >= 8
as __attribute__ ((nonstring)). This successfully suppresses
the warning on Fedora Linux 42's default compiler.
The alternative would be to replace the "ODNS" literal by {0} and
instead memcpy(opt.magic, "ODNS", sizeof(opt.magic)); on the next line,
which is correct, C++ compatible, but also less concise.