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.
The proximate cause for doing this is to fix a bug that
causes replies to PTR queries with more than one answer to have the
second and subsequent answers ignored.
The fix turned into a small re-write which removed a very old hack.
When caching reponses which include CNAME records, the cache system
stores the CNAME with a link to the record representing the target of
the CNAME. This isn't possible for PTR records representing IP
addresses since the name stored is the target of the PTR, record and
its name is inferred from the address in the cache record. Such
cache records have the F_REVERSE flag set. To get
around this, long ago, the code which stores such records elided the
CNAME entirely, so
4.3.2.1.in-addr.arpa CNAME 18/3.2.1.in-addr.arpa
18/3.2.1.in-addr.arpa PTR myhost.example.com
would be stored as
4.3.2.1.in-addr.arpa PTR myhost.example.com
and returned from the cache to subsequent requestor in that form.
Since that hack was committed, dnsmasq has learned to cache arbitrary
RRs. So now we can store the PTR records for all the no-trivial cases.
The means the CNAME chains ending in PTR records don't get mangled,
and we can store PTR records whose name in not w.x.y.x.in-addr.arpa
or the IPv6 equivalent.