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 5718 additions and 6977 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 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 Fix a remote buffer overflow problem in the DNSSEC code. Any
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this, dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
referenced by CVE-2020-25681, CVE-2020-25682, CVE-2020-25683 referenced by CERT VU#434904.
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.
version 2.82 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 # 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 # 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_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` 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_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` 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` 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` 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_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` 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' \ nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
HAVE_CRYPTOHASH $(PKG_CONFIG) --cflags nettle \ nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
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`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp` 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` sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"' 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 \ 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 \ 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 \ 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 \ poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
metrics.o hash_questions.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h metrics.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 \ radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \ dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c poll.c rrfilter.c edns0.c arp.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 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 # 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. # 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 # 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 # first. This favours, eg v2.63 over 2.63rc6.
# that, eg v2.64 comes before v2.63, but v2.63 comes before v2.63rc1
# and v2.63rc1 comes before v2.63test1
# Change directory to the toplevel source directory. # Change directory to the toplevel source directory.
if test -z "$1" || ! test -d "$1" || ! cd "$1"; then 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]` vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then 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 else
cat $1/VERSION cat $1/VERSION
fi fi
+19 -22
View File
@@ -1,37 +1,35 @@
#!/bin/sh #!/bin/sh
search=$1
shift
pkg=$1
shift
op=$1
shift
in=`cat` in=`cat`
search() if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
{ echo $in | grep $search >/dev/null 2>&1; then
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
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP # Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
if [ $op = "--copy" ]; then if [ $op = "--copy" ]; then
if [ -z "$pkg" ]; then if [ -z "$pkg" ]; then
pkg="$lib" pkg="$*"
elif search "$pkg"; then elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
echo $in | grep $pkg >/dev/null 2>&1; then
pkg="" pkg=""
else else
pkg="$lib" pkg="$*"
fi fi
elif search "${search}_STATIC"; then elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
pkg=`$pkg --static $op $lib` echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
pkg=`$pkg --static $op $*`
else else
pkg=`$pkg $op $lib` pkg=`$pkg $op $*`
fi 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 if [ $op = "--libs" ] || [ $op = "--copy" ]; then
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic" echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
else else
@@ -42,4 +40,3 @@ if search "$search"; then
fi fi
fi fi
done
-39
View File
@@ -1,42 +1,3 @@
dnsmasq (2.85-1) unstable; urgency=low
* New upstream.
* Includes fix to CVE-2021-3448.
* Fix manpage typos. (closes: #986150)
-- 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 dnsmasq (2.82-1) unstable; urgency=low
* New upstream. * 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/ It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
-3
View File
@@ -1,9 +1,6 @@
#!/bin/sh #!/bin/sh
set -e 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 ---------------------- # Code copied from dh_systemd_enable ----------------------
# This will only remove masks created by d-s-h on package removal. # This will only remove masks created by d-s-h on package removal.
deb-systemd-helper unmask dnsmasq.service >/dev/null || true deb-systemd-helper unmask dnsmasq.service >/dev/null || true
-3
View File
@@ -1,9 +1,6 @@
#!/bin/sh #!/bin/sh
set -e 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 if [ purge = "$1" ]; then
update-rc.d dnsmasq remove >/dev/null update-rc.d dnsmasq remove >/dev/null
fi 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/usr/lib/tmpfiles.d \
-d debian/trees/daemon/etc/insserv.conf.d -d debian/trees/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN 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 \ if ! dpkg-vendor --derives-from Ubuntu; then \
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \ rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
dh_runit -pdnsmasq -Pdebian/trees/daemon; \ dh_runit -pdnsmasq -Pdebian/trees/daemon; \
+11 -51
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 dnsmasq will close and reopen the file when it receives SIGUSR2. This
allows the log file to be rotated without stopping dnsmasq. allows the log file to be rotated without stopping dnsmasq.
.TP .TP
.B --log-debug
Enable extra logging intended for debugging rather than information.
.TP
.B --log-async[=<lines>] .B --log-async[=<lines>]
Enable asynchronous logging and optionally set the limit on the Enable asynchronous logging and optionally set the limit on the
number of lines number of lines
@@ -184,7 +181,7 @@ OS: this was the default behaviour in versions prior to 2.43.
.B --min-port=<port> .B --min-port=<port>
Do not use ports less than that given as source for outbound DNS Do not use ports less than that given as source for outbound DNS
queries. Dnsmasq picks random ports as source for outbound queries: queries. Dnsmasq picks random ports as source for outbound queries:
when this option is given, the ports used will always be larger when this option is given, the ports used will always to larger
than that specified. Useful for systems behind firewalls. If not specified, than that specified. Useful for systems behind firewalls. If not specified,
defaults to 1024. defaults to 1024.
.TP .TP
@@ -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. under Linux. On other platforms it falls-back to \fB--bind-interfaces\fP mode.
.TP .TP
.B \-y, --localise-queries .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 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 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 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 .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 maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
.TP .TP
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix] .B \-B, --bogus-nxdomain=<ipaddr>
Transform replies which contain the IP specified address or subnet into "No such Transform replies which contain the IP address given into "No such
domain" replies. This is intended to counteract a devious move made by domain" replies. This is intended to counteract a devious move made by
Verisign in September 2003 when they started returning the address of Verisign in September 2003 when they started returning the address of
an advertising web page in response to queries for unregistered names, 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 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 the IP address being returned by Verisign is 64.94.110.11
.TP .TP
.B --ignore-address=<ipaddr>[/prefix] .B --ignore-address=<ipaddr>
Ignore replies to A-record queries which include the specified address or subnet. Ignore replies to A-record queries which include the specified address.
No error is generated, dnsmasq simply continues to listen for another reply. 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 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. 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 or domain parts, to upstream nameservers. If the name is not known
from /etc/hosts or DHCP then a "not found" answer is returned. from /etc/hosts or DHCP then a "not found" answer is returned.
.TP .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 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 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 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 part of the source address. Forcing queries to an interface is not
implemented on all platforms supported by dnsmasq. implemented on all platforms supported by dnsmasq.
.TP .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 This is functionally the same as
.B --server, .B --server,
but provides some syntactic sugar to make specifying address-to-name queries easier. For example 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 or the value of \fB--local-ttl\fP. The value is a positive integer and gives
the time-to-live in seconds. the time-to-live in seconds.
.TP .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>] .B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings, 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 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 address information either. The default is zero for both IPv4 and
IPv6. Note that upstream nameservers may be configured to return IPv6. Note that upstream nameservers may be configured to return
different results based on this information, but the dnsmasq cache different results based on this information, but the dnsmasq cache
does not take account. Caching is therefore disabled for such replies, does not take account. If a dnsmasq instance is configured such that
unless the subnet address being added is constant. different results may be encountered, caching should be disabled.
For example, For example,
.B --add-subnet=24,96 .B --add-subnet=24,96
@@ -1054,19 +1045,6 @@ option, but aliases are possible by using CNAMEs. (See
.B --cname .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" The special keyword "ignore"
tells dnsmasq to never offer a DHCP lease to a machine. The machine tells dnsmasq to never offer a DHCP lease to a machine. The machine
can be specified by hardware address, client ID or hostname, for 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 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 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, 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 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 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, boot server and directs the PXE client to download the file by TFTP,
@@ -1503,22 +1481,6 @@ to allow netbooting. This mode is enabled using the
keyword in keyword in
.B --dhcp-range. .B --dhcp-range.
.TP .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> .B \-X, --dhcp-lease-max=<number>
Limits dnsmasq to the specified maximum number of DHCP leases. The Limits dnsmasq to the specified maximum number of DHCP leases. The
default is 1000. This limit is to prevent DoS attacks from hosts which default is 1000. This limit is to prevent DoS attacks from hosts which
@@ -2389,8 +2351,6 @@ IPv4 and IPv6 addresses from /etc/hosts (and
.B --host-record .B --host-record
and and
.B --interface-name .B --interface-name
and
.B ---dynamic-host
provided the address falls into one of the subnets specified in the provided the address falls into one of the subnets specified in the
.B --auth-zone. .B --auth-zone.
.PP .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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */ #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 */ #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 define this to include the facility to act as an authoritative DNS
server for one or more zones. server for one or more zones.
HAVE_CRYPTOHASH
include just hash function from crypto library, but no DNSSEC.
HAVE_DNSSEC HAVE_DNSSEC
include DNSSEC validator. include DNSSEC validator.
@@ -189,7 +187,6 @@ RESOLVFILE
/* #define HAVE_IDN */ /* #define HAVE_IDN */
/* #define HAVE_LIBIDN2 */ /* #define HAVE_LIBIDN2 */
/* #define HAVE_CONNTRACK */ /* #define HAVE_CONNTRACK */
/* #define HAVE_CRYPTOHASH */
/* #define HAVE_DNSSEC */ /* #define HAVE_DNSSEC */
@@ -423,10 +420,6 @@ static char *compile_opts =
"no-" "no-"
#endif #endif
"auth " "auth "
#if !defined(HAVE_CRYPTOHASH) && !defined(HAVE_DNSSEC)
"no-"
#endif
"cryptohash "
#ifndef HAVE_DNSSEC #ifndef HAVE_DNSSEC
"no-" "no-"
#endif #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 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 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 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 it under the terms of the GNU General Public License as published by
@@ -18,25 +18,13 @@
#ifdef HAVE_DNSSEC #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/rsa.h>
#include <nettle/ecdsa.h> #include <nettle/ecdsa.h>
#include <nettle/ecc-curve.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> #include <nettle/eddsa.h>
#endif #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
#if MIN_VERSION(3, 6)
# include <nettle/gostdsa.h> # include <nettle/gostdsa.h>
#endif #endif
#endif
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
#include <nettle/nettle-meta.h> #include <nettle/nettle-meta.h>
#include <nettle/bignum.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 /* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
incompatibilities if sizeof(nettle_hashes) changes between library incompatibilities if sizeof(nettle_hashes) changes between library
versions. */ versions. It also #defines nettle_hashes, so use that to tell
#if MIN_VERSION(3, 4) if we have the new facilities. */
#ifdef nettle_hashes
return nettle_lookup_hash(name); return nettle_lookup_hash(name);
#else #else
{ {
@@ -178,10 +168,6 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
return 1; 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, 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) 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 struct ecc_point *key_256 = NULL, *key_384 = NULL;
static mpz_t x, y; static mpz_t x, y;
static struct dsa_signature *sig_struct; 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_256r1() (&nettle_secp_256r1)
#define nettle_get_secp_384r1() (&nettle_secp_384r1) #define nettle_get_secp_384r1() (&nettle_secp_384r1)
#endif #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); 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, static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo) 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 #endif
#if MIN_VERSION(3, 1)
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len, static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo) 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, ((struct null_hash_digest *)digest)->buff,
sig); sig);
#if MIN_VERSION(3, 6) #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
case 16: case 16:
if (key_len != ED448_KEY_SIZE || if (key_len != ED448_KEY_SIZE ||
sig_len != ED448_SIGNATURE_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; return 0;
} }
#endif
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len, 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) 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: case 5: case 7: case 8: case 10:
return dnsmasq_rsa_verify; return dnsmasq_rsa_verify;
#if MIN_VERSION(3, 6) #if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
case 12: case 12:
return dnsmasq_gostdsa_verify; return dnsmasq_gostdsa_verify;
#endif #endif
case 13: case 14: case 13: case 14:
return dnsmasq_ecdsa_verify; return dnsmasq_ecdsa_verify;
#if MIN_VERSION(3, 1)
case 15: case 16: case 15: case 16:
return dnsmasq_eddsa_verify; return dnsmasq_eddsa_verify;
#endif
} }
return NULL; 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 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 it under the terms of the GNU General Public License as published by
+7 -5
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 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 it under the terms of the GNU General Public License as published by
@@ -281,15 +281,14 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
if (!context) /* called via find_config() from lease_update_from_configs() */ if (!context) /* called via find_config() from lease_update_from_configs() */
return 1; return 1;
if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
return 1;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (context->flags & CONTEXT_V6) if (context->flags & CONTEXT_V6)
{ {
struct addrlist *addr_list; struct addrlist *addr_list;
if (config->flags & CONFIG_ADDR6) if (!(config->flags & CONFIG_ADDR6))
return 1;
for (; context; context = context->current) for (; context; context = context->current)
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
{ {
@@ -303,6 +302,9 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
else else
#endif #endif
{ {
if (!(config->flags & CONFIG_ADDR))
return 1;
for (; context; context = context->current) for (; context; context = context->current)
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask)) if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
return 1; 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 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 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 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 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 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 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 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 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 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 it under the terms of the GNU General Public License as published by
+9 -33
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 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 it under the terms of the GNU General Public License as published by
@@ -237,13 +237,6 @@ int main (int argc, char **argv)
die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF); die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
#endif #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) if (daemon->max_port < daemon->min_port)
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF); die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
@@ -397,16 +390,8 @@ int main (int argc, char **argv)
if (daemon->port != 0) if (daemon->port != 0)
{ {
cache_init(); cache_init();
blockdata_init();
hash_questions_init();
/* Scale random socket pool by ftabsize, but blockdata_init();
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));
} }
#ifdef HAVE_INOTIFY #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 a single file will be sent to may clients (the file only needs
one fd). */ one fd). */
max_fd -= 30 + daemon->numrrand; /* use other than TFTP */ max_fd -= 30; /* use other than TFTP */
if (max_fd < 0) if (max_fd < 0)
max_fd = 5; max_fd = 5;
@@ -1687,7 +1672,6 @@ static int set_dns_listeners(time_t now)
{ {
struct serverfd *serverfdp; struct serverfd *serverfdp;
struct listener *listener; struct listener *listener;
struct randfd_list *rfl;
int wait = 0, i; int wait = 0, i;
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
@@ -1708,14 +1692,11 @@ static int set_dns_listeners(time_t now)
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
poll_listen(serverfdp->fd, POLLIN); poll_listen(serverfdp->fd, POLLIN);
for (i = 0; i < daemon->numrrand; i++) if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0) if (daemon->randomsocks[i].refcount != 0)
poll_listen(daemon->randomsocks[i].fd, POLLIN); 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);
for (listener = daemon->listeners; listener; listener = listener->next) for (listener = daemon->listeners; listener; listener = listener->next)
{ {
/* only listen for queries if we have resources */ /* only listen for queries if we have resources */
@@ -1752,23 +1733,18 @@ static void check_dns_listeners(time_t now)
{ {
struct serverfd *serverfdp; struct serverfd *serverfdp;
struct listener *listener; struct listener *listener;
struct randfd_list *rfl;
int i; int i;
int pipefd[2]; int pipefd[2];
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (poll_check(serverfdp->fd, POLLIN)) 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->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0 && if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN)) poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, now); reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, 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);
/* Races. The child process can die before we read all of the data from the /* 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 pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
+36 -69
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 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 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/>. 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 /* We do defines that influence behavior of stdio.h, so complain
if included too early. */ if included too early. */
@@ -95,7 +95,11 @@ typedef unsigned long long u64;
#if defined(HAVE_SOLARIS_NETWORK) #if defined(HAVE_SOLARIS_NETWORK)
# include <sys/sockio.h> # include <sys/sockio.h>
#endif #endif
#include <poll.h> #if defined(HAVE_POLL_H)
# include <poll.h>
#else
# include <sys/poll.h>
#endif
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/un.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> #include <priv.h>
#endif #endif
/* Backwards compat with 2.83 */ #ifdef HAVE_DNSSEC
#if defined(HAVE_NETTLEHASH)
# define HAVE_CRYPTOHASH
#endif
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
# include <nettle/nettle-meta.h> # include <nettle/nettle-meta.h>
#endif #endif
@@ -269,8 +269,7 @@ struct event_desc {
#define OPT_IGNORE_CLID 59 #define OPT_IGNORE_CLID 59
#define OPT_SINGLE_PORT 60 #define OPT_SINGLE_PORT 60
#define OPT_LEASE_RENEW 61 #define OPT_LEASE_RENEW 61
#define OPT_LOG_DEBUG 62 #define OPT_LAST 62
#define OPT_LAST 63
#define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) #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_val(x) ((1u) << ((x) % OPTION_BITS))
#define option_bool(x) (option_var(x) & option_val(x)) #define option_bool(x) (option_var(x) & option_val(x))
/* extra flags for my_syslog, we use facilities since they are known /* 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. 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. */
#define MS_TFTP LOG_USER #define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON #define MS_DHCP LOG_DAEMON
#define MS_SCRIPT LOG_MAIL #define MS_SCRIPT LOG_MAIL
#define MS_DEBUG LOG_NEWS
/* Note that this is used widely as a container for IPv4/IPv6 addresses, /* 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 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 bogus_addr {
struct in_addr addr, mask; struct in_addr addr;
struct bogus_addr *next; struct bogus_addr *next;
}; };
@@ -426,17 +423,10 @@ struct host_record {
struct host_record *next; struct host_record *next;
}; };
#define IN4 1
#define IN6 2
#define INP4 4
#define INP6 8
struct interface_name { struct interface_name {
char *name; /* domain name */ char *name; /* domain name */
char *intr; /* interface name */ char *intr; /* interface name */
int flags; int family; /* AF_INET, AF_INET6 or zero for both */
struct in_addr proto4;
struct in6_addr proto6;
struct addrlist *addr; struct addrlist *addr;
struct interface_name *next; struct interface_name *next;
}; };
@@ -549,20 +539,13 @@ struct serverfd {
}; };
struct randfd { struct randfd {
struct server *serv;
int fd; 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 { struct server {
union mysockaddr addr, source_addr; union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1]; char interface[IF_NAMESIZE+1];
unsigned int ifindex; /* corresponding to interface, above */
struct serverfd *sfd; struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */ char *domain; /* set if this server only handles a domain. */
int flags, tcpfd, edns_pktsz; int flags, tcpfd, edns_pktsz;
@@ -671,24 +654,22 @@ struct hostsfile {
#define FREC_ADDED_PHEADER 128 #define FREC_ADDED_PHEADER 128
#define FREC_TEST_PKTSZ 256 #define FREC_TEST_PKTSZ 256
#define FREC_HAS_EXTRADATA 512 #define FREC_HAS_EXTRADATA 512
#define FREC_HAS_PHEADER 1024
#define FREC_NO_CACHE 2048
#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 {
struct frec_src {
union mysockaddr source; union mysockaddr source;
union all_addr dest; union all_addr dest;
unsigned int iface, log_id;
int fd;
unsigned short orig_id;
struct frec_src *next;
} frec_src;
struct server *sentto; /* NULL means free */ struct server *sentto; /* NULL means free */
struct randfd_list *rfds; struct randfd *rfd4;
unsigned short new_id; struct randfd *rfd6;
int forwardall, flags; unsigned int iface;
unsigned short orig_id, new_id;
int log_id, fd, forwardall, flags;
time_t time; time_t time;
unsigned char *hash[HASH_SIZE]; unsigned char *hash[HASH_SIZE];
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
@@ -848,7 +829,6 @@ struct dhcp_opt {
#define DHOPT_RFC3925 2048 #define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096 #define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192 #define DHOPT_ADDR6 8192
#define DHOPT_VENDOR_PXE 16384
struct dhcp_boot { struct dhcp_boot {
char *file, *sname, *tftp_sname; char *file, *sname, *tftp_sname;
@@ -872,8 +852,6 @@ struct pxe_service {
struct pxe_service *next; struct pxe_service *next;
}; };
#define DHCP_PXE_DEF_VENDOR "PXEClient"
#define MATCH_VENDOR 1 #define MATCH_VENDOR 1
#define MATCH_USER 2 #define MATCH_USER 2
#define MATCH_CIRCUIT 3 #define MATCH_CIRCUIT 3
@@ -889,11 +867,6 @@ struct dhcp_vendor {
struct dhcp_vendor *next; struct dhcp_vendor *next;
}; };
struct dhcp_pxe_vendor {
char *data;
struct dhcp_pxe_vendor *next;
};
struct dhcp_mac { struct dhcp_mac {
unsigned int mask; unsigned int mask;
int hwaddr_len, hwaddr_type; int hwaddr_len, hwaddr_type;
@@ -1067,7 +1040,6 @@ extern struct daemon {
struct dhcp_config *dhcp_conf; struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6; struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_match_name *dhcp_name_match; struct dhcp_match_name *dhcp_name_match;
struct dhcp_pxe_vendor *dhcp_pxe_vendors;
struct dhcp_vendor *dhcp_vendors; struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs; struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config; struct dhcp_boot *boot_config;
@@ -1116,8 +1088,6 @@ extern struct daemon {
int back_to_the_future; int back_to_the_future;
#endif #endif
struct frec *frec_list; struct frec *frec_list;
struct frec_src *free_frec_src;
int frec_src_count;
struct serverfd *sfds; struct serverfd *sfds;
struct irec *interfaces; struct irec *interfaces;
struct listener *listeners; struct listener *listeners;
@@ -1126,13 +1096,11 @@ extern struct daemon {
int forwardcount; int forwardcount;
struct server *srv_save; /* Used for resend on DoD */ struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */ size_t packet_len; /* " " */
int fd_save; /* " " */ struct randfd *rfd_save; /* " " */
pid_t tcp_pids[MAX_PROCS]; pid_t tcp_pids[MAX_PROCS];
int tcp_pipes[MAX_PROCS]; int tcp_pipes[MAX_PROCS];
int pipe_to_parent; int pipe_to_parent;
int numrrand; struct randfd randomsocks[RANDOM_SOCKS];
struct randfd *randomsocks;
struct randfd_list *rfl_spare, *rfl_poll;
int v6pktinfo; int v6pktinfo;
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */ 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 */ 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, struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader); 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, int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
time_t now); struct bogus_addr *baddr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen); 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); 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, size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen); unsigned char *pheader, size_t hlen);
int add_resource_record(struct dns_header *header, char *limit, int *truncp, 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 check_unsigned, int *neganswer, int *nons, int *nsec_ttl);
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen); int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
size_t filter_rrsigs(struct dns_header *header, size_t plen); 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); 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 */ /* crypto.c */
const struct nettle_hash *hash_find(char *name); const struct nettle_hash *hash_find(char *name);
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp); 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 safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size); void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr); 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_isequal(const char *a, const char *b);
int hostname_issubdomain(char *a, char *b); int hostname_issubdomain(char *a, char *b);
time_t dnsmasq_time(void); 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); int option_read_dynfile(char *file, int flags);
/* forward.c */ /* 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); void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now, unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns); 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, union mysockaddr *to, union all_addr *source,
unsigned int iface); unsigned int iface);
void resend_query(void); void resend_query(void);
int allocate_rfd(struct randfd_list **fdlp, struct server *serv); struct randfd *allocate_rfd(int family);
void free_rfds(struct randfd_list **fdlp); void free_rfd(struct randfd *rfd);
/* network.c */ /* network.c */
int indextoname(int fd, int index, char *name); 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 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); void pre_allocate_sfds(void);
int reload_servers(char *fname); int reload_servers(char *fname);
void mark_servers(int flag); 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); 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_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, 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); int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
/* arp.c */ /* arp.c */
+33 -45
View File
@@ -335,33 +335,6 @@ static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
return rrsetidx; /* short packet */ return rrsetidx; /* short packet */
state2.end = state2.ip + rdlen2; 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)
{
int rdmin = rdlen1 > rdlen2 ? rdlen2 : rdlen1;
int cmp = memcmp(state1.ip, state2.ip, rdmin);
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))
{
/* 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) while (1)
{ {
int ok1, ok2; int ok1, ok2;
@@ -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); hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
from_wire(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) for (i = 0; i < rrsetidx; ++i)
{ {
@@ -645,26 +618,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
hash->update(ctx, 4, p); /* class and type */ hash->update(ctx, 4, p); /* class and type */
hash->update(ctx, 4, (unsigned char *)&nsigttl); hash->update(ctx, 4, (unsigned char *)&nsigttl);
p += 8; /* skip type, class, ttl */ p += 8; /* skip class, type, ttl */
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen)) if (!CHECK_LEN(header, p, plen, rdlen))
return STAT_BOGUS; return STAT_BOGUS;
/* 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(rdlen);
hash->update(ctx, 2, (unsigned char *)&len);
hash->update(ctx, rdlen, p);
}
else
{
/* canonicalise rdata and calculate length of same, use /* canonicalise rdata and calculate length of same, use
name buffer as workspace for get_rdata. */ name buffer as workspace for get_rdata. */
state.ip = p; state.ip = p;
@@ -704,7 +662,6 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
if (j != 0) if (j != 0)
hash->update(ctx, j, rrbuf); hash->update(ctx, j, rrbuf);
} }
}
hash->digest(ctx, hash->digest_size, digest); 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; 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 */ #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 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 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 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 it under the terms of the GNU General Public License as published by
+13 -32
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 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 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]); out[3] = char64(in[2]);
} }
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
union mysockaddr *l3, time_t now, int *cacheablep)
{ {
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */ int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
unsigned char mac[DHCP_CHADDR_MAX]; 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) if ((maclen = find_mac(l3, mac, 1, now)) == 6)
{ {
replace = 1; replace = 1;
*cacheablep = 0;
if (option_bool(OPT_MAC_HEX)) if (option_bool(OPT_MAC_HEX))
print_mac(encode, mac, maclen); print_mac(encode, mac, maclen);
@@ -290,17 +288,13 @@ 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, static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
union mysockaddr *l3, time_t now, int *cacheablep)
{ {
int maclen; int maclen;
unsigned char mac[DHCP_CHADDR_MAX]; unsigned char mac[DHCP_CHADDR_MAX];
if ((maclen = find_mac(l3, mac, 1, now)) != 0) 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; return plen;
} }
@@ -319,14 +313,13 @@ static void *get_addrp(union mysockaddr *addr, const short family)
return &addr->in.sin_addr; 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 */ /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len; int len;
void *addrp = NULL; void *addrp = NULL;
int sa_family = source->sa.sa_family; int sa_family = source->sa.sa_family;
int cacheable = 0;
opt->source_netmask = 0; opt->source_netmask = 0;
opt->scope_netmask = 0; opt->scope_netmask = 0;
@@ -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; sa_family = daemon->add_subnet6->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family); addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
cacheable = 1;
} }
else else
addrp = &source->in6.sin6_addr; 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; sa_family = daemon->add_subnet4->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family); addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
cacheable = 1; /* Address is constant */
} }
else else
addrp = &source->in.sin_addr; 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); opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
len = 0;
if (addrp && opt->source_netmask != 0) if (addrp && opt->source_netmask != 0)
{ {
len = ((opt->source_netmask - 1) >> 3) + 1; 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) if (opt->source_netmask & 7)
opt->addr[len-1] &= 0xff << (8 - (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; 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 */ /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len; int len;
struct subnet_opt opt; 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); return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
} }
@@ -398,7 +383,7 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
unsigned char *p; unsigned char *p;
int code, i, rdlen; 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))) if (!(p = skip_name(pseudoheader, header, plen, 10)))
return 1; return 1;
@@ -427,20 +412,16 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
return 1; 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, 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; *check_subnet = 0;
*cacheable = 1;
if (option_bool(OPT_ADD_MAC)) 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)) 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) if (daemon->dns_client_id)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
@@ -448,7 +429,7 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
if (option_bool(OPT_CLIENT_SUBNET)) 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; *check_subnet = 1;
} }
+294 -469
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 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 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 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 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 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 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 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 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) if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
next_event = LEASE_RETRY + now; 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), daemon->lease_file, strerror(err),
(unsigned int)difftime(next_event, now)); (unsigned int)difftime(next_event, now));
} }
+2 -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 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 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. /* 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 OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
DNS, DHCP and TFTP services. 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, ...) void my_syslog(int priority, const char *format, ...)
{ {
va_list ap; va_list ap;
@@ -290,12 +290,6 @@ void my_syslog(int priority, const char *format, ...)
func = "-dhcp"; func = "-dhcp";
else if ((LOG_FACMASK & priority) == MS_SCRIPT) else if ((LOG_FACMASK & priority) == MS_SCRIPT)
func = "-script"; func = "-script";
else if ((LOG_FACMASK & priority) == MS_DEBUG)
{
if (!option_bool(OPT_LOG_DEBUG))
return;
func = "-debug";
}
#ifdef LOG_PRI #ifdef LOG_PRI
priority = LOG_PRI(priority); priority = LOG_PRI(priority);
+11 -5
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 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 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() void loop_send_probes()
{ {
struct server *serv; struct server *serv;
struct randfd_list *rfds = NULL;
if (!option_bool(OPT_LOOP_DETECT)) if (!option_bool(OPT_LOOP_DETECT))
return; return;
@@ -35,15 +34,22 @@ void loop_send_probes()
{ {
ssize_t len = loop_make_probe(serv->uid); ssize_t len = loop_make_probe(serv->uid);
int fd; int fd;
struct randfd *rfd = NULL;
if ((fd = allocate_rfd(&rfds, serv)) == -1) if (serv->sfd)
fd = serv->sfd->fd;
else
{
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
continue; continue;
fd = rfd->fd;
}
while (retry_send(sendto(fd, daemon->packet, len, 0, while (retry_send(sendto(fd, daemon->packet, len, 0,
&serv->addr.sa, sa_len(&serv->addr)))); &serv->addr.sa, sa_len(&serv->addr))));
}
free_rfds(&rfds); free_rfd(rfd);
}
} }
static ssize_t loop_make_probe(u32 uid) static ssize_t loop_make_probe(u32 uid)
+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 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 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 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 it under the terms of the GNU General Public License as published by
+29 -46
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 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 it under the terms of the GNU General Public License as published by
@@ -43,24 +43,17 @@
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) # define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#endif #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),
};
static struct iovec iov; static struct iovec iov;
static u32 netlink_pid; static u32 netlink_pid;
static unsigned nl_async(struct nlmsghdr *h, unsigned state); static void nl_async(struct nlmsghdr *h);
static void nl_multicast_state(unsigned state);
char *netlink_init(void) char *netlink_init(void)
{ {
struct sockaddr_nl addr; struct sockaddr_nl addr;
socklen_t slen = sizeof(addr); socklen_t slen = sizeof(addr);
int opt = 1;
addr.nl_family = AF_NETLINK; addr.nl_family = AF_NETLINK;
addr.nl_pad = 0; addr.nl_pad = 0;
@@ -99,10 +92,14 @@ char *netlink_init(void)
iov.iov_len = 100; iov.iov_len = 100;
iov.iov_base = safe_malloc(iov.iov_len); 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; return NULL;
} }
static ssize_t netlink_recv(int flags) static ssize_t netlink_recv(void)
{ {
struct msghdr msg; struct msghdr msg;
struct sockaddr_nl nladdr; struct sockaddr_nl nladdr;
@@ -118,8 +115,7 @@ static ssize_t netlink_recv(int flags)
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
msg.msg_flags = 0; msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, flags | MSG_PEEK | MSG_TRUNC)) == -1 && while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
errno == EINTR);
/* make buffer big enough */ /* make buffer big enough */
if (rc != -1 && (msg.msg_flags & MSG_TRUNC)) if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
@@ -136,7 +132,7 @@ static ssize_t netlink_recv(int flags)
/* read it for real */ /* read it for real */
msg.msg_flags = 0; 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 */ /* Make sure this is from the kernel */
if (rc == -1 || nladdr.nl_pid == 0) 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_UNSPEC finds ARP table entries.
family = AF_LOCAL finds MAC addresses. family = AF_LOCAL finds MAC addresses. */
returns 0 on failure, 1 on success, -1 when restart is required
*/
int iface_enumerate(int family, void *parm, int (*callback)()) int iface_enumerate(int family, void *parm, int (*callback)())
{ {
struct sockaddr_nl addr; struct sockaddr_nl addr;
@@ -165,7 +159,6 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ssize_t len; ssize_t len;
static unsigned int seq = 0; static unsigned int seq = 0;
int callback_ok = 1; int callback_ok = 1;
unsigned state = 0;
struct { struct {
struct nlmsghdr nlh; struct nlmsghdr nlh;
@@ -177,6 +170,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr.nl_family = AF_NETLINK; addr.nl_family = AF_NETLINK;
again:
if (family == AF_UNSPEC) if (family == AF_UNSPEC)
req.nlh.nlmsg_type = RTM_GETNEIGH; req.nlh.nlmsg_type = RTM_GETNEIGH;
else if (family == AF_LOCAL) else if (family == AF_LOCAL)
@@ -199,12 +193,12 @@ int iface_enumerate(int family, void *parm, int (*callback)())
while (1) while (1)
{ {
if ((len = netlink_recv(0)) == -1) if ((len = netlink_recv()) == -1)
{ {
if (errno == ENOBUFS) if (errno == ENOBUFS)
{ {
nl_multicast_state(state); sleep(1);
return -1; goto again;
} }
return 0; 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) if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{ {
/* May be multicast arriving async */ /* May be multicast arriving async */
state = nl_async(h, state); nl_async(h);
} }
else if (h->nlmsg_seq != seq) 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; ssize_t len;
struct nlmsghdr *h; struct nlmsghdr *h;
int flags;
do {
/* don't risk blocking reading netlink messages here. */ /* don't risk blocking reading netlink messages here. */
while ((len = netlink_recv(MSG_DONTWAIT)) != -1) 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)) for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
state = nl_async(h, state); nl_async(h);
} while (errno == ENOBUFS);
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
} }
void netlink_multicast(void) static void nl_async(struct nlmsghdr *h)
{
unsigned state = 0;
nl_multicast_state(state);
}
static unsigned nl_async(struct nlmsghdr *h, unsigned state)
{ {
if (h->nlmsg_type == NLMSG_ERROR) if (h->nlmsg_type == NLMSG_ERROR)
{ {
@@ -376,8 +368,7 @@ static unsigned nl_async(struct nlmsghdr *h, unsigned state)
if (err->error != 0) if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error))); my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
} }
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE && else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
(state & STATE_NEWROUTE)==0)
{ {
/* We arrange to receive netlink multicast messages whenever the network route is added. /* 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. 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 && if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
(rtm->rtm_table == RT_TABLE_MAIN || (rtm->rtm_table == RT_TABLE_MAIN ||
rtm->rtm_table == RT_TABLE_LOCAL)) rtm->rtm_table == RT_TABLE_LOCAL))
{
queue_event(EVENT_NEWROUTE); queue_event(EVENT_NEWROUTE);
state |= STATE_NEWROUTE;
} }
} else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
(state & STATE_NEWADDR)==0)
{
queue_event(EVENT_NEWADDR); queue_event(EVENT_NEWADDR);
state |= STATE_NEWADDR;
}
return state;
} }
#endif #endif
+99 -178
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 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 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) union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)
{ {
struct irec *iface; struct irec *iface;
int loopback; int mtu = 0, loopback;
struct ifreq ifr; struct ifreq ifr;
int tftp_ok = !!option_bool(OPT_TFTP); int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1; int dhcp_ok = 1;
@@ -253,6 +253,9 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
if (loopback) if (loopback)
dhcp_ok = 0; dhcp_ok = 0;
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
if (!label) if (!label)
label = ifr.ifr_name; label = ifr.ifr_name;
else else
@@ -348,31 +351,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
/* Update addresses from interface_names. These are a set independent /* Update addresses from interface_names. These are a set independent
of the set we're listening on. */ of the set we're listening on. */
for (int_name = daemon->int_names; int_name; int_name = int_name->next) 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)))
{
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) if (param->spare)
{ {
@@ -382,75 +362,25 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
else else
al = whine_malloc(sizeof(struct addrlist)); 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;
}
}
}
if (al) if (al)
{ {
al->next = int_name->addr; al->next = int_name->addr;
int_name->addr = al; 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 */ /* add to list */
if ((iface = whine_malloc(sizeof(struct irec)))) 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->addr = *addr;
iface->netmask = netmask; iface->netmask = netmask;
iface->tftp_ok = tftp_ok; iface->tftp_ok = tftp_ok;
@@ -667,7 +592,7 @@ static int release_listener(struct listener *l)
int port; int port;
port = prettyprint_addr(&l->iface->addr, daemon->addrbuff); 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); l->iface->name, l->iface->index, daemon->addrbuff, port);
/* In case it ever returns */ /* In case it ever returns */
l->iface->done = 0; l->iface->done = 0;
@@ -696,7 +621,6 @@ int enumerate_interfaces(int reset)
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
struct auth_zone *zone; struct auth_zone *zone;
#endif #endif
struct server *serv;
/* Do this max once per select cycle - also inhibits netlink socket use /* Do this max once per select cycle - also inhibits netlink socket use
in TCP child processes. */ in TCP child processes. */
@@ -715,25 +639,6 @@ int enumerate_interfaces(int reset)
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0; 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 */ /* Mark interfaces for garbage collection */
for (iface = daemon->interfaces; iface; iface = iface->next) for (iface = daemon->interfaces; iface; iface = iface->next)
iface->found = 0; iface->found = 0;
@@ -785,14 +690,9 @@ again:
param.spare = spare; param.spare = spare;
ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6); ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
if (ret < 0)
goto again; if (ret)
else if (ret)
{
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4); ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
if (ret < 0)
goto again;
}
errsave = errno; errsave = errno;
close(param.fd); close(param.fd);
@@ -1145,7 +1045,7 @@ void create_bound_listeners(int dienow)
if (!dienow) if (!dienow)
{ {
int port = prettyprint_addr(&iface->addr, daemon->addrbuff); 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); iface->name, iface->index, daemon->addrbuff, port);
} }
} }
@@ -1172,7 +1072,7 @@ void create_bound_listeners(int dienow)
if (!dienow) if (!dienow)
{ {
int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff); 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,59 +1206,75 @@ void join_multicast(int dienow)
} }
#endif #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) int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
{ {
union mysockaddr addr_copy = *addr; 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. */ /* cannot set source _port_ for TCP connections. */
if (is_tcp) 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));
}
while (1)
{
/* elide bind() call if it's to port 0, address 0 */
if (addr_copy.sa.sa_family == AF_INET) if (addr_copy.sa.sa_family == AF_INET)
{ addr_copy.in.sin_port = 0;
if (port == 0 && addr_copy.in.sin_addr.s_addr == 0)
break;
addr_copy.in.sin_port = port;
}
else else
{ addr_copy.in6.sin6_port = 0;
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) if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
break;
if (errno != EADDRINUSE && errno != EACCES)
return 0; return 0;
if (--tries == 0)
return 0;
port = htons(daemon->min_port + (rand16() % ports_avail));
}
if (!is_tcp && ifindex > 0) if (!is_tcp && ifindex > 0)
{ {
#if defined(IP_UNICAST_IF) #if defined(IP_UNICAST_IF)
@@ -1387,33 +1303,38 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
return 1; 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; struct serverfd *sfd;
unsigned int ifindex = 0;
int errsave; int errsave;
int opt = 1; int opt = 1;
/* when using random ports, servers which would otherwise use /* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL, this is the INADDR_ANY/port0 socket have sfd set to NULL */
anything without an explictly set source port. */ if (!daemon->osport && intname[0] == 0)
if (!daemon->osport)
{ {
errno = 0; errno = 0;
if (addr->sa.sa_family == AF_INET && if (addr->sa.sa_family == AF_INET &&
addr->in.sin_addr.s_addr == INADDR_ANY &&
addr->in.sin_port == htons(0)) addr->in.sin_port == htons(0))
return NULL; return NULL;
if (addr->sa.sa_family == AF_INET6 && if (addr->sa.sa_family == AF_INET6 &&
memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
addr->in6.sin6_port == htons(0)) addr->in6.sin6_port == htons(0))
return NULL; 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 */ /* may have a suitable one already */
for (sfd = daemon->sfds; sfd; sfd = sfd->next ) for (sfd = daemon->sfds; sfd; sfd = sfd->next )
if (ifindex == sfd->ifindex && if (sockaddr_isequal(&sfd->source_addr, addr) &&
sockaddr_isequal(&sfd->source_addr, addr) && strcmp(intname, sfd->interface) == 0 &&
strcmp(intname, sfd->interface) == 0) ifindex == sfd->ifindex)
return sfd; return sfd;
/* need to make a new one. */ /* need to make a new one. */
@@ -1464,7 +1385,7 @@ void pre_allocate_sfds(void)
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in); addr.in.sin_len = sizeof(struct sockaddr_in);
#endif #endif
if ((sfd = allocate_sfd(&addr, "", 0))) if ((sfd = allocate_sfd(&addr, "")))
sfd->preallocated = 1; sfd->preallocated = 1;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
@@ -1474,13 +1395,13 @@ void pre_allocate_sfds(void)
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6); addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif #endif
if ((sfd = allocate_sfd(&addr, "", 0))) if ((sfd = allocate_sfd(&addr, "")))
sfd->preallocated = 1; sfd->preallocated = 1;
} }
for (srv = daemon->servers; srv; srv = srv->next) for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) && 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 && errno != 0 &&
option_bool(OPT_NOWILD)) option_bool(OPT_NOWILD))
{ {
@@ -1689,7 +1610,7 @@ void check_servers(void)
/* Do we need a socket set? */ /* Do we need a socket set? */
if (!serv->sfd && 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) errno != 0)
{ {
my_syslog(LOG_WARNING, my_syslog(LOG_WARNING,
+26 -89
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 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 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_IGNORE_CLID 358
#define LOPT_SINGLE_PORT 359 #define LOPT_SINGLE_PORT 359
#define LOPT_SCRIPT_TIME 360 #define LOPT_SCRIPT_TIME 360
#define LOPT_PXE_VENDOR 361
#define LOPT_DYNHOST 362
#define LOPT_LOG_DEBUG 363
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -273,7 +270,6 @@ static const struct myoption opts[] =
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT }, { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE }, { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR }, { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
{ "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
{ "interface-name", 1, 0, LOPT_INTNAME }, { "interface-name", 1, 0, LOPT_INTNAME },
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST }, { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS }, { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
@@ -343,8 +339,6 @@ static const struct myoption opts[] =
{ "dumpfile", 1, 0, LOPT_DUMPFILE }, { "dumpfile", 1, 0, LOPT_DUMPFILE },
{ "dumpmask", 1, 0, LOPT_DUMPMASK }, { "dumpmask", 1, 0, LOPT_DUMPMASK },
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID }, { "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 } { 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_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_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_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 }, { '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 }, { 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 }, { '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_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_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_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_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_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 }, { 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_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_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_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_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_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 }, { 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 (interface_opt)
{ {
#if defined(SO_BINDTODEVICE) #if defined(SO_BINDTODEVICE)
safe_strncpy(interface, source, IF_NAMESIZE); safe_strncpy(interface, interface_opt, IF_NAMESIZE);
source = interface_opt;
#else #else
return _("interface binding not supported"); return _("interface binding not supported");
#endif #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 */ case LOPT_IGNORE_ADDR: /* --ignore-address */
{ {
struct in_addr addr; struct in_addr addr;
int prefix = 32;
unhide_metas(arg); unhide_metas(arg);
if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
if (!arg ||
((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix)) ||
(inet_pton(AF_INET, arg, &addr) != 1))
ret_err(gen_err); /* error */
else
{ {
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr)); struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
if (option == 'B') if (option == 'B')
@@ -2508,9 +2492,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
baddr->next = daemon->ignore_addr; baddr->next = daemon->ignore_addr;
daemon->ignore_addr = baddr; daemon->ignore_addr = baddr;
} }
baddr->mask.s_addr = htonl(~((1 << (32 - prefix)) - 1)); baddr->addr = addr;
baddr->addr.s_addr = addr.s_addr & baddr->mask.s_addr;
} }
else
ret_err(gen_err); /* error */
break; break;
} }
@@ -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); new->val = opt_malloc(new->len);
memcpy(new->val + 1, arg, new->len - 1); memcpy(new->val + 1, arg, new->len - 1);
new->u.vendor_class = NULL; new->u.vendor_class = (unsigned char *)"PXEClient";
new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE; new->flags = DHOPT_VENDOR;
if (comma && atoi_check(comma, &timeout)) if (comma && atoi_check(comma, &timeout))
*(new->val) = timeout; *(new->val) = timeout;
@@ -3953,19 +3938,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
break; 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;
case LOPT_RELAY: /* --dhcp-relay */ case LOPT_RELAY: /* --dhcp-relay */
{ {
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay)); struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
@@ -4087,66 +4059,36 @@ err:
} }
case LOPT_INTNAME: /* --interface-name */ case LOPT_INTNAME: /* --interface-name */
case LOPT_DYNHOST: /* --dynamic-host */
{ {
struct interface_name *new, **up; struct interface_name *new, **up;
char *domain = arg; char *domain = NULL;
arg = split(arg); comma = split(arg);
if (!comma || !(domain = canonicalise_opt(arg)))
ret_err(_("bad interface name"));
new = opt_malloc(sizeof(struct interface_name)); new = opt_malloc(sizeof(struct interface_name));
memset(new, 0, sizeof(struct interface_name)); new->next = NULL;
new->flags = IN4 | IN6; new->addr = NULL;
/* Add to the end of the list, so that first name /* Add to the end of the list, so that first name
of an interface is used for PTR lookups. */ of an interface is used for PTR lookups. */
for (up = &daemon->int_names; *up; up = &((*up)->next)); for (up = &daemon->int_names; *up; up = &((*up)->next));
*up = new; *up = new;
new->name = domain;
while ((comma = split(arg))) new->family = 0;
arg = split_chr(comma, '/');
if (arg)
{ {
if (inet_pton(AF_INET, arg, &new->proto4)) if (strcmp(arg, "4") == 0)
new->flags |= INP4; new->family = AF_INET;
else if (inet_pton(AF_INET6, arg, &new->proto6)) else if (strcmp(arg, "6") == 0)
new->flags |= INP6; new->family = AF_INET6;
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;
else else
ret_err_free(gen_err, new); ret_err_free(gen_err, new);
} }
new->intr = opt_string_alloc(comma);
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"));
break; break;
} }
@@ -5076,6 +5018,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_refresh = SOA_REFRESH; daemon->soa_refresh = SOA_REFRESH;
daemon->soa_retry = SOA_RETRY; daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY; daemon->soa_expiry = SOA_EXPIRY;
daemon->max_port = MAX_PORT;
daemon->min_port = MIN_PORT;
#ifndef NO_ID #ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 ); add_txt("version.bind", "dnsmasq-" VERSION, 0 );
@@ -5269,13 +5213,6 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->hostmaster = opt_string_alloc(buff); 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 */ /* only one of these need be specified: the other defaults to the host-name */
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget) 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 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 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 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 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 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 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 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 it under the terms of the GNU General Public License as published by
+89 -29
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 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 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; 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) size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
{ {
unsigned char *ansp = skip_questions(header, plen); unsigned char *ansp = skip_questions(header, plen);
@@ -1017,13 +1066,16 @@ int check_for_local_domain(char *name, time_t now)
return 0; 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; unsigned char *p;
int i, qtype, qclass, rdlen; int i, qtype, qclass, rdlen;
unsigned long ttl; unsigned long ttl;
struct bogus_addr *baddrp; struct bogus_addr *baddrp;
struct in_addr addr;
/* skip over questions */ /* skip over questions */
if (!(p = skip_questions(header, qlen))) if (!(p = skip_questions(header, qlen)))
@@ -1031,30 +1083,28 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
for (i = ntohs(header->ancount); i != 0; i--) 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 */ return 0; /* bad packet */
if (!name && !(p = skip_name(p, header, qlen, 10)))
return 0;
GETSHORT(qtype, p); GETSHORT(qtype, p);
GETSHORT(qclass, p); GETSHORT(qclass, p);
GETLONG(ttl, p); GETLONG(ttl, p);
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
if (ttlp)
*ttlp = ttl;
if (qclass == C_IN && qtype == T_A) if (qclass == C_IN && qtype == T_A)
{ {
if (!CHECK_LEN(header, p, qlen, INADDRSZ)) if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0; return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next) for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
{ {
memcpy(&addr, p, INADDRSZ); /* 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();
if ((addr.s_addr & baddrp->mask.s_addr) == baddrp->addr.s_addr)
return 1; return 1;
} }
} }
@@ -1066,31 +1116,43 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
return 0; return 0;
} }
/* Is the packet a reply with the answer address equal to addr? int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
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)
{ {
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 if (!(p = skip_name(p, header, qlen, 10)))
to get the ttl from in the normal processing */ return 0; /* bad packet */
cache_start_insert();
cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
cache_end_insert();
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; return 1;
} }
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0;
}
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, 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, ...) 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); strcpy(name, cname_target);
} }
+21 -66
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 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 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 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(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, 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 struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int offset, int size); static unsigned int option_uint(unsigned char *opt, int offset, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac, 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, int vendor_class_len,
time_t now, time_t now,
unsigned int lease_time, unsigned int lease_time,
unsigned short fuzz, unsigned short fuzz);
const char *pxevendor);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 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 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 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); 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); 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 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 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 dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int loopback, 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_mac *mac;
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1; 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; struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
unsigned char *end = (unsigned char *)(mess + 1); unsigned char *end = (unsigned char *)(mess + 1);
unsigned char *real_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); clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 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);
} }
} }
@@ -839,7 +836,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* Check if client is PXE client. */ /* Check if client is PXE client. */
if (daemon->enable_pxe && if (daemon->enable_pxe &&
is_pxe_client(mess, sz, &pxevendor)) (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))) 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_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr)); 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); prune_vendor_opts(tagif_netid);
opt71.val = save71; 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, option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK); mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr)); 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); prune_vendor_opts(tagif_netid);
if ((pxe && !workaround) || !redirect4011) 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); 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); option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */ /* 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), 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); 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) if (rapid_commit)
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0); option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 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); 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), 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 */ *is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end); 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, 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; unsigned char *p;
size_t len = strlen(string); size_t len = strlen(string);
@@ -2028,34 +2026,17 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
dopt->flags &= ~DHOPT_VENDOR_MATCH; dopt->flags &= ~DHOPT_VENDOR_MATCH;
if (opt && (dopt->flags & DHOPT_VENDOR)) if (opt && (dopt->flags & DHOPT_VENDOR))
{ {
const struct dhcp_pxe_vendor *pv; int i, len = 0;
struct dhcp_pxe_vendor dummy_vendor = { if (dopt->u.vendor_class)
.data = (char *)dopt->u.vendor_class, len = strlen((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++) for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0) if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
{
matched = 1;
break;
}
if (matched)
{ {
dopt->flags |= DHOPT_VENDOR_MATCH; dopt->flags |= DHOPT_VENDOR_MATCH;
break; break;
} }
} }
} }
}
} }
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
@@ -2106,13 +2087,11 @@ static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
return ret; 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; unsigned char *p;
if (!pxevendor) option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
pxevendor="PXEClient";
option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17))) if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
memcpy(p, uuid, 17); memcpy(p, uuid, 17);
} }
@@ -2329,29 +2308,6 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid)
return boot; 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, static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess, struct dhcp_packet *mess,
unsigned char *end, unsigned char *end,
@@ -2366,8 +2322,7 @@ static void do_options(struct dhcp_context *context,
int vendor_class_len, int vendor_class_len,
time_t now, time_t now,
unsigned int lease_time, unsigned int lease_time,
unsigned short fuzz, unsigned short fuzz)
const char *pxevendor)
{ {
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts; struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
struct dhcp_boot *boot; struct dhcp_boot *boot;
@@ -2741,7 +2696,7 @@ static void do_options(struct dhcp_context *context,
if (context && pxe_arch != -1) 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)) if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
config_opts = pxe_opts(pxe_arch, tagif, context->local, now); 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 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 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 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 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 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 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; io.pfrio_size = 1;
if (ioctl(dev, DIOCRADDTABLES, &io)) 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; return -1;
} }
+4 -23
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 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 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 struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static void free_transfer(struct tftp_transfer *transfer); 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(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 ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end); static char *next(char **p, char *end);
static void sanitise(char *buf); static void sanitise(char *buf);
@@ -39,7 +39,6 @@ static void sanitise(char *buf);
#define ERR_PERM 2 #define ERR_PERM 2
#define ERR_FULL 3 #define ERR_FULL 3
#define ERR_ILL 4 #define ERR_ILL 4
#define ERR_TID 5
void tftp_request(struct listener *listen, time_t now) void tftp_request(struct listener *listen, time_t now)
{ {
@@ -584,25 +583,9 @@ void check_tftp_listeners(time_t now)
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next) for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
if (poll_check(transfer->sockfd, POLLIN)) if (poll_check(transfer->sockfd, POLLIN))
{ {
union mysockaddr peer;
socklen_t addr_len = sizeof(union mysockaddr);
ssize_t len;
/* we overwrote the buffer... */ /* we overwrote the buffer... */
daemon->srv_save = NULL; daemon->srv_save = NULL;
handle_tftp(now, transfer, recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0));
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));
}
}
} }
for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp) for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
@@ -753,7 +736,6 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
char *errstr = strerror(errno); char *errstr = strerror(errno);
memset(packet, 0, daemon->packet_buff_sz); memset(packet, 0, daemon->packet_buff_sz);
if (file)
sanitise(file); sanitise(file);
mess->op = htons(OP_ERR); mess->op = htons(OP_ERR);
@@ -766,10 +748,9 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
return ret; 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 */ /* 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); 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 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 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 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 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; 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) if (s1->sa.sa_family == s2->sa.sa_family)
{ {