Compare commits

..
1 Commits
Author SHA1 Message Date
Simon Kelley 45903b7776 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-11-11 23:25:04 +00:00
69 changed files with 5875 additions and 7133 deletions

No files matched your search

+1 -111
View File
@@ -1,117 +1,7 @@
version 2.85
Fix problem with DNS retries in 2.83/2.84.
The new logic in 2.83/2.84 which merges distinct requests
for the same domain causes problems with clients which do
retries as distinct requests (differing IDs and/or source ports.)
The retries just get piggy-backed on the first, failed, request.
The logic is now changed so that distinct requests for repeated
queries still get merged into a single ID/source port, but
they now always trigger a re-try upstream.
Thanks to Nicholas Mu for his analysis.
Tweak sort order of tags in get-version. v2.84 sorts
before v2.83, but v2.83 sorts before v2.83rc1 and 2.83rc1
sorts before v2.83test1. This fixes the problem which lead
to 2.84 announcing itself as 2.84rc2.
Avoid treating a --dhcp-host which has an IPv6 address
as eligible for use with DHCPv4 on the grounds that it has
no address, and vice-versa. Thanks to Viktor Papp for
spotting the problem. (This bug was fixed was back in 2.67, and
then regressed in 2.81).
Add --dynamic-host option: A and AAAA records which take their
network part from the network of a local interface. Useful
for routers with dynamically prefixes. Thanks
to Fred F for the suggestion.
Teach --bogus-nxdomain and --ignore-address to take an IPv4 subnet.
Use random source ports where possible if source
addresses/interfaces in use.
CVE-2021-3448 applies. Thanks to Petr Menšík for spotting this.
It's possible to specify the source address or interface to be
used when contacting upstream name servers: server=8.8.8.8@1.2.3.4
or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of
these have, until now, used a single socket, bound to a fixed
port. This was originally done to allow an error (non-existent
interface, or non-local address) to be detected at start-up. This
means that any upstream servers specified in such a way don't use
random source ports, and are more susceptible to cache-poisoning
attacks.
We now use random ports where possible, even when the
source is specified, so server=8.8.8.8@1.2.3.4 or
server=8.8.8.8@eth0 will use random source
ports. server=8.8.8.8@1.2.3.4#66 or any use of --query-port will
use the explicitly configured port, and should only be done with
understanding of the security implications.
Note that this change changes non-existing interface, or non-local
source address errors from fatal to run-time. The error will be
logged and communication with the server not possible.
Change the method of allocation of random source ports for DNS.
Previously, without min-port or max-port configured, dnsmasq would
default to the compiled in defaults for those, which are 1024 and
65535. Now, when neither are configured, it defaults instead to
the kernel's ephemeral port range, which is typically
32768 to 60999 on Linux systems. This change eliminates the
possibility that dnsmasq may be using a registered port > 1024
when a long-running daemon starts up and wishes to claim it.
This change does likely slightly reduce the number of random ports
and therefore the protection from reply spoofing. The older
behaviour can be restored using the min-port and max-port config
switches should that be a concern.
Scale the size of the DNS random-port pool based on the
value of the --dns-forward-max configuration.
Tweak TFTP code to check sender of all received packets, as
specified in RFC 1350 para 4.
version 2.84
Fix a problem, introduced in 2.83, which could see DNS replies
being sent via the wrong socket. On machines running both
IPv4 and IPv6 this could result in sporadic messages of
the form "failed to send packet: Network is unreachable" and
the lost of the query. Since the error is sporadic and of
low probability, the client retry would normally succeed.
Change HAVE_NETTLEHASH compile-time to HAVE_CRYPTOHASH.
version 2.83
Use the values of --min-port and --max-port in outgoing
TCP connections to upstream DNS servers.
Fix a remote buffer overflow problem in the DNSSEC code. Any
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
referenced by CVE-2020-25681, CVE-2020-25682, CVE-2020-25683
CVE-2020-25687.
Be sure to only accept UDP DNS query replies at the address
from which the query was originated. This keeps as much entropy
in the {query-ID, random-port} tuple as possible, to help defeat
cache poisoning attacks. Refer: CVE-2020-25684.
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: CVE-2020-25685.
Handle multiple identical near simultaneous DNS queries better.
Previously, such queries would all be forwarded
independently. This is, in theory, inefficient but in practise
not a problem, _except_ that is means that an answer for any
of the forwarded queries will be accepted and cached.
An attacker can send a query multiple times, and for each repeat,
another {port, ID} becomes capable of accepting the answer he is
sending in the blind, to random IDs and ports. The chance of a
successful attack is therefore multiplied by the number of repeats
of the query. The new behaviour detects repeated queries and
merely stores the clients sending repeats so that when the
first query completes, the answer can be sent to all the
clients who asked. Refer: CVE-2020-25686.
referenced by CERT VU#434904.
version 2.82
+5 -10
View File
@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2021 Simon Kelley
# dnsmasq is Copyright (c) 2000-2016 Simon Kelley
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -53,7 +53,7 @@ top?=$(CURDIR)
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus`
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
@@ -62,12 +62,8 @@ ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CON
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
HAVE_CRYPTOHASH $(PKG_CONFIG) --cflags nettle \
HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \
HAVE_CRYPTOHASH $(PKG_CONFIG) --libs nettle \
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
@@ -81,8 +77,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
metrics.o hash_questions.o
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
+1 -1
View File
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
crypto.c dump.c ubus.c metrics.c hash_questions.c
crypto.c dump.c ubus.c
LOCAL_MODULE := dnsmasq
+2 -5
View File
@@ -9,10 +9,7 @@
# If we can find one which matches $v[0-9].* then we assume it's
# a version-number tag, else we just use the whole string.
# If there is more than one v[0-9].* tag, sort them and use the
# first. The insane arguments to the sort command are to ensure
# that, eg v2.64 comes before v2.63, but v2.63 comes before v2.63rc1
# and v2.63rc1 comes before v2.63test1
# first. This favours, eg v2.63 over 2.63rc6.
# Change directory to the toplevel source directory.
if test -z "$1" || ! test -d "$1" || ! cd "$1"; then
@@ -31,7 +28,7 @@ else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then
echo "${vers}" | sort -k1.2,1.5Vr -k1.6,1.6 -k1.8,1.9Vr -k1.10,1.11Vr | head -n 1 | sed 's/^v//'
echo "${vers}" | sort -r | head -n 1 | sed 's/^v//'
else
cat $1/VERSION
fi
+19 -22
View File
@@ -1,37 +1,35 @@
#!/bin/sh
search=$1
shift
pkg=$1
shift
op=$1
shift
in=`cat`
search()
{
grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
echo $in | grep $1 >/dev/null 2>&1
}
while [ "$#" -gt 0 ]; do
search=$1
pkg=$2
op=$3
lib=$4
shift 4
if search "$search"; then
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
echo $in | grep $search >/dev/null 2>&1; then
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
if [ $op = "--copy" ]; then
if [ -z "$pkg" ]; then
pkg="$lib"
elif search "$pkg"; then
pkg="$*"
elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
echo $in | grep $pkg >/dev/null 2>&1; then
pkg=""
else
pkg="$lib"
pkg="$*"
fi
elif search "${search}_STATIC"; then
pkg=`$pkg --static $op $lib`
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
pkg=`$pkg --static $op $*`
else
pkg=`$pkg $op $lib`
pkg=`$pkg $op $*`
fi
if search "${search}_STATIC"; then
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
else
@@ -42,4 +40,3 @@ if search "$search"; then
fi
fi
done
-38
View File
@@ -1,41 +1,3 @@
dnsmasq (2.85-1) unstable; urgency=low
* New upstream.
* Includes fix to CVE-2021-3448.
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 03 Apr 2021 22:17:23 +0100
dnsmasq (2.84-1.2) unstable; urgency=medium
* Non-maintainer upload.
* Bump old-version in dpkg-maintscript-helper dir_to_symlink calls to also
clean up after upgrades to an earlier version in testing.
-- Andreas Beckmann <anbe@debian.org> Thu, 01 Apr 2021 16:01:51 +0200
dnsmasq (2.84-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Fix symlink to directory conversion for /usr/share/doc/dnsmasq.
This is achieved by directly calling dpkg-maintscript-helper in the preinst,
postinst, and postrm scripts, since the package does not use debhelper.
(Closes: #985282)
-- Sébastien Villemot <sebastien@debian.org> Sun, 28 Mar 2021 10:55:07 +0200
dnsmasq (2.84-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 24 Jan 2021 22:02:01 +0000
dnsmasq (2.83-1) unstable; urgency=high
* New upstream.
* Includes fixes to CVE-2020-25681 - CVE-2020-25687 inclusive.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 15 Jan 2021 22:22:41 +0000
dnsmasq (2.82-1) unstable; urgency=low
* New upstream.
+1 -1
View File
@@ -1,4 +1,4 @@
dnsmasq is Copyright (c) 2000-2021 Simon Kelley
dnsmasq is Copyright (c) 2000-2020 Simon Kelley
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
-3
View File
@@ -1,9 +1,6 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
# Code copied from dh_systemd_enable ----------------------
# This will only remove masks created by d-s-h on package removal.
deb-systemd-helper unmask dnsmasq.service >/dev/null || true
-3
View File
@@ -1,9 +1,6 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
if [ purge = "$1" ]; then
update-rc.d dnsmasq remove >/dev/null
fi
-5
View File
@@ -1,5 +0,0 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
+1 -1
View File
@@ -176,7 +176,7 @@ binary-indep: checkroot
-d debian/trees/daemon/usr/lib/tmpfiles.d \
-d debian/trees/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/preinst debian/prerm debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
if ! dpkg-vendor --derives-from Ubuntu; then \
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
dh_runit -pdnsmasq -Pdebian/trees/daemon; \
+10 -50
View File
@@ -135,9 +135,6 @@ running, will go exclusively to the file.) When logging to a file,
dnsmasq will close and reopen the file when it receives SIGUSR2. This
allows the log file to be rotated without stopping dnsmasq.
.TP
.B --log-debug
Enable extra logging intended for debugging rather than information.
.TP
.B --log-async[=<lines>]
Enable asynchronous logging and optionally set the limit on the
number of lines
@@ -299,7 +296,7 @@ option requires non-standard networking APIs and it is only available
under Linux. On other platforms it falls-back to \fB--bind-interfaces\fP mode.
.TP
.B \-y, --localise-queries
Return answers to DNS queries from /etc/hosts and \fB--interface-name\fP and \fB--dynamic-host\fP which depend on the interface over which the query was
Return answers to DNS queries from /etc/hosts and \fB--interface-name\fP which depend on the interface over which the query was
received. If a name has more than one address associated with
it, and at least one of those addresses is on the same subnet as the
interface to which the query was sent, then return only the
@@ -326,8 +323,8 @@ are re-written. So
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
.TP
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix]
Transform replies which contain the IP specified address or subnet into "No such
.B \-B, --bogus-nxdomain=<ipaddr>
Transform replies which contain the IP address given into "No such
domain" replies. This is intended to counteract a devious move made by
Verisign in September 2003 when they started returning the address of
an advertising web page in response to queries for unregistered names,
@@ -335,8 +332,8 @@ instead of the correct NXDOMAIN response. This option tells dnsmasq to
fake the correct response when it sees this behaviour. As at Sept 2003
the IP address being returned by Verisign is 64.94.110.11
.TP
.B --ignore-address=<ipaddr>[/prefix]
Ignore replies to A-record queries which include the specified address or subnet.
.B --ignore-address=<ipaddr>
Ignore replies to A-record queries which include the specified address.
No error is generated, dnsmasq simply continues to listen for another reply.
This is useful to defeat blocking strategies which rely on quickly supplying a
forged answer to a DNS request for certain domain, before the correct answer can arrive.
@@ -431,7 +428,7 @@ Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
or domain parts, to upstream nameservers. If the name is not known
from /etc/hosts or DHCP then a "not found" answer is returned.
.TP
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<interface>][@<source-ip>[#<port>]]
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<source-ip>|<interface>[#<port>]]
Specify IP address of upstream servers directly. Setting this flag does
not suppress reading of /etc/resolv.conf, use \fB--no-resolv\fP to do that. If one or more
optional domains are given, that server is used only for those domains
@@ -492,7 +489,7 @@ source address specified but the port may be specified directly as
part of the source address. Forcing queries to an interface is not
implemented on all platforms supported by dnsmasq.
.TP
.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<source-ip>|<interface>[#<port>]]
This is functionally the same as
.B --server,
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
@@ -594,12 +591,6 @@ If the time-to-live is given, it overrides the default, which is zero
or the value of \fB--local-ttl\fP. The value is a positive integer and gives
the time-to-live in seconds.
.TP
.B --dynamic-host=<name>,[IPv4-address],[IPv6-address],<interface>
Add A, AAAA and PTR records to the DNS in the same subnet as the specified interface. The address is derived from the network part of each address associated with the interface, and the host part from the specified address. For example
.B --dynamic-host=example.com,0.0.0.8,eth0
will, when eth0 has the address 192.168.78.x and netmask 255.255.255.0 give the
name example.com an A record for 192.168.78.8. The same principle applies to IPv6 addresses. Note that if an interface has more than one address, more than one A or AAAA record will be created. The TTL of the records is always zero, and any changes to interface addresses will be immediately reflected in them.
.TP
.B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings,
so any number may be included, delimited by commas; use quotes to put
@@ -701,8 +692,8 @@ still marks the request so that no upstream nameserver will add client
address information either. The default is zero for both IPv4 and
IPv6. Note that upstream nameservers may be configured to return
different results based on this information, but the dnsmasq cache
does not take account. Caching is therefore disabled for such replies,
unless the subnet address being added is constant.
does not take account. If a dnsmasq instance is configured such that
different results may be encountered, caching should be disabled.
For example,
.B --add-subnet=24,96
@@ -1054,19 +1045,6 @@ option, but aliases are possible by using CNAMEs. (See
.B --cname
).
More than one
.B --dhcp-host
can be associated (by name, hardware address or UID) with a host. Which one is used
(and therefore which address is allocated by DHCP and appears in the DNS) depends
on the subnet on which the host last obtained a DHCP lease:
the
.B --dhcp-host
with an address within the subnet is used. If more than one address is within the subnet,
the result is undefined. A corollary to this is that the name associated with a host using
.B --dhcp-host
does not appear in the DNS until the host obtains a DHCP lease.
The special keyword "ignore"
tells dnsmasq to never offer a DHCP lease to a machine. The machine
can be specified by hardware address, client ID or hostname, for
@@ -1458,7 +1436,7 @@ functions when supported by a suitable DHCP server.
This specifies a boot option which may appear in a PXE boot menu. <CSA> is
client system type, only services of the correct type will appear in a
menu. The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
Intel_Lean_Client, IA32_EFI, x86-64_EFI, Xscale_EFI, BC_EFI, ARM32_EFI and ARM64_EFI; an
Intel_Lean_Client, IA32_EFI, X86-64_EFI, Xscale_EFI, BC_EFI, ARM32_EFI and ARM64_EFI; an
integer may be used for other types. The
parameter after the menu text may be a file name, in which case dnsmasq acts as a
boot server and directs the PXE client to download the file by TFTP,
@@ -1502,22 +1480,6 @@ to allow netbooting. This mode is enabled using the
.B proxy
keyword in
.B --dhcp-range.
.TP
.B --dhcp-pxe-vendor=<vendor>[,...]
According to UEFI and PXE specifications, DHCP packets between PXE clients and
proxy PXE servers should have
.I PXEClient
in their vendor-class field. However, the firmware of computers from a few
vendors is customized to carry a different identifier in that field. This option
is used to consider such identifiers valid for identifying PXE clients. For
instance
.B --dhcp-pxe-vendor=PXEClient,HW-Client
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
.I HW-Client
in as their identifier.
>>>>>>> 907def3... pxe: support pxe clients with custom vendor-class
.TP
.B \-X, --dhcp-lease-max=<number>
Limits dnsmasq to the specified maximum number of DHCP leases. The
@@ -2389,8 +2351,6 @@ IPv4 and IPv6 addresses from /etc/hosts (and
.B --host-record
and
.B --interface-name
and
.B ---dynamic-host
provided the address falls into one of the subnets specified in the
.B --auth-zone.
.PP
+723 -709
View File
File diff suppressed because it is too large. Load diff
+467 -504
View File
File diff suppressed because it is too large. Load diff
+467 -502
View File
File diff suppressed because it is too large. Load diff
+467 -504
View File
File diff suppressed because it is too large. Load diff
+500 -540
View File
File diff suppressed because it is too large. Load diff
+467 -502
View File
File diff suppressed because it is too large. Load diff
+467 -504
View File
File diff suppressed because it is too large. Load diff
+467 -504
View File
File diff suppressed because it is too large. Load diff
+467 -502
View File
File diff suppressed because it is too large. Load diff
+467 -504
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+2 -9
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
@@ -119,9 +120,6 @@ HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
HAVE_CRYPTOHASH
include just hash function from crypto library, but no DNSSEC.
HAVE_DNSSEC
include DNSSEC validator.
@@ -189,7 +187,6 @@ RESOLVFILE
/* #define HAVE_IDN */
/* #define HAVE_LIBIDN2 */
/* #define HAVE_CONNTRACK */
/* #define HAVE_CRYPTOHASH */
/* #define HAVE_DNSSEC */
@@ -423,10 +420,6 @@ static char *compile_opts =
"no-"
#endif
"auth "
#if !defined(HAVE_CRYPTOHASH) && !defined(HAVE_DNSSEC)
"no-"
#endif
"cryptohash "
#ifndef HAVE_DNSSEC
"no-"
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+11 -28
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,25 +18,13 @@
#ifdef HAVE_DNSSEC
/* Minimal version of nettle */
#define MIN_VERSION(major, minor) (NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
(NETTLE_VERSION_MAJOR > (major))
#include <nettle/rsa.h>
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#if !defined(NETTLE_VERSION_MAJOR)
#define NETTLE_VERSION_MAJOR 2
#endif
#if MIN_VERSION(3, 1)
#include <nettle/eddsa.h>
#endif
#if MIN_VERSION(3, 6)
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
# include <nettle/gostdsa.h>
#endif
#endif
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
#include <nettle/nettle-meta.h>
#include <nettle/bignum.h>
@@ -124,8 +112,10 @@ const struct nettle_hash *hash_find(char *name)
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
incompatibilities if sizeof(nettle_hashes) changes between library
versions. */
#if MIN_VERSION(3, 4)
versions. It also #defines nettle_hashes, so use that to tell
if we have the new facilities. */
#ifdef nettle_hashes
return nettle_lookup_hash(name);
#else
{
@@ -177,10 +167,6 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
return 1;
}
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
#ifdef HAVE_DNSSEC
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -245,7 +231,7 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
static mpz_t x, y;
static struct dsa_signature *sig_struct;
#if !MIN_VERSION(3, 4)
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR < 4
#define nettle_get_secp_256r1() (&nettle_secp_256r1)
#define nettle_get_secp_384r1() (&nettle_secp_384r1)
#endif
@@ -308,7 +294,7 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
}
#if MIN_VERSION(3, 6)
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -349,7 +335,6 @@ static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_l
}
#endif
#if MIN_VERSION(3, 1)
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -376,7 +361,7 @@ static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len
((struct null_hash_digest *)digest)->buff,
sig);
#if MIN_VERSION(3, 6)
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
case 16:
if (key_len != ED448_KEY_SIZE ||
sig_len != ED448_SIGNATURE_SIZE)
@@ -392,7 +377,6 @@ static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len
return 0;
}
#endif
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -408,17 +392,16 @@ static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key
case 5: case 7: case 8: case 10:
return dnsmasq_rsa_verify;
#if MIN_VERSION(3, 6)
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
case 12:
return dnsmasq_gostdsa_verify;
#endif
case 13: case 14:
return dnsmasq_ecdsa_verify;
#if MIN_VERSION(3, 1)
case 15: case 16:
return dnsmasq_eddsa_verify;
#endif
}
return NULL;
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+16 -14
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -280,29 +280,31 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
return 1;
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_V6)
{
struct addrlist *addr_list;
if (config->flags & CONFIG_ADDR6)
for (; context; context = context->current)
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
{
if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
return 1;
if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
return 1;
}
if (!(config->flags & CONFIG_ADDR6))
return 1;
for (; context; context = context->current)
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
{
if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
return 1;
if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
return 1;
}
}
else
#endif
{
if (!(config->flags & CONFIG_ADDR))
return 1;
for (; context; context = context->current)
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
return 1;
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+15 -39
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -237,16 +237,9 @@ int main (int argc, char **argv)
die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
#endif
/* Handle only one of min_port/max_port being set. */
if (daemon->min_port != 0 && daemon->max_port == 0)
daemon->max_port = MAX_PORT;
if (daemon->max_port != 0 && daemon->min_port == 0)
daemon->min_port = MIN_PORT;
if (daemon->max_port < daemon->min_port)
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
now = dnsmasq_time();
if (daemon->auth_zones)
@@ -397,16 +390,8 @@ int main (int argc, char **argv)
if (daemon->port != 0)
{
cache_init();
blockdata_init();
hash_questions_init();
/* Scale random socket pool by ftabsize, but
limit it based on available fds. */
daemon->numrrand = daemon->ftabsize/2;
if (daemon->numrrand > max_fd/3)
daemon->numrrand = max_fd/3;
/* safe_malloc returns zero'd memory */
daemon->randomsocks = safe_malloc(daemon->numrrand * sizeof(struct randfd));
blockdata_init();
}
#ifdef HAVE_INOTIFY
@@ -995,7 +980,7 @@ int main (int argc, char **argv)
a single file will be sent to may clients (the file only needs
one fd). */
max_fd -= 30 + daemon->numrrand; /* use other than TFTP */
max_fd -= 30; /* use other than TFTP */
if (max_fd < 0)
max_fd = 5;
@@ -1687,7 +1672,6 @@ static int set_dns_listeners(time_t now)
{
struct serverfd *serverfdp;
struct listener *listener;
struct randfd_list *rfl;
int wait = 0, i;
#ifdef HAVE_TFTP
@@ -1708,14 +1692,11 @@ static int set_dns_listeners(time_t now)
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
poll_listen(serverfdp->fd, POLLIN);
for (i = 0; i < daemon->numrrand; i++)
if (daemon->randomsocks[i].refcount != 0)
poll_listen(daemon->randomsocks[i].fd, POLLIN);
/* Check overflow random sockets too. */
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
poll_listen(rfl->rfd->fd, POLLIN);
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0)
poll_listen(daemon->randomsocks[i].fd, POLLIN);
for (listener = daemon->listeners; listener; listener = listener->next)
{
/* only listen for queries if we have resources */
@@ -1752,23 +1733,18 @@ static void check_dns_listeners(time_t now)
{
struct serverfd *serverfdp;
struct listener *listener;
struct randfd_list *rfl;
int i;
int pipefd[2];
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (poll_check(serverfdp->fd, POLLIN))
reply_query(serverfdp->fd, now);
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
for (i = 0; i < daemon->numrrand; i++)
if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, now);
/* Check overflow random sockets too. */
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
if (poll_check(rfl->rfd->fd, POLLIN))
reply_query(rfl->rfd->fd, now);
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
/* Races. The child process can die before we read all of the data from the
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
+40 -73
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (c) 2000-2021 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2020 Simon Kelley"
/* We do defines that influence behavior of stdio.h, so complain
if included too early. */
@@ -95,7 +95,11 @@ typedef unsigned long long u64;
#if defined(HAVE_SOLARIS_NETWORK)
# include <sys/sockio.h>
#endif
#include <poll.h>
#if defined(HAVE_POLL_H)
# include <poll.h>
#else
# include <sys/poll.h>
#endif
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/un.h>
@@ -153,11 +157,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
#include <priv.h>
#endif
/* Backwards compat with 2.83 */
#if defined(HAVE_NETTLEHASH)
# define HAVE_CRYPTOHASH
#endif
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
#ifdef HAVE_DNSSEC
# include <nettle/nettle-meta.h>
#endif
@@ -269,8 +269,7 @@ struct event_desc {
#define OPT_IGNORE_CLID 59
#define OPT_SINGLE_PORT 60
#define OPT_LEASE_RENEW 61
#define OPT_LOG_DEBUG 62
#define OPT_LAST 63
#define OPT_LAST 62
#define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
@@ -278,13 +277,11 @@ struct event_desc {
#define option_val(x) ((1u) << ((x) % OPTION_BITS))
#define option_bool(x) (option_var(x) & option_val(x))
/* extra flags for my_syslog, we use facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up.
MS_DEBUG messages are suppressed unless --log-debug is set. */
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
#define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON
#define MS_SCRIPT LOG_MAIL
#define MS_DEBUG LOG_NEWS
/* Note that this is used widely as a container for IPv4/IPv6 addresses,
so for that reason, was well as to avoid wasting memory in almost every
@@ -325,7 +322,7 @@ union all_addr {
struct bogus_addr {
struct in_addr addr, mask;
struct in_addr addr;
struct bogus_addr *next;
};
@@ -426,17 +423,10 @@ struct host_record {
struct host_record *next;
};
#define IN4 1
#define IN6 2
#define INP4 4
#define INP6 8
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
int flags;
struct in_addr proto4;
struct in6_addr proto6;
int family; /* AF_INET, AF_INET6 or zero for both */
struct addrlist *addr;
struct interface_name *next;
};
@@ -549,20 +539,13 @@ struct serverfd {
};
struct randfd {
struct server *serv;
int fd;
unsigned short refcount; /* refcount == 0xffff means overflow record. */
unsigned short refcount, family;
};
struct randfd_list {
struct randfd *rfd;
struct randfd_list *next;
};
struct server {
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
unsigned int ifindex; /* corresponding to interface, above */
struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */
int flags, tcpfd, edns_pktsz;
@@ -670,25 +653,23 @@ struct hostsfile {
#define FREC_DO_QUESTION 64
#define FREC_ADDED_PHEADER 128
#define FREC_TEST_PKTSZ 256
#define FREC_HAS_EXTRADATA 512
#define FREC_HAS_PHEADER 1024
#define FREC_NO_CACHE 2048
#define FREC_HAS_EXTRADATA 512
#define HASH_SIZE 32 /* SHA-256 digest size */
#ifdef HAVE_DNSSEC
#define HASH_SIZE 20 /* SHA-1 digest size */
#else
#define HASH_SIZE sizeof(int)
#endif
struct frec {
struct frec_src {
union mysockaddr source;
union all_addr dest;
unsigned int iface, log_id;
int fd;
unsigned short orig_id;
struct frec_src *next;
} frec_src;
union mysockaddr source;
union all_addr dest;
struct server *sentto; /* NULL means free */
struct randfd_list *rfds;
unsigned short new_id;
int forwardall, flags;
struct randfd *rfd4;
struct randfd *rfd6;
unsigned int iface;
unsigned short orig_id, new_id;
int log_id, fd, forwardall, flags;
time_t time;
unsigned char *hash[HASH_SIZE];
#ifdef HAVE_DNSSEC
@@ -848,7 +829,6 @@ struct dhcp_opt {
#define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192
#define DHOPT_VENDOR_PXE 16384
struct dhcp_boot {
char *file, *sname, *tftp_sname;
@@ -872,8 +852,6 @@ struct pxe_service {
struct pxe_service *next;
};
#define DHCP_PXE_DEF_VENDOR "PXEClient"
#define MATCH_VENDOR 1
#define MATCH_USER 2
#define MATCH_CIRCUIT 3
@@ -889,11 +867,6 @@ struct dhcp_vendor {
struct dhcp_vendor *next;
};
struct dhcp_pxe_vendor {
char *data;
struct dhcp_pxe_vendor *next;
};
struct dhcp_mac {
unsigned int mask;
int hwaddr_len, hwaddr_type;
@@ -1067,7 +1040,6 @@ extern struct daemon {
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_match_name *dhcp_name_match;
struct dhcp_pxe_vendor *dhcp_pxe_vendors;
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
@@ -1116,8 +1088,6 @@ extern struct daemon {
int back_to_the_future;
#endif
struct frec *frec_list;
struct frec_src *free_frec_src;
int frec_src_count;
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
@@ -1126,13 +1096,11 @@ extern struct daemon {
int forwardcount;
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
int fd_save; /* " " */
struct randfd *rfd_save; /* " " */
pid_t tcp_pids[MAX_PROCS];
int tcp_pipes[MAX_PROCS];
int pipe_to_parent;
int numrrand;
struct randfd *randomsocks;
struct randfd_list *rfl_spare, *rfl_poll;
struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo;
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
int log_id, log_display_id; /* ids of transactions for logging */
@@ -1249,9 +1217,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen);
struct bogus_addr *baddr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
int check_for_local_domain(char *name, time_t now);
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen);
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
@@ -1276,12 +1245,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl);
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
size_t filter_rrsigs(struct dns_header *header, size_t plen);
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
int setup_timestamp(void);
/* hash_questions.c */
void hash_questions_init(void);
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
/* crypto.c */
const struct nettle_hash *hash_find(char *name);
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
@@ -1304,7 +1270,7 @@ void safe_strncpy(char *dest, const char *src, size_t size);
void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(const char *a, const char *b);
int hostname_issubdomain(char *a, char *b);
time_t dnsmasq_time(void);
@@ -1355,7 +1321,7 @@ char *parse_server(char *arg, union mysockaddr *addr,
int option_read_dynfile(char *file, int flags);
/* forward.c */
void reply_query(int fd, time_t now);
void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
@@ -1365,12 +1331,13 @@ int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, union all_addr *source,
unsigned int iface);
void resend_query(void);
int allocate_rfd(struct randfd_list **fdlp, struct server *serv);
void free_rfds(struct randfd_list **fdlp);
struct randfd *allocate_rfd(int family);
void free_rfd(struct randfd *rfd);
/* network.c */
int indextoname(int fd, int index, char *name);
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void mark_servers(int flag);
@@ -1678,7 +1645,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable);
union mysockaddr *source, time_t now, int *check_subnet);
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
/* arp.c */
+86 -98
View File
@@ -334,64 +334,37 @@ static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
return rrsetidx; /* short packet */
state2.end = state2.ip + rdlen2;
/* If the RR has no names in it then canonicalisation
is the identity function and we can compare
the RRs directly. If not we compare the
canonicalised RRs one byte at a time. */
if (*rr_desc == (u16)-1)
while (1)
{
int rdmin = rdlen1 > rdlen2 ? rdlen2 : rdlen1;
int cmp = memcmp(state1.ip, state2.ip, rdmin);
int ok1, ok2;
if (cmp > 0 || (cmp == 0 && rdlen1 > rdmin))
{
unsigned char *tmp = rrset[i+1];
rrset[i+1] = rrset[i];
rrset[i] = tmp;
swap = 1;
}
else if (cmp == 0 && (rdlen1 == rdlen2))
ok1 = get_rdata(header, plen, &state1);
ok2 = get_rdata(header, plen, &state2);
if (!ok1 && !ok2)
{
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
for (j = i+1; j < rrsetidx-1; j++)
rrset[j] = rrset[j+1];
rrsetidx--;
i--;
}
}
else
/* Comparing canonicalised RRs, byte-at-a-time. */
while (1)
{
int ok1, ok2;
ok1 = get_rdata(header, plen, &state1);
ok2 = get_rdata(header, plen, &state2);
if (!ok1 && !ok2)
{
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
for (j = i+1; j < rrsetidx-1; j++)
rrset[j] = rrset[j+1];
rrsetidx--;
i--;
break;
}
else if (ok1 && (!ok2 || *state1.op > *state2.op))
{
unsigned char *tmp = rrset[i+1];
rrset[i+1] = rrset[i];
rrset[i] = tmp;
swap = 1;
break;
}
else if (ok2 && (!ok1 || *state2.op > *state1.op))
break;
/* arrive here when bytes are equal, go round the loop again
and compare the next ones. */
}
}
else if (ok1 && (!ok2 || *state1.op > *state2.op))
{
unsigned char *tmp = rrset[i+1];
rrset[i+1] = rrset[i];
rrset[i] = tmp;
swap = 1;
break;
}
else if (ok2 && (!ok1 || *state2.op > *state1.op))
break;
/* arrive here when bytes are equal, go round the loop again
and compare the next ones. */
}
}
} while (swap);
@@ -606,7 +579,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
from_wire(keyname);
#define RRBUFLEN 128 /* Most RRs are smaller than this. */
#define RRBUFLEN 300 /* Most RRs are smaller than this. */
for (i = 0; i < rrsetidx; ++i)
{
@@ -644,66 +617,50 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
hash->update(ctx, 4, p); /* class and type */
hash->update(ctx, 4, (unsigned char *)&nsigttl);
p += 8; /* skip type, class, ttl */
p += 8; /* skip class, type, ttl */
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return STAT_BOGUS;
/* canonicalise rdata and calculate length of same, use
name buffer as workspace for get_rdata. */
state.ip = p;
state.op = NULL;
state.desc = rr_desc;
state.buff = name;
state.end = p + rdlen;
for (j = 0; get_rdata(header, plen, &state); j++)
if (j < RRBUFLEN)
rrbuf[j] = *state.op;
/* Optimisation for RR types which need no cannonicalisation.
This includes DNSKEY DS NSEC and NSEC3, which are also long, so
it saves lots of calls to get_rdata, and avoids the pessimal
segmented insertion, even with a small rrbuf[].
If canonicalisation is not needed, a simple insertion into the hash works.
*/
if (*rr_desc == (u16)-1)
len = htons((u16)j);
hash->update(ctx, 2, (unsigned char *)&len);
/* If the RR is shorter than RRBUFLEN (most of them, in practice)
then we can just digest it now. If it exceeds RRBUFLEN we have to
go back to the start and do it in chunks. */
if (j >= RRBUFLEN)
{
len = htons(rdlen);
hash->update(ctx, 2, (unsigned char *)&len);
hash->update(ctx, rdlen, p);
}
else
{
/* canonicalise rdata and calculate length of same, use
name buffer as workspace for get_rdata. */
state.ip = p;
state.op = NULL;
state.desc = rr_desc;
state.buff = name;
state.end = p + rdlen;
for (j = 0; get_rdata(header, plen, &state); j++)
if (j < RRBUFLEN)
rrbuf[j] = *state.op;
len = htons((u16)j);
hash->update(ctx, 2, (unsigned char *)&len);
/* If the RR is shorter than RRBUFLEN (most of them, in practice)
then we can just digest it now. If it exceeds RRBUFLEN we have to
go back to the start and do it in chunks. */
if (j >= RRBUFLEN)
{
state.ip = p;
state.op = NULL;
state.desc = rr_desc;
for (j = 0; get_rdata(header, plen, &state); j++)
{
rrbuf[j] = *state.op;
if (j == RRBUFLEN - 1)
{
hash->update(ctx, RRBUFLEN, rrbuf);
j = -1;
}
}
rrbuf[j] = *state.op;
if (j == RRBUFLEN - 1)
{
hash->update(ctx, RRBUFLEN, rrbuf);
j = -1;
}
}
if (j != 0)
hash->update(ctx, j, rrbuf);
}
if (j != 0)
hash->update(ctx, j, rrbuf);
}
hash->digest(ctx, hash->digest_size, digest);
@@ -2130,4 +2087,35 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
return ret;
}
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
{
int q;
unsigned int len;
unsigned char *p = (unsigned char *)(header+1);
const struct nettle_hash *hash;
void *ctx;
unsigned char *digest;
if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
return NULL;
for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!extract_name(header, plen, &p, name, 1, 4))
break; /* bad packet */
len = to_wire(name);
hash->update(ctx, len, (unsigned char *)name);
/* CRC the class and type as well */
hash->update(ctx, 4, p);
p += 4;
if (!CHECK_LEN(header, p, plen, 0))
break; /* bad packet */
}
hash->digest(ctx, hash->digest_size, digest);
return digest;
}
#endif /* HAVE_DNSSEC */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+29 -48
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -264,8 +264,7 @@ static void encoder(unsigned char *in, char *out)
out[3] = char64(in[2]);
}
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *l3, time_t now, int *cacheablep)
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
{
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
unsigned char mac[DHCP_CHADDR_MAX];
@@ -274,7 +273,6 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
{
replace = 1;
*cacheablep = 0;
if (option_bool(OPT_MAC_HEX))
print_mac(encode, mac, maclen);
@@ -290,18 +288,14 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
}
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *l3, time_t now, int *cacheablep)
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
{
int maclen;
unsigned char mac[DHCP_CHADDR_MAX];
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
{
*cacheablep = 0;
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
}
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
return plen;
}
@@ -319,18 +313,17 @@ static void *get_addrp(union mysockaddr *addr, const short family)
return &addr->in.sin_addr;
}
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len;
void *addrp = NULL;
int sa_family = source->sa.sa_family;
int cacheable = 0;
opt->source_netmask = 0;
opt->scope_netmask = 0;
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
{
opt->source_netmask = daemon->add_subnet6->mask;
@@ -338,7 +331,6 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source,
{
sa_family = daemon->add_subnet6->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
cacheable = 1;
}
else
addrp = &source->in6.sin6_addr;
@@ -351,7 +343,6 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source,
{
sa_family = daemon->add_subnet4->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
cacheable = 1; /* Address is constant */
}
else
addrp = &source->in.sin_addr;
@@ -359,6 +350,8 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source,
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
len = 0;
if (addrp && opt->source_netmask != 0)
{
len = ((opt->source_netmask - 1) >> 3) + 1;
@@ -366,26 +359,18 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source,
if (opt->source_netmask & 7)
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
}
else
{
cacheable = 1; /* No address ever supplied. */
len = 0;
}
if (cacheablep)
*cacheablep = cacheable;
return len + 4;
}
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len;
struct subnet_opt opt;
len = calc_subnet_opt(&opt, source, cacheable);
len = calc_subnet_opt(&opt, source);
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
}
@@ -398,18 +383,18 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
unsigned char *p;
int code, i, rdlen;
calc_len = calc_subnet_opt(&opt, peer, NULL);
calc_len = calc_subnet_opt(&opt, peer);
if (!(p = skip_name(pseudoheader, header, plen, 10)))
return 1;
p += 8; /* skip UDP length and RCODE */
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return 1; /* bad packet */
/* check if option there */
if (!(p = skip_name(pseudoheader, header, plen, 10)))
return 1;
p += 8; /* skip UDP length and RCODE */
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return 1; /* bad packet */
/* check if option there */
for (i = 0; i + 4 < rdlen; i += len + 4)
{
GETSHORT(code, p);
@@ -427,28 +412,24 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
return 1;
}
/* Set *check_subnet if we add a client subnet option, which needs to checked
in the reply. Set *cacheable to zero if we add an option which the answer
may depend on. */
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)
union mysockaddr *source, time_t now, int *check_subnet)
{
*check_subnet = 0;
*cacheable = 1;
if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, limit, source, now, cacheable);
plen = add_mac(header, plen, limit, source, now);
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
plen = add_dns_client(header, plen, limit, source, now, cacheable);
plen = add_dns_client(header, plen, limit, source, now);
if (daemon->dns_client_id)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
if (option_bool(OPT_CLIENT_SUBNET))
{
plen = add_source_addr(header, plen, limit, source, cacheable);
plen = add_source_addr(header, plen, limit, source);
*check_subnet = 1;
}
+316 -491
View File
File diff suppressed because it is too large. Load diff
-284
View File
@@ -1,284 +0,0 @@
/* Copyright (c) 2012-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Hash the question section. This is used to safely detect query
retransmission and to detect answers to questions we didn't ask, which
might be poisoning attacks. Note that we decode the name rather
than CRC the raw bytes, since replies might be compressed differently.
We ignore case in the names for the same reason.
The hash used is SHA-256. If we're building with DNSSEC support,
we use the Nettle cypto library. If not, we prefer not to
add a dependency on Nettle, and use a stand-alone implementaion.
*/
#include "dnsmasq.h"
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
static const struct nettle_hash *hash;
static void *ctx;
static unsigned char *digest;
void hash_questions_init(void)
{
if (!(hash = hash_find("sha256")))
die(_("Failed to create SHA-256 hash object"), NULL, EC_MISC);
ctx = safe_malloc(hash->context_size);
digest = safe_malloc(hash->digest_size);
}
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
{
int q;
unsigned char *p = (unsigned char *)(header+1);
hash->init(ctx);
for (q = ntohs(header->qdcount); q != 0; q--)
{
char *cp, c;
if (!extract_name(header, plen, &p, name, 1, 4))
break; /* bad packet */
for (cp = name; (c = *cp); cp++)
if (c >= 'A' && c <= 'Z')
*cp += 'a' - 'A';
hash->update(ctx, cp - name, (unsigned char *)name);
/* CRC the class and type as well */
hash->update(ctx, 4, p);
p += 4;
if (!CHECK_LEN(header, p, plen, 0))
break; /* bad packet */
}
hash->digest(ctx, hash->digest_size, digest);
return digest;
}
#else /* HAVE_DNSSEC || HAVE_CRYPTOHASH */
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
typedef unsigned char BYTE; // 8-bit byte
typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct {
BYTE data[64];
WORD datalen;
unsigned long long bitlen;
WORD state[8];
} SHA256_CTX;
static void sha256_init(SHA256_CTX *ctx);
static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
static void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
void hash_questions_init(void)
{
}
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
{
int q;
unsigned char *p = (unsigned char *)(header+1);
SHA256_CTX ctx;
static BYTE digest[SHA256_BLOCK_SIZE];
sha256_init(&ctx);
for (q = ntohs(header->qdcount); q != 0; q--)
{
char *cp, c;
if (!extract_name(header, plen, &p, name, 1, 4))
break; /* bad packet */
for (cp = name; (c = *cp); cp++)
if (c >= 'A' && c <= 'Z')
*cp += 'a' - 'A';
sha256_update(&ctx, (BYTE *)name, cp - name);
/* CRC the class and type as well */
sha256_update(&ctx, (BYTE *)p, 4);
p += 4;
if (!CHECK_LEN(header, p, plen, 0))
break; /* bad packet */
}
sha256_final(&ctx, digest);
return (unsigned char *)digest;
}
/* Code from here onwards comes from https://github.com/B-Con/crypto-algorithms
and was written by Brad Conte (brad@bradconte.com), to whom all credit is given.
This code is in the public domain, and the copyright notice at the head of this
file does not apply to it.
*/
/****************************** MACROS ******************************/
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
/**************************** VARIABLES *****************************/
static const WORD k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
/*********************** FUNCTION DEFINITIONS ***********************/
static void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
{
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
for ( ; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i)
{
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
t2 = EP0(a) + MAJ(a,b,c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
static void sha256_init(SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
{
WORD i;
for (i = 0; i < len; ++i)
{
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
{
WORD i;
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56)
{
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else
{
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (i = 0; i < 4; ++i)
{
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -378,7 +378,7 @@ void lease_update_file(time_t now)
if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
next_event = LEASE_RETRY + now;
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %u s)"),
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
daemon->lease_file, strerror(err),
(unsigned int)difftime(next_event, now));
}
+3 -9
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -273,7 +273,7 @@ static void log_write(void)
/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
DNS, DHCP and TFTP services.
If OR'd with MS_DEBUG, the messages are suppressed unless --log-debug is set. */
*/
void my_syslog(int priority, const char *format, ...)
{
va_list ap;
@@ -290,13 +290,7 @@ void my_syslog(int priority, const char *format, ...)
func = "-dhcp";
else if ((LOG_FACMASK & priority) == MS_SCRIPT)
func = "-script";
else if ((LOG_FACMASK & priority) == MS_DEBUG)
{
if (!option_bool(OPT_LOG_DEBUG))
return;
func = "-debug";
}
#ifdef LOG_PRI
priority = LOG_PRI(priority);
#else
+14 -8
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@ static ssize_t loop_make_probe(u32 uid);
void loop_send_probes()
{
struct server *serv;
struct randfd_list *rfds = NULL;
if (!option_bool(OPT_LOOP_DETECT))
return;
@@ -35,22 +34,29 @@ void loop_send_probes()
{
ssize_t len = loop_make_probe(serv->uid);
int fd;
struct randfd *rfd = NULL;
if ((fd = allocate_rfd(&rfds, serv)) == -1)
continue;
if (serv->sfd)
fd = serv->sfd->fd;
else
{
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
continue;
fd = rfd->fd;
}
while (retry_send(sendto(fd, daemon->packet, len, 0,
&serv->addr.sa, sa_len(&serv->addr))));
free_rfd(rfd);
}
free_rfds(&rfds);
}
static ssize_t loop_make_probe(u32 uid)
{
struct dns_header *header = (struct dns_header *)daemon->packet;
unsigned char *p = (unsigned char *)(header+1);
/* packet buffer overwritten */
daemon->srv_save = NULL;
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+35 -52
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,26 +41,19 @@
#ifndef NDA_RTA
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#endif
/* Used to request refresh of addresses or routes just once,
* when multiple changes might be announced. */
enum async_states {
STATE_NEWADDR = (1 << 0),
STATE_NEWROUTE = (1 << 1),
};
#endif
static struct iovec iov;
static u32 netlink_pid;
static unsigned nl_async(struct nlmsghdr *h, unsigned state);
static void nl_multicast_state(unsigned state);
static void nl_async(struct nlmsghdr *h);
char *netlink_init(void)
{
struct sockaddr_nl addr;
socklen_t slen = sizeof(addr);
int opt = 1;
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
@@ -99,10 +92,14 @@ char *netlink_init(void)
iov.iov_len = 100;
iov.iov_base = safe_malloc(iov.iov_len);
if (daemon->kernel_version >= KERNEL_VERSION(2,6,30) &&
setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1)
return _("warning: failed to set NETLINK_NO_ENOBUFS on netlink socket");
return NULL;
}
static ssize_t netlink_recv(int flags)
static ssize_t netlink_recv(void)
{
struct msghdr msg;
struct sockaddr_nl nladdr;
@@ -118,8 +115,7 @@ static ssize_t netlink_recv(int flags)
msg.msg_iovlen = 1;
msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, flags | MSG_PEEK | MSG_TRUNC)) == -1 &&
errno == EINTR);
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
/* make buffer big enough */
if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
@@ -136,7 +132,7 @@ static ssize_t netlink_recv(int flags)
/* read it for real */
msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, flags)) == -1 && errno == EINTR);
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
/* Make sure this is from the kernel */
if (rc == -1 || nladdr.nl_pid == 0)
@@ -155,9 +151,7 @@ static ssize_t netlink_recv(int flags)
/* family = AF_UNSPEC finds ARP table entries.
family = AF_LOCAL finds MAC addresses.
returns 0 on failure, 1 on success, -1 when restart is required
*/
family = AF_LOCAL finds MAC addresses. */
int iface_enumerate(int family, void *parm, int (*callback)())
{
struct sockaddr_nl addr;
@@ -165,7 +159,6 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ssize_t len;
static unsigned int seq = 0;
int callback_ok = 1;
unsigned state = 0;
struct {
struct nlmsghdr nlh;
@@ -177,6 +170,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr.nl_family = AF_NETLINK;
again:
if (family == AF_UNSPEC)
req.nlh.nlmsg_type = RTM_GETNEIGH;
else if (family == AF_LOCAL)
@@ -199,12 +193,12 @@ int iface_enumerate(int family, void *parm, int (*callback)())
while (1)
{
if ((len = netlink_recv(0)) == -1)
if ((len = netlink_recv()) == -1)
{
if (errno == ENOBUFS)
{
nl_multicast_state(state);
return -1;
sleep(1);
goto again;
}
return 0;
}
@@ -213,7 +207,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{
/* May be multicast arriving async */
state = nl_async(h, state);
nl_async(h);
}
else if (h->nlmsg_seq != seq)
{
@@ -347,28 +341,26 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
}
static void nl_multicast_state(unsigned state)
void netlink_multicast(void)
{
ssize_t len;
struct nlmsghdr *h;
do {
/* don't risk blocking reading netlink messages here. */
while ((len = netlink_recv(MSG_DONTWAIT)) != -1)
int flags;
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
state = nl_async(h, state);
} while (errno == ENOBUFS);
/* don't risk blocking reading netlink messages here. */
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
return;
if ((len = netlink_recv()) != -1)
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
nl_async(h);
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
}
void netlink_multicast(void)
{
unsigned state = 0;
nl_multicast_state(state);
}
static unsigned nl_async(struct nlmsghdr *h, unsigned state)
static void nl_async(struct nlmsghdr *h)
{
if (h->nlmsg_type == NLMSG_ERROR)
{
@@ -376,8 +368,7 @@ static unsigned nl_async(struct nlmsghdr *h, unsigned state)
if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
}
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE &&
(state & STATE_NEWROUTE)==0)
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
{
/* We arrange to receive netlink multicast messages whenever the network route is added.
If this happens and we still have a DNS packet in the buffer, we re-send it.
@@ -389,18 +380,10 @@ static unsigned nl_async(struct nlmsghdr *h, unsigned state)
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
(rtm->rtm_table == RT_TABLE_MAIN ||
rtm->rtm_table == RT_TABLE_LOCAL))
{
queue_event(EVENT_NEWROUTE);
state |= STATE_NEWROUTE;
}
queue_event(EVENT_NEWROUTE);
}
else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
(state & STATE_NEWADDR)==0)
{
queue_event(EVENT_NEWADDR);
state |= STATE_NEWADDR;
}
return state;
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
queue_event(EVENT_NEWADDR);
}
#endif
+114 -193
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -232,7 +232,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)
{
struct irec *iface;
int loopback;
int mtu = 0, loopback;
struct ifreq ifr;
int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1;
@@ -253,6 +253,9 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
if (loopback)
dhcp_ok = 0;
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
if (!label)
label = ifr.ifr_name;
else
@@ -348,109 +351,36 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
/* Update addresses from interface_names. These are a set independent
of the set we're listening on. */
for (int_name = daemon->int_names; int_name; int_name = int_name->next)
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0 &&
(addr->sa.sa_family == int_name->family || int_name->family == 0))
{
struct addrlist *lp;
al = NULL;
if (addr->sa.sa_family == AF_INET && (int_name->flags & (IN4 | INP4)))
if (param->spare)
{
struct in_addr newaddr = addr->in.sin_addr;
if (int_name->flags & INP4)
{
if (netmask.s_addr == 0xffff)
continue;
newaddr.s_addr = (addr->in.sin_addr.s_addr & netmask.s_addr) |
(int_name->proto4.s_addr & ~netmask.s_addr);
}
/* check for duplicates. */
for (lp = int_name->addr; lp; lp = lp->next)
if (lp->flags == 0 && lp->addr.addr4.s_addr == newaddr.s_addr)
break;
if (!lp)
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->flags = 0;
al->addr.addr4 = newaddr;
}
}
}
if (addr->sa.sa_family == AF_INET6 && (int_name->flags & (IN6 | INP6)))
{
struct in6_addr newaddr = addr->in6.sin6_addr;
if (int_name->flags & INP6)
{
int i;
/* No sense in doing /128. */
if (prefixlen == 128)
continue;
for (i = 0; i < 16; i++)
{
int bits = ((i+1)*8) - prefixlen;
if (bits >= 8)
newaddr.s6_addr[i] = int_name->proto6.s6_addr[i];
else if (bits >= 0)
{
unsigned char mask = 0xff << bits;
newaddr.s6_addr[i] =
(addr->in6.sin6_addr.s6_addr[i] & mask) |
(int_name->proto6.s6_addr[i] & ~mask);
}
}
}
/* check for duplicates. */
for (lp = int_name->addr; lp; lp = lp->next)
if ((lp->flags & ADDRLIST_IPV6) &&
IN6_ARE_ADDR_EQUAL(&lp->addr.addr6, &newaddr))
break;
if (!lp)
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->flags = ADDRLIST_IPV6;
al->addr.addr6 = newaddr;
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
don't appear in forward queries, but will in reverse ones. */
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
al->flags |= ADDRLIST_REVONLY;
}
}
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = int_name->addr;
int_name->addr = al;
if (addr->sa.sa_family == AF_INET)
{
al->addr.addr4 = addr->in.sin_addr;
al->flags = 0;
}
else
{
al->addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
don't appear in forward queries, but will in reverse ones. */
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
al->flags |= ADDRLIST_REVONLY;
}
}
}
}
@@ -528,11 +458,6 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
/* add to list */
if ((iface = whine_malloc(sizeof(struct irec))))
{
int mtu = 0;
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
iface->addr = *addr;
iface->netmask = netmask;
iface->tftp_ok = tftp_ok;
@@ -667,7 +592,7 @@ static int release_listener(struct listener *l)
int port;
port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);
my_syslog(LOG_DEBUG|MS_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
l->iface->name, l->iface->index, daemon->addrbuff, port);
/* In case it ever returns */
l->iface->done = 0;
@@ -696,8 +621,7 @@ int enumerate_interfaces(int reset)
#ifdef HAVE_AUTH
struct auth_zone *zone;
#endif
struct server *serv;
/* Do this max once per select cycle - also inhibits netlink socket use
in TCP child processes. */
@@ -714,26 +638,7 @@ int enumerate_interfaces(int reset)
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
/* iface indexes can change when interfaces are created/destroyed.
We use them in the main forwarding control path, when the path
to a server is specified by an interface, so cache them.
Update the cache here. */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->interface[0] != 0)
{
#ifdef HAVE_LINUX_NETWORK
struct ifreq ifr;
safe_strncpy(ifr.ifr_name, serv->interface, IF_NAMESIZE);
if (ioctl(param.fd, SIOCGIFINDEX, &ifr) != -1)
serv->ifindex = ifr.ifr_ifindex;
#else
serv->ifindex = if_nametoindex(serv->interface);
#endif
}
again:
/* Mark interfaces for garbage collection */
for (iface = daemon->interfaces; iface; iface = iface->next)
iface->found = 0;
@@ -785,14 +690,9 @@ again:
param.spare = spare;
ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
if (ret < 0)
goto again;
else if (ret)
{
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
if (ret < 0)
goto again;
}
if (ret)
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
errsave = errno;
close(param.fd);
@@ -827,7 +727,7 @@ again:
errno = errsave;
spare = param.spare;
return ret;
}
@@ -967,10 +867,10 @@ int tcp_interface(int fd, int af)
/* use mshdr so that the CMSDG_* macros are available */
msg.msg_control = daemon->packet;
msg.msg_controllen = len = daemon->packet_buff_sz;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
daemon->srv_save = NULL;
if (af == AF_INET)
{
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
@@ -1145,7 +1045,7 @@ void create_bound_listeners(int dienow)
if (!dienow)
{
int port = prettyprint_addr(&iface->addr, daemon->addrbuff);
my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s(#%d): %s port %d"),
my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s port %d"),
iface->name, iface->index, daemon->addrbuff, port);
}
}
@@ -1172,7 +1072,7 @@ void create_bound_listeners(int dienow)
if (!dienow)
{
int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
my_syslog(LOG_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
}
}
}
@@ -1306,58 +1206,74 @@ void join_multicast(int dienow)
}
#endif
/* return a UDP socket bound to a random port, have to cope with straying into
occupied port nos and reserved ones. */
int random_sock(int family)
{
int fd;
if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
{
union mysockaddr addr;
unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
int tries = ports_avail < 30 ? 3 * ports_avail : 100;
memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = family;
/* don't loop forever if all ports in use. */
if (fix_fd(fd))
while(tries--)
{
unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
if (family == AF_INET)
{
addr.in.sin_addr.s_addr = INADDR_ANY;
addr.in.sin_port = port;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
else
{
addr.in6.sin6_addr = in6addr_any;
addr.in6.sin6_port = port;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
}
if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
return fd;
if (errno != EADDRINUSE && errno != EACCES)
break;
}
close(fd);
}
return -1;
}
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
{
union mysockaddr addr_copy = *addr;
unsigned short port;
int tries = 1;
unsigned short ports_avail = 1;
if (addr_copy.sa.sa_family == AF_INET)
port = addr_copy.in.sin_port;
else
port = addr_copy.in6.sin6_port;
/* cannot set source _port_ for TCP connections. */
if (is_tcp)
port = 0;
else if (port == 0 && daemon->max_port != 0)
{
/* Bind a random port within the range given by min-port and max-port if either
or both are set. Otherwise use the OS's random ephemeral port allocation by
leaving port == 0 and tries == 1 */
ports_avail = daemon->max_port - daemon->min_port + 1;
tries = ports_avail < 30 ? 3 * ports_avail : 100;
port = htons(daemon->min_port + (rand16() % ports_avail));
if (addr_copy.sa.sa_family == AF_INET)
addr_copy.in.sin_port = 0;
else
addr_copy.in6.sin6_port = 0;
}
while (1)
{
/* elide bind() call if it's to port 0, address 0 */
if (addr_copy.sa.sa_family == AF_INET)
{
if (port == 0 && addr_copy.in.sin_addr.s_addr == 0)
break;
addr_copy.in.sin_port = port;
}
else
{
if (port == 0 && IN6_IS_ADDR_UNSPECIFIED(&addr_copy.in6.sin6_addr))
break;
addr_copy.in6.sin6_port = port;
}
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)
break;
if (errno != EADDRINUSE && errno != EACCES)
return 0;
if (--tries == 0)
return 0;
port = htons(daemon->min_port + (rand16() % ports_avail));
}
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
return 0;
if (!is_tcp && ifindex > 0)
{
@@ -1387,33 +1303,38 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
return 1;
}
static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsigned int ifindex)
static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
{
struct serverfd *sfd;
unsigned int ifindex = 0;
int errsave;
int opt = 1;
/* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL, this is
anything without an explictly set source port. */
if (!daemon->osport)
the INADDR_ANY/port0 socket have sfd set to NULL */
if (!daemon->osport && intname[0] == 0)
{
errno = 0;
if (addr->sa.sa_family == AF_INET &&
addr->in.sin_addr.s_addr == INADDR_ANY &&
addr->in.sin_port == htons(0))
return NULL;
if (addr->sa.sa_family == AF_INET6 &&
memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
addr->in6.sin6_port == htons(0))
return NULL;
}
if (intname && strlen(intname) != 0)
ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */
/* may have a suitable one already */
for (sfd = daemon->sfds; sfd; sfd = sfd->next )
if (ifindex == sfd->ifindex &&
sockaddr_isequal(&sfd->source_addr, addr) &&
strcmp(intname, sfd->interface) == 0)
if (sockaddr_isequal(&sfd->source_addr, addr) &&
strcmp(intname, sfd->interface) == 0 &&
ifindex == sfd->ifindex)
return sfd;
/* need to make a new one. */
@@ -1464,7 +1385,7 @@ void pre_allocate_sfds(void)
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
if ((sfd = allocate_sfd(&addr, "", 0)))
if ((sfd = allocate_sfd(&addr, "")))
sfd->preallocated = 1;
memset(&addr, 0, sizeof(addr));
@@ -1474,13 +1395,13 @@ void pre_allocate_sfds(void)
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
if ((sfd = allocate_sfd(&addr, "", 0)))
if ((sfd = allocate_sfd(&addr, "")))
sfd->preallocated = 1;
}
for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
!allocate_sfd(&srv->source_addr, srv->interface) &&
errno != 0 &&
option_bool(OPT_NOWILD))
{
@@ -1689,7 +1610,7 @@ void check_servers(void)
/* Do we need a socket set? */
if (!serv->sfd &&
!(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
!(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
+30 -93
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -167,9 +167,6 @@ struct myoption {
#define LOPT_IGNORE_CLID 358
#define LOPT_SINGLE_PORT 359
#define LOPT_SCRIPT_TIME 360
#define LOPT_PXE_VENDOR 361
#define LOPT_DYNHOST 362
#define LOPT_LOG_DEBUG 363
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -273,7 +270,6 @@ static const struct myoption opts[] =
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE },
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
{ "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
{ "interface-name", 1, 0, LOPT_INTNAME },
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
@@ -343,8 +339,6 @@ static const struct myoption opts[] =
{ "dumpfile", 1, 0, LOPT_DUMPFILE },
{ "dumpmask", 1, 0, LOPT_DUMPMASK },
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
{ NULL, 0, 0, 0 }
};
@@ -389,7 +383,6 @@ static struct {
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
{ 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
@@ -495,7 +488,6 @@ static struct {
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
{ LOPT_DYNHOST, ARG_DUP, "<name>,[<IPv4>][,<IPv6>],<interface-name>", gettext_noop("Specify host record in interface subnet"), NULL },
{ LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
@@ -517,7 +509,6 @@ static struct {
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
{ LOPT_LOG_DEBUG, OPT_LOG_DEBUG, NULL, gettext_noop("Log debugging information."), NULL },
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
@@ -819,8 +810,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (interface_opt)
{
#if defined(SO_BINDTODEVICE)
safe_strncpy(interface, source, IF_NAMESIZE);
source = interface_opt;
safe_strncpy(interface, interface_opt, IF_NAMESIZE);
#else
return _("interface binding not supported");
#endif
@@ -2488,14 +2478,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_IGNORE_ADDR: /* --ignore-address */
{
struct in_addr addr;
int prefix = 32;
unhide_metas(arg);
if (!arg ||
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)) ||
(inet_pton(AF_INET, arg, &addr) != 1))
ret_err(gen_err); /* error */
else
if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
{
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
if (option == 'B')
@@ -2508,11 +2492,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
baddr->next = daemon->ignore_addr;
daemon->ignore_addr = baddr;
}
baddr->mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
baddr->addr.s_addr = addr.s_addr & baddr->mask.s_addr;
baddr->addr = addr;
}
break;
}
else
ret_err(gen_err); /* error */
break;
}
case 'a': /* --listen-address */
case LOPT_AUTHPEER: /* --auth-peer */
@@ -3687,8 +3672,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->val = opt_malloc(new->len);
memcpy(new->val + 1, arg, new->len - 1);
new->u.vendor_class = NULL;
new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
new->u.vendor_class = (unsigned char *)"PXEClient";
new->flags = DHOPT_VENDOR;
if (comma && atoi_check(comma, &timeout))
*(new->val) = timeout;
@@ -3950,19 +3935,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->override_relays;
daemon->override_relays = new;
arg = comma;
}
break;
case LOPT_PXE_VENDOR: /* --dhcp-pxe-vendor */
{
while (arg) {
struct dhcp_pxe_vendor *new = opt_malloc(sizeof(struct dhcp_pxe_vendor));
comma = split(arg);
new->data = opt_string_alloc(arg);
new->next = daemon->dhcp_pxe_vendors;
daemon->dhcp_pxe_vendors = new;
arg = comma;
}
}
break;
@@ -4087,66 +4059,36 @@ err:
}
case LOPT_INTNAME: /* --interface-name */
case LOPT_DYNHOST: /* --dynamic-host */
{
struct interface_name *new, **up;
char *domain = arg;
char *domain = NULL;
comma = split(arg);
arg = split(arg);
if (!comma || !(domain = canonicalise_opt(arg)))
ret_err(_("bad interface name"));
new = opt_malloc(sizeof(struct interface_name));
memset(new, 0, sizeof(struct interface_name));
new->flags = IN4 | IN6;
new->next = NULL;
new->addr = NULL;
/* Add to the end of the list, so that first name
of an interface is used for PTR lookups. */
for (up = &daemon->int_names; *up; up = &((*up)->next));
*up = new;
while ((comma = split(arg)))
new->name = domain;
new->family = 0;
arg = split_chr(comma, '/');
if (arg)
{
if (inet_pton(AF_INET, arg, &new->proto4))
new->flags |= INP4;
else if (inet_pton(AF_INET6, arg, &new->proto6))
new->flags |= INP6;
else
break;
arg = comma;
}
if ((comma = split_chr(arg, '/')))
{
if (strcmp(comma, "4") == 0)
new->flags &= ~IN6;
else if (strcmp(comma, "6") == 0)
new->flags &= ~IN4;
if (strcmp(arg, "4") == 0)
new->family = AF_INET;
else if (strcmp(arg, "6") == 0)
new->family = AF_INET6;
else
ret_err_free(gen_err, new);
}
new->intr = opt_string_alloc(arg);
if (option == LOPT_DYNHOST)
{
if (!(new->flags & (INP4 | INP6)))
ret_err(_("missing address in dynamic host"));
if (!(new->flags & IN4) || !(new->flags & IN6))
arg = NULL; /* provoke error below */
new->flags &= ~(IN4 | IN6);
}
else
{
if (new->flags & (INP4 | INP6))
arg = NULL; /* provoke error below */
}
if (!domain || !arg || !(new->name = canonicalise_opt(domain)))
ret_err(option == LOPT_DYNHOST ?
_("bad dynamic host") : _("bad interface name"));
}
new->intr = opt_string_alloc(comma);
break;
}
@@ -5076,7 +5018,9 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_refresh = SOA_REFRESH;
daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY;
daemon->max_port = MAX_PORT;
daemon->min_port = MIN_PORT;
#ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
add_txt("authors.bind", "Simon Kelley", 0);
@@ -5268,13 +5212,6 @@ void read_opts(int argc, char **argv, char *compile_opts)
strcat(buff, daemon->authserver);
daemon->hostmaster = opt_string_alloc(buff);
}
if (!daemon->dhcp_pxe_vendors)
{
daemon->dhcp_pxe_vendors = opt_malloc(sizeof(struct dhcp_pxe_vendor));
daemon->dhcp_pxe_vendors->data = opt_string_alloc(DHCP_PXE_DEF_VENDOR);
daemon->dhcp_pxe_vendors->next = NULL;
}
/* only one of these need be specified: the other defaults to the host-name */
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+97 -37
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -333,6 +333,55 @@ unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *h
return ansp;
}
/* CRC the question section. This is used to safely detect query
retransmission and to detect answers to questions we didn't ask, which
might be poisoning attacks. Note that we decode the name rather
than CRC the raw bytes, since replies might be compressed differently.
We ignore case in the names for the same reason. Return all-ones
if there is not question section. */
#ifndef HAVE_DNSSEC
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
{
int q;
unsigned int crc = 0xffffffff;
unsigned char *p1, *p = (unsigned char *)(header+1);
for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!extract_name(header, plen, &p, name, 1, 4))
return crc; /* bad packet */
for (p1 = (unsigned char *)name; *p1; p1++)
{
int i = 8;
char c = *p1;
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';
crc ^= c << 24;
while (i--)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}
/* CRC the class and type as well */
for (p1 = p; p1 < p+4; p1++)
{
int i = 8;
crc ^= *p1 << 24;
while (i--)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}
p += 4;
if (!CHECK_LEN(header, p, plen, 0))
return crc; /* bad packet */
}
return crc;
}
#endif
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
{
unsigned char *ansp = skip_questions(header, plen);
@@ -1017,33 +1066,30 @@ int check_for_local_domain(char *name, time_t now)
return 0;
}
static int check_bad_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr, char *name, unsigned long *ttlp)
/* Is the packet a reply with the answer address equal to addr?
If so mung is into an NXDOMAIN reply and also put that information
in the cache. */
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *baddr, time_t now)
{
unsigned char *p;
int i, qtype, qclass, rdlen;
unsigned long ttl;
struct bogus_addr *baddrp;
struct in_addr addr;
/* skip over questions */
if (!(p = skip_questions(header, qlen)))
return 0; /* bad packet */
for (i = ntohs(header->ancount); i != 0; i--)
{
if (name && !extract_name(header, qlen, &p, name, 1, 10))
if (!extract_name(header, qlen, &p, name, 1, 10))
return 0; /* bad packet */
if (!name && !(p = skip_name(p, header, qlen, 10)))
return 0;
GETSHORT(qtype, p);
GETSHORT(qclass, p);
GETLONG(ttl, p);
GETSHORT(rdlen, p);
if (ttlp)
*ttlp = ttl;
if (qclass == C_IN && qtype == T_A)
{
@@ -1051,12 +1097,16 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
{
memcpy(&addr, p, INADDRSZ);
if ((addr.s_addr & baddrp->mask.s_addr) == baddrp->addr.s_addr)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
{
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
cache_start_insert();
cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
cache_end_insert();
return 1;
}
}
}
if (!ADD_RDLEN(header, p, qlen, rdlen))
@@ -1066,31 +1116,43 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
return 0;
}
/* Is the packet a reply with the answer address equal to addr?
If so mung is into an NXDOMAIN reply and also put that information
in the cache. */
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, time_t now)
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
{
unsigned long ttl;
unsigned char *p;
int i, qtype, qclass, rdlen;
struct bogus_addr *baddrp;
if (check_bad_address(header, qlen, daemon->bogus_addr, name, &ttl))
/* skip over questions */
if (!(p = skip_questions(header, qlen)))
return 0; /* bad packet */
for (i = ntohs(header->ancount); i != 0; i--)
{
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
cache_start_insert();
cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
cache_end_insert();
return 1;
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
p += 4; /* TTL */
GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A)
{
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
return 1;
}
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0;
}
return 0;
}
int check_for_ignored_address(struct dns_header *header, size_t qlen)
{
return check_bad_address(header, qlen, daemon->ignore_addr, NULL, NULL);
}
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
@@ -1346,8 +1408,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
}
else
return 0; /* give up if any cached CNAME in chain can't be used for DNSSEC reasons. */
strcpy(name, cname_target);
}
+27 -72
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, const char *string, int null_term);
int opt, char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int offset, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
@@ -54,19 +54,17 @@ static void do_options(struct dhcp_context *context,
int vendor_class_len,
time_t now,
unsigned int lease_time,
unsigned short fuzz,
const char *pxevendor);
unsigned short fuzz);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
static int prune_vendor_opts(struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int loopback,
@@ -78,7 +76,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
struct dhcp_mac *mac;
struct dhcp_netid_list *id_list;
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
const char *pxevendor = NULL;
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
unsigned char *end = (unsigned char *)(mess + 1);
unsigned char *real_end = (unsigned char *)(mess + 1);
@@ -650,7 +647,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL);
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
}
}
@@ -838,8 +835,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clid = NULL;
/* Check if client is PXE client. */
if (daemon->enable_pxe &&
is_pxe_client(mess, sz, &pxevendor))
if (daemon->enable_pxe &&
(opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
{
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
{
@@ -901,7 +899,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
pxe_misc(mess, end, uuid, pxevendor);
pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid);
opt71.val = save71;
@@ -981,7 +979,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
pxe_misc(mess, end, uuid, pxevendor);
pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid);
if ((pxe && !workaround) || !redirect4011)
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
@@ -1152,7 +1150,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1501,7 +1499,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (rapid_commit)
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
}
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1568,7 +1566,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1950,7 +1948,7 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
}
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
const char *string, int null_term)
char *string, int null_term)
{
unsigned char *p;
size_t len = strlen(string);
@@ -2028,32 +2026,15 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
dopt->flags &= ~DHOPT_VENDOR_MATCH;
if (opt && (dopt->flags & DHOPT_VENDOR))
{
const struct dhcp_pxe_vendor *pv;
struct dhcp_pxe_vendor dummy_vendor = {
.data = (char *)dopt->u.vendor_class,
.next = NULL,
};
if (dopt->flags & DHOPT_VENDOR_PXE)
pv = daemon->dhcp_pxe_vendors;
else
pv = &dummy_vendor;
for (; pv; pv = pv->next)
{
int i, len = 0, matched = 0;
if (pv->data)
len = strlen(pv->data);
for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
{
matched = 1;
break;
}
if (matched)
{
dopt->flags |= DHOPT_VENDOR_MATCH;
break;
}
}
int i, len = 0;
if (dopt->u.vendor_class)
len = strlen((char *)dopt->u.vendor_class);
for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
{
dopt->flags |= DHOPT_VENDOR_MATCH;
break;
}
}
}
}
@@ -2106,13 +2087,11 @@ static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
return ret;
}
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
{
unsigned char *p;
if (!pxevendor)
pxevendor="PXEClient";
option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
memcpy(p, uuid, 17);
}
@@ -2329,29 +2308,6 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid)
return boot;
}
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
{
const unsigned char *opt = NULL;
ssize_t conf_len = 0;
const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
if (!opt)
return 0;
for (; conf; conf = conf->next)
{
conf_len = strlen(conf->data);
if (option_len(opt) < conf_len)
continue;
if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
{
if (pxe_vendor)
*pxe_vendor = conf->data;
return 1;
}
}
return 0;
}
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *end,
@@ -2366,8 +2322,7 @@ static void do_options(struct dhcp_context *context,
int vendor_class_len,
time_t now,
unsigned int lease_time,
unsigned short fuzz,
const char *pxevendor)
unsigned short fuzz)
{
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
struct dhcp_boot *boot;
@@ -2741,7 +2696,7 @@ static void do_options(struct dhcp_context *context,
if (context && pxe_arch != -1)
{
pxe_misc(mess, end, uuid, pxevendor);
pxe_misc(mess, end, uuid);
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -98,7 +98,7 @@ int add_to_ipset(const char *setname, const union all_addr *ipaddr,
io.pfrio_size = 1;
if (ioctl(dev, DIOCRADDTABLES, &io))
{
my_syslog(LOG_WARNING, _("IPset: error: %s"), pfr_strerror(errno));
my_syslog(LOG_WARNING, _("IPset: error:%s"), pfr_strerror(errno));
return -1;
}
+9 -28
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static void free_transfer(struct tftp_transfer *transfer);
static ssize_t tftp_err(int err, char *packet, char *message, char *file);
static ssize_t tftp_err_oops(char *packet, const char *file);
static ssize_t tftp_err_oops(char *packet, char *file);
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end);
static void sanitise(char *buf);
@@ -39,7 +39,6 @@ static void sanitise(char *buf);
#define ERR_PERM 2
#define ERR_FULL 3
#define ERR_ILL 4
#define ERR_TID 5
void tftp_request(struct listener *listen, time_t now)
{
@@ -95,7 +94,7 @@ void tftp_request(struct listener *listen, time_t now)
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
return;
/* Can always get recvd interface for IPv6 */
if (!check_dest)
{
@@ -584,27 +583,11 @@ void check_tftp_listeners(time_t now)
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
if (poll_check(transfer->sockfd, POLLIN))
{
union mysockaddr peer;
socklen_t addr_len = sizeof(union mysockaddr);
ssize_t len;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if ((len = recvfrom(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0, &peer.sa, &addr_len)) > 0)
{
if (sockaddr_isequal(&peer, &transfer->peer))
handle_tftp(now, transfer, len);
else
{
/* Wrong source address. See rfc1350 para 4. */
prettyprint_addr(&peer, daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
}
}
handle_tftp(now, transfer, recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0));
}
for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
{
tmp = transfer->next;
@@ -619,7 +602,7 @@ void check_tftp_listeners(time_t now)
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if ((len = get_block(daemon->packet, transfer)) == -1)
{
len = tftp_err_oops(daemon->packet, transfer->file->filename);
@@ -753,8 +736,7 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
char *errstr = strerror(errno);
memset(packet, 0, daemon->packet_buff_sz);
if (file)
sanitise(file);
sanitise(file);
mess->op = htons(OP_ERR);
mess->err = htons(err);
@@ -766,11 +748,10 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
return ret;
}
static ssize_t tftp_err_oops(char *packet, const char *file)
static ssize_t tftp_err_oops(char *packet, char *file)
{
/* May have >1 refs to file, so potentially mangle a copy of the name */
if (file != daemon->namebuff)
strcpy(daemon->namebuff, file);
strcpy(daemon->namebuff, file);
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -316,7 +316,7 @@ void *whine_malloc(size_t size)
return ret;
}
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
{
if (s1->sa.sa_family == s2->sa.sa_family)
{