mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
327bbc92bc | ||
|
|
cc0b4489c7 | ||
|
|
9212ad284f | ||
|
|
503f68dbc4 | ||
|
|
e01e09c712 | ||
|
|
6a6e06fbb0 | ||
|
|
2024f97297 | ||
|
|
25e63f1e56 | ||
|
|
15b60ddf93 | ||
|
|
824461192c | ||
|
|
1eb6cedb03 | ||
|
|
059aded070 | ||
|
|
2d765867c5 | ||
|
|
257ac0c5f7 | ||
|
|
4e96a4be68 | ||
|
|
a2a7e040b1 | ||
|
|
4ded96209e | ||
|
|
f60fea1fb0 | ||
|
|
4d85e409cd | ||
|
|
2bd02d2f59 | ||
|
|
7e194a0a7d | ||
|
|
9beb4d9ea2 | ||
|
|
ab5ebe9507 | ||
|
|
837e8f4eb5 | ||
|
|
e2cb655958 | ||
|
|
8270648da1 | ||
|
|
619000a3c5 | ||
|
|
1c1b925052 | ||
|
|
49bdf1ead9 | ||
|
|
60a3ae19c5 | ||
|
|
951a22165c | ||
|
|
51cdd1a227 | ||
|
|
66adee85be | ||
|
|
4890bcdea2 | ||
|
|
8baf583a3f | ||
|
|
913fa15fb1 | ||
|
|
00fe2f49e0 | ||
|
|
ec2067df75 | ||
|
|
7ddb99d251 | ||
|
|
ba26d3485b | ||
|
|
081a1c4014 | ||
|
|
532246fc9e | ||
|
|
8caf3d7c6c | ||
|
|
d162bee356 | ||
|
|
b43585c34b | ||
|
|
3f60ecd6f0 | ||
|
|
0506a5ed4e | ||
|
|
e7ee1aa093 | ||
|
|
63ed917ad9 | ||
|
|
63e21bdea3 | ||
|
|
1627d577af | ||
|
|
b837c4528d | ||
|
|
46bdfe691a | ||
|
|
dded78b233 | ||
|
|
b594e8defa | ||
|
|
70c50efd0d | ||
|
|
ea3c60ac07 | ||
|
|
fc19399a1f | ||
|
|
980b14f174 | ||
|
|
1df73fe831 | ||
|
|
c125c1dfee | ||
|
|
e39c484ebd | ||
|
|
977a5a2df1 | ||
|
|
02df0007c8 |
No files matched your search
@@ -1,12 +1,67 @@
|
||||
version 2.83
|
||||
Use the values of --min-port and --max-port in outgoing
|
||||
TCP connections to upstream DNS servers.
|
||||
|
||||
Fix a remote buffer overflow problem in the DNSSEC code. Any
|
||||
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
|
||||
referenced by CVE-2020-25681, CVE-2020-25682, CVE-2020-25683
|
||||
CVE-2020-25687.
|
||||
|
||||
Be sure to only accept UDP DNS query replies at the address
|
||||
from which the query was originated. This keeps as much entropy
|
||||
in the {query-ID, random-port} tuple as possible, to help defeat
|
||||
cache poisoning attacks. Refer: CVE-2020-25684.
|
||||
|
||||
Use the SHA-256 hash function to verify that DNS answers
|
||||
received are for the questions originally asked. This replaces
|
||||
the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
the very insecure CRC32 (otherwise). Refer: CVE-2020-25685.
|
||||
|
||||
Handle multiple identical near simultaneous DNS queries better.
|
||||
Previously, such queries would all be forwarded
|
||||
independently. This is, in theory, inefficent 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
|
||||
succesful 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
|
||||
Improve behaviour in the face of network interfaces which come
|
||||
and go and change index. Thanks to Petr Mensik for the patch.
|
||||
|
||||
Convert hard startup failure on NETLINK_NO_ENOBUFS under qemu-user
|
||||
to a warning.
|
||||
|
||||
Allow IPv6 addresses ofthe form [::ffff:1.2.3.4] in --dhcp-option.
|
||||
|
||||
Fix crash under heavy TCP connection load introduced in 2.81.
|
||||
Thanks to Frank for good work chasing this down.
|
||||
|
||||
Change default lease time for DHCPv6 to one day.
|
||||
|
||||
Alter calculation of preferred and valid times in router
|
||||
advertisements, so that these do not have a floor applied
|
||||
of the lease time in the dhcp-range if this is not explicitly
|
||||
specified and is merely the default.
|
||||
Thanks to Martin-Éric Racine for suggestions on this.
|
||||
|
||||
|
||||
version 2.81
|
||||
Impove cache behaviour for TCP connections. For ease of
|
||||
implementaion, dnsmasq has always forked a new process to handle
|
||||
Improve cache behaviour for TCP connections. For ease of
|
||||
implementation, dnsmasq has always forked a new process to handle
|
||||
each incoming TCP connection. A side-effect of this is that
|
||||
any DNS queries answered from TCP connections are not cached:
|
||||
when TCP connections were rare, this was not a problem.
|
||||
With the coming of DNSSEC, it's now the case that some
|
||||
With the coming of DNSSEC, it is now the case that some
|
||||
DNSSEC queries have answers which spill to TCP, and if,
|
||||
for instance, this applies to the keys for the root then
|
||||
for instance, this applies to the keys for the root, then
|
||||
those never get cached, and performance is very bad.
|
||||
This fix passes cache entries back from the TCP child process to
|
||||
the main server process, and fixes the problem.
|
||||
@@ -35,7 +90,7 @@ version 2.81
|
||||
configuration.
|
||||
|
||||
Add --shared-network config. This enables allocation of addresses
|
||||
the DHCP server in subnets where the server (or relay) doesn't
|
||||
by the DHCP server in subnets where the server (or relay) does not
|
||||
have an interface on the network in that subnet. Many thanks to
|
||||
kamp.de for sponsoring this feature.
|
||||
|
||||
@@ -66,7 +121,7 @@ version 2.81
|
||||
Evgenii Seliavka for the suggestion and initial patch.
|
||||
|
||||
In the router advert code, handle case where we have two
|
||||
different interfaces on the same IPv6 net, and we're doing
|
||||
different interfaces on the same IPv6 net, and we are doing
|
||||
RA/DHCP service on only one of them. Thanks to NIIBE Yutaka
|
||||
for spotting this case and making the initial patch.
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ top?=$(CURDIR)
|
||||
|
||||
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus`
|
||||
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
|
||||
@@ -62,8 +62,10 @@ ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CON
|
||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
|
||||
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
|
||||
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
|
||||
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
|
||||
HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
|
||||
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \
|
||||
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
@@ -77,7 +79,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||
metrics.o hash_questions.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
|
||||
crypto.c dump.c ubus.c
|
||||
crypto.c dump.c ubus.c metrics.c hash_questions.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
+22
-19
@@ -1,35 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
search=$1
|
||||
shift
|
||||
pkg=$1
|
||||
shift
|
||||
op=$1
|
||||
shift
|
||||
|
||||
in=`cat`
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $search >/dev/null 2>&1; then
|
||||
search()
|
||||
{
|
||||
grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $1 >/dev/null 2>&1
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
search=$1
|
||||
pkg=$2
|
||||
op=$3
|
||||
lib=$4
|
||||
shift 4
|
||||
if search "$search"; then
|
||||
|
||||
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
if [ -z "$pkg" ]; then
|
||||
pkg="$*"
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
pkg="$lib"
|
||||
elif search "$pkg"; then
|
||||
pkg=""
|
||||
else
|
||||
pkg="$*"
|
||||
pkg="$lib"
|
||||
fi
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
pkg=`$pkg --static $op $*`
|
||||
elif search "${search}_STATIC"; then
|
||||
pkg=`$pkg --static $op $lib`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
pkg=`$pkg $op $lib`
|
||||
fi
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
if search "${search}_STATIC"; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
@@ -40,3 +42,4 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
Vendored
+33
-1
@@ -1,3 +1,34 @@
|
||||
dnsmasq (2.83-1) unstable; urgency=high
|
||||
|
||||
* New upstream.
|
||||
* Includes fixes to CVE-2020-25681 - CVE-2020-25687 inclusive.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 15 Jan 2021 22:22:41 +0000
|
||||
|
||||
dnsmasq (2.82-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 22:22:41 +0000
|
||||
|
||||
dnsmasq (2.81-4) unstable; urgency=low
|
||||
|
||||
* Remove runit support when building for Ubuntu. (closes: #960401)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 21:52:44 +0000
|
||||
|
||||
dnsmasq (2.81-3) unstable; urgency=low
|
||||
|
||||
* Fixes to control file for bug 958100
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 19 Apr 2020 21:44:12 +0000
|
||||
|
||||
dnsmasq (2.81-2) unstable; urgency=low
|
||||
|
||||
* Fix FTBFS on kFreeBSD. (closes: #958100)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 18 Apr 2020 18:34:15 +0000
|
||||
|
||||
dnsmasq (2.81-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
@@ -12,8 +43,9 @@ dnsmasq (2.81-1) unstable; urgency=low
|
||||
* Fix breakage of dig +trace. (closes: #942363)
|
||||
* Fix build faliure with newer Nettle libraries. (closes: #940985)
|
||||
* Support runscript init-system (closes: #929884)
|
||||
* Security fix for CVE-2019-14834 (closes: #948373)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 27 Jan 2020 22:31:15 +0000
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 8 Apr 2020 17:33:15 +0000
|
||||
|
||||
dnsmasq (2.80-1) unstable; urgency=low
|
||||
|
||||
|
||||
Vendored
+3
-2
@@ -3,8 +3,9 @@ Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10)
|
||||
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
|
||||
pkg-config
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
debian/dnsmasq.runscript name=dnsmasq,logscript,since=2.80-1+runit
|
||||
debian/dnsmasq.runscript name=dnsmasq,logscript,presubj
|
||||
Vendored
+17
-10
@@ -98,9 +98,10 @@ ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_DNSSEC
|
||||
endif
|
||||
|
||||
ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
ifeq ($(DEB_HOST_ARCH_OS),kfreebsd)
|
||||
# For strlcpy in FreeBSD
|
||||
LDFLAGS += -lbsd
|
||||
LIBS += $(shell ${PKG_CONFIG} --libs libbsd-overlay)
|
||||
CFLAGS += $(shell ${PKG_CONFIG} --cflags libbsd-overlay)
|
||||
endif
|
||||
|
||||
define build_tree
|
||||
@@ -169,16 +170,20 @@ binary-indep: checkroot
|
||||
-d debian/trees/daemon/etc/resolvconf/update.d \
|
||||
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/trees/daemon/usr/share/dnsmasq \
|
||||
-d debian/trees/daemon/usr/share/doc/dnsmasq \
|
||||
-d debian/trees/daemon/etc/default \
|
||||
-d debian/trees/daemon/lib/systemd/system \
|
||||
-d debian/trees/daemon/usr/lib/tmpfiles.d \
|
||||
-d debian/trees/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
|
||||
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper
|
||||
dh_runit -pdnsmasq -Pdebian/trees/daemon
|
||||
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst
|
||||
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm
|
||||
if ! dpkg-vendor --derives-from Ubuntu; then \
|
||||
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
|
||||
dh_runit -pdnsmasq -Pdebian/trees/daemon; \
|
||||
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst; \
|
||||
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm; \
|
||||
cd debian/trees/daemon && find etc/sv -type f -printf '/%p\n' >>DEBIAN/conffiles; \
|
||||
fi
|
||||
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
@@ -190,7 +195,9 @@ binary-indep: checkroot
|
||||
install -m 644 debian/systemd@.service debian/trees/daemon/lib/systemd/system/dnsmasq@.service
|
||||
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
|
||||
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
|
||||
install -m 644 debian/copyright debian/trees/daemon/usr/share/doc/dnsmasq/copyright
|
||||
install -m 644 debian/changelog debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
|
||||
gzip -9n debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
|
||||
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/dnsmasq.substvars -pdnsmasq -Pdebian/trees/daemon
|
||||
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
@@ -200,7 +207,7 @@ binary-indep: checkroot
|
||||
|
||||
binary-arch: checkroot
|
||||
$(call build_tree,debian/trees/base)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/base)
|
||||
else
|
||||
@@ -219,7 +226,7 @@ endif
|
||||
dpkg --build debian/trees/base ..
|
||||
|
||||
$(call build_tree,debian/trees/lua-base)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/lua-base)
|
||||
else
|
||||
@@ -249,7 +256,7 @@ ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 755 -d debian/trees/utils/usr/share/man/man1
|
||||
endif
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
|
||||
+59
-31
@@ -1,4 +1,4 @@
|
||||
.TH DNSMASQ 8
|
||||
.TH DNSMASQ 8 2020-04-05
|
||||
.SH NAME
|
||||
dnsmasq \- A lightweight DHCP and caching DNS server.
|
||||
.SH SYNOPSIS
|
||||
@@ -244,7 +244,7 @@ specified interface. The <domain> is the "glue record". It should
|
||||
resolve in the global DNS to an A and/or AAAA record which points to
|
||||
the address dnsmasq is listening on. When an interface is specified,
|
||||
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
|
||||
addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the glue record.
|
||||
addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the primary external nameserver.
|
||||
.TP
|
||||
.B --local-service
|
||||
Accept DNS queries only from hosts whose address is on a local subnet,
|
||||
@@ -366,10 +366,13 @@ been built with DBus support. If the service name is given, dnsmasq
|
||||
provides service at that name, rather than the default which is
|
||||
.B uk.org.thekelleys.dnsmasq
|
||||
.TP
|
||||
.B --enable-ubus
|
||||
.B --enable-ubus[=<service-name>]
|
||||
Enable dnsmasq UBus interface. It sends notifications via UBus on
|
||||
DHCPACK and DHCPRELEASE events. Furthermore it offers metrics.
|
||||
Requires that dnsmasq has been built with UBus support.
|
||||
Requires that dnsmasq has been built with UBus support. If the service
|
||||
name is given, dnsmasq provides service at that namespace, rather than
|
||||
the default which is
|
||||
.B dnsmasq
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
By default, dnsmasq will send queries to any of the upstream servers
|
||||
@@ -395,11 +398,13 @@ were previously disabled.
|
||||
.TP
|
||||
.B --stop-dns-rebind
|
||||
Reject (and log) addresses from upstream nameservers which are in the
|
||||
private IP ranges. This blocks an attack where a browser behind a
|
||||
firewall is used to probe machines on the local network.
|
||||
private ranges. This blocks an attack where a browser behind a
|
||||
firewall is used to probe machines on the local network. For IPv6, the
|
||||
private range covers the IPv4-mapped addresses in private space plus
|
||||
all link-local (LL) and site-local (ULA) addresses.
|
||||
.TP
|
||||
.B --rebind-localhost-ok
|
||||
Exempt 127.0.0.0/8 from rebinding checks. This address range is
|
||||
Exempt 127.0.0.0/8 and ::1 from rebinding checks. This address range is
|
||||
returned by realtime black hole servers, so blocking it may disable
|
||||
these services.
|
||||
.TP
|
||||
@@ -423,7 +428,7 @@ Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<source-ip>|<interface>[#<port>]]
|
||||
Specify IP address of upstream servers directly. Setting this flag does
|
||||
not suppress reading of /etc/resolv.conf, use \fB--no-resolv\fP to do that. If one or more
|
||||
optional domains are given, that server is used only for those domains
|
||||
@@ -687,8 +692,8 @@ still marks the request so that no upstream nameserver will add client
|
||||
address information either. The default is zero for both IPv4 and
|
||||
IPv6. Note that upstream nameservers may be configured to return
|
||||
different results based on this information, but the dnsmasq cache
|
||||
does not take account. If a dnsmasq instance is configured such that
|
||||
different results may be encountered, caching should be disabled.
|
||||
does not take account. Caching is therefore disabled for such replies,
|
||||
unless the subnet address being added is constant.
|
||||
|
||||
For example,
|
||||
.B --add-subnet=24,96
|
||||
@@ -856,7 +861,7 @@ in
|
||||
options. If the lease time is given, then leases
|
||||
will be given for that length of time. The lease time is in seconds,
|
||||
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
||||
the default lease time is one hour. The
|
||||
the default lease time is one hour for IPv4 and one day for IPv6. The
|
||||
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
||||
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||
lease or router advertisement to zero, which causes clients to use
|
||||
@@ -904,7 +909,7 @@ then the address can be simply ::
|
||||
The optional
|
||||
.B set:<tag>
|
||||
sets an alphanumeric label which marks this network so that
|
||||
dhcp options may be specified on a per-network basis.
|
||||
DHCP options may be specified on a per-network basis.
|
||||
When it is prefixed with 'tag:' instead, then its meaning changes from setting
|
||||
a tag to matching it. Only one tag may be set, but more than one tag
|
||||
may be matched.
|
||||
@@ -1012,7 +1017,7 @@ may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 address
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
IPv6 addresses may contain only the host-identifier part:
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
in which case they act as wildcards in constructed dhcp ranges, with
|
||||
in which case they act as wildcards in constructed DHCP ranges, with
|
||||
the appropriate network part inserted. For IPv6, an address may include a prefix length:
|
||||
.B --dhcp-host=laptop,[1234:50/126]
|
||||
which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability
|
||||
@@ -1349,7 +1354,7 @@ vendor-identifying vendor classes for the specified enterprise. Please
|
||||
see RFC 3925 for more details of these rare and interesting beasts.
|
||||
.TP
|
||||
.B --dhcp-name-match=set:<tag>,<name>[*]
|
||||
Set the tag if the given name is supplied by a dhcp client. There may be a single trailing wildcard *, which has the usual meaning. Combined with dhcp-ignore or dhcp-ignore-names this gives the ability to ignore certain clients by name, or disallow certain hostnames from being claimed by a client.
|
||||
Set the tag if the given name is supplied by a DHCP client. There may be a single trailing wildcard *, which has the usual meaning. Combined with dhcp-ignore or dhcp-ignore-names this gives the ability to ignore certain clients by name, or disallow certain hostnames from being claimed by a client.
|
||||
.TP
|
||||
.B --tag-if=set:<tag>[,set:<tag>[,tag:<tag>[,tag:<tag>]]]
|
||||
Perform boolean operations on tags. Any tag appearing as set:<tag> is set if
|
||||
@@ -1475,6 +1480,22 @@ to allow netbooting. This mode is enabled using the
|
||||
.B proxy
|
||||
keyword in
|
||||
.B --dhcp-range.
|
||||
.TP
|
||||
.B --dhcp-pxe-vendor=<vendor>[,...]
|
||||
According to UEFI and PXE specifications, DHCP packets between PXE clients and
|
||||
proxy PXE servers should have
|
||||
.I PXEClient
|
||||
in their vendor-class field. However, the firmware of computers from a few
|
||||
vendors is customized to carry a different identifier in that field. This option
|
||||
is used to consider such identifiers valid for identifying PXE clients. For
|
||||
instance
|
||||
|
||||
.B --dhcp-pxe-vendor=PXEClient,HW-Client
|
||||
|
||||
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
|
||||
.I HW-Client
|
||||
in as their identifier.
|
||||
>>>>>>> 907def3... pxe: support pxe clients with custom vendor-class
|
||||
.TP
|
||||
.B \-X, --dhcp-lease-max=<number>
|
||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||
@@ -1746,7 +1767,7 @@ option also forces the leasechange script to be called on changes
|
||||
to the client-id and lease length and expiry time.
|
||||
.TP
|
||||
.B --script-on-renewal
|
||||
Call the dhcp script when the lease expiry time changes, for instance when the
|
||||
Call the DHCP script when the lease expiry time changes, for instance when the
|
||||
lease is renewed.
|
||||
.TP
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
@@ -1762,25 +1783,34 @@ It is permissible to add more than one alias using more than one \fB--bridge-int
|
||||
\fB--bridge-interface=int1,alias1,alias2\fP is exactly equivalent to
|
||||
\fB--bridge-interface=int1,alias1 --bridge-interface=int1,alias2\fP
|
||||
.TP
|
||||
.B --shared-network=<interface>|<addr>,<addr>
|
||||
The DHCP server determines which dhcp ranges are useable for allocating and
|
||||
.B --shared-network=<interface>,<addr>
|
||||
.PD 0
|
||||
.TP
|
||||
.B --shared-network=<addr>,<addr>
|
||||
.PD 1v
|
||||
The DHCP server determines which DHCP ranges are useable for allocating an
|
||||
address to a DHCP client based on the network from which the DHCP request arrives,
|
||||
and the IP configuration of the server's interface on that network. The shared-network
|
||||
option extends the available subnets (and therefore dhcp ranges) beyond the
|
||||
subnets configured on the arrival interface. The first argument is either the
|
||||
name of an interface or an address which is configured on a local interface, and the
|
||||
option extends the available subnets (and therefore DHCP ranges) beyond the
|
||||
subnets configured on the arrival interface.
|
||||
|
||||
The first argument is either the
|
||||
name of an interface, or an address that is configured on a local interface, and the
|
||||
second argument is an address which defines another subnet on which addresses can be allocated.
|
||||
To be useful, there must be suitable dhcp-range which allows address allocation on this subnet
|
||||
and this dhcp-range MUST include the netmask. Use shared-network also needs extra
|
||||
consideration of routing. Dnsmasq doesn't have the usual information which it uses to
|
||||
|
||||
To be useful, there must be a suitable dhcp-range which allows address allocation on this subnet
|
||||
and this dhcp-range MUST include the netmask.
|
||||
|
||||
Using shared-network also needs extra
|
||||
consideration of routing. Dnsmasq does not have the usual information that it uses to
|
||||
determine the default route, so the default route option (or other routing) MUST be
|
||||
manually configured. The client must have a route to the server: if the two-address form
|
||||
of shared-network is used, this will be to the first specified address. If the interface,address
|
||||
configured manually. The client must have a route to the server: if the two-address form
|
||||
of shared-network is used, this needs to be to the first specified address. If the interface,address
|
||||
form is used, there must be a route to all of the addresses configured on the interface.
|
||||
|
||||
The two-address form of shared-network is also usable with a DHCP relay: the first address
|
||||
is the address of the relay and the second, as before, specifies an extra subnet which
|
||||
may be allocated.
|
||||
addresses may be allocated from.
|
||||
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
@@ -1790,7 +1820,7 @@ firstly it causes the DHCP server to return the domain to any hosts
|
||||
which request it, and secondly it sets the domain which it is legal
|
||||
for DHCP-configured hosts to claim. The intention is to constrain
|
||||
hostnames so that an untrusted host on the LAN cannot advertise
|
||||
its name via dhcp as e.g. "microsoft.com" and capture traffic not
|
||||
its name via DHCP as e.g. "microsoft.com" and capture traffic not
|
||||
meant for it. If no domain suffix is specified, then any DHCP
|
||||
hostname with a domain part (ie with a period) will be disallowed
|
||||
and logged. If suffix is specified, then hostnames with a domain
|
||||
@@ -1881,7 +1911,7 @@ The mtu: parameter may be an arbitrary interface name, in which case the MTU val
|
||||
for (eg) advertising the MTU of a WAN interface on the other interfaces of a router.
|
||||
.TP
|
||||
.B --dhcp-reply-delay=[tag:<tag>,]<integer>
|
||||
Delays sending DHCPOFFER and proxydhcp replies for at least the specified number of seconds.
|
||||
Delays sending DHCPOFFER and PROXYDHCP replies for at least the specified number of seconds.
|
||||
This can be used as workaround for bugs in PXE boot firmware that does not function properly when
|
||||
receiving an instant reply.
|
||||
This option takes into account the time already spent waiting (e.g. performing ping check) if any.
|
||||
@@ -2017,7 +2047,7 @@ and
|
||||
.I /etc/ethers
|
||||
and any file given by \fB--dhcp-hostsfile\fP, \fB--dhcp-hostsdir\fP, \fB--dhcp-optsfile\fP,
|
||||
\fB--dhcp-optsdir\fP, \fB--addn-hosts\fP or \fB--hostsdir\fP.
|
||||
The dhcp lease change script is called for all
|
||||
The DHCP lease change script is called for all
|
||||
existing DHCP leases. If
|
||||
.B
|
||||
--no-poll
|
||||
@@ -2195,7 +2225,6 @@ as is the tag "bootp", allowing some control over the options returned to
|
||||
different classes of hosts.
|
||||
|
||||
.SH AUTHORITATIVE CONFIGURATION
|
||||
.PP
|
||||
Configuring dnsmasq to act as an authoritative DNS server is
|
||||
complicated by the fact that it involves configuration of external DNS
|
||||
servers to provide delegation. We will walk through three scenarios of
|
||||
@@ -2365,7 +2394,6 @@ used, and must match the zone's domain.
|
||||
|
||||
|
||||
.SH EXIT CODES
|
||||
.PP
|
||||
0 - Dnsmasq successfully forked into the background, or terminated
|
||||
normally if backgrounding is not enabled.
|
||||
.PP
|
||||
|
||||
+781
-623
File diff suppressed because it is too large.
Load diff
+13
-9
@@ -628,16 +628,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
{
|
||||
struct name_list *secondary;
|
||||
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
|
||||
/* Only include the machine running dnsmasq if it's acting as an auth server */
|
||||
if (daemon->authinterface)
|
||||
{
|
||||
if (offset == 0)
|
||||
offset = newoffset;
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
|
||||
{
|
||||
if (offset == 0)
|
||||
offset = newoffset;
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!subnet)
|
||||
|
||||
+17
-4
@@ -472,16 +472,29 @@ void cache_start_insert(void)
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned int flags)
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & (F_DNSKEY | F_DS))
|
||||
{
|
||||
/* The DNSSEC validation process works by getting needed records into the
|
||||
cache, then retrying the validation until they are all in place.
|
||||
This can be messed up by very short TTLs, and _really_ messed up by
|
||||
zero TTLs, so we force the TTL to be at least long enough to do a validation.
|
||||
Ideally, we should use some kind of reference counting so that records are
|
||||
locked until the validation that asked for them is complete, but this
|
||||
is much easier, and just as effective. */
|
||||
if (ttl < DNSSEC_MIN_TTL)
|
||||
ttl = DNSSEC_MIN_TTL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don't mess with TTL for DNSSEC records. */
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
|
||||
ttl = daemon->min_cache_ttl;
|
||||
}
|
||||
}
|
||||
|
||||
return really_insert(name, addr, class, now, ttl, flags);
|
||||
}
|
||||
|
||||
+12
-1
@@ -40,9 +40,11 @@
|
||||
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
|
||||
#define SMALLDNAME 50 /* most domain names are smaller than this */
|
||||
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
|
||||
#define DNSSEC_MIN_TTL 60 /* DNSKEY and DS records in cache last at least this long */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define DEFLEASE 3600 /* default DHCPv4 lease time, one hour */
|
||||
#define DEFLEASE6 (3600*24) /* default lease time for DHCPv6. One day. */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
@@ -50,6 +52,7 @@
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
#define DNSMASQ_UBUS_NAME "dnsmasq" /* Default - may be overridden by config */
|
||||
#define AUTH_TTL 600 /* default TTL for auth DNS */
|
||||
#define SOA_REFRESH 1200 /* SOA refresh default */
|
||||
#define SOA_RETRY 180 /* SOA retry default */
|
||||
@@ -117,6 +120,9 @@ HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
HAVE_NETTLEHASH
|
||||
include just hash function from nettle, but no DNSSEC.
|
||||
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
@@ -184,6 +190,7 @@ RESOLVFILE
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_NETTLEHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
|
||||
@@ -417,6 +424,10 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"auth "
|
||||
#if !defined(HAVE_NETTLEHASH) && !defined(HAVE_DNSSEC)
|
||||
"no-"
|
||||
#endif
|
||||
"nettlehash "
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
|
||||
# include <nettle/gostdsa.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
@@ -167,6 +170,10 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
|
||||
+1
-1
@@ -237,7 +237,7 @@ static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_LOOP)
|
||||
{
|
||||
prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
|
||||
}
|
||||
|
||||
|
||||
+13
-4
@@ -38,7 +38,7 @@ void dhcp_common_init(void)
|
||||
|
||||
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
{
|
||||
ssize_t sz;
|
||||
ssize_t sz, new_sz;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -65,9 +65,18 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
}
|
||||
}
|
||||
|
||||
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
|
||||
/* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway.
|
||||
If that happens we get EAGAIN here because the socket is non-blocking.
|
||||
Use the result of the original testing recvmsg as long as the buffer
|
||||
was big enough. There's a small race here that may lose the odd packet,
|
||||
but it's UDP anyway. */
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
|
||||
if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
new_sz = sz;
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
|
||||
}
|
||||
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||
@@ -649,7 +658,7 @@ static const struct opttab_t opttab6[] = {
|
||||
{ "sntp-server", 31, OT_ADDR_LIST },
|
||||
{ "information-refresh-time", 32, OT_TIME },
|
||||
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
|
||||
{ "ntp-server", 56, 0 },
|
||||
{ "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
|
||||
{ "bootfile-url", 59, OT_NAME },
|
||||
{ "bootfile-param", 60, OT_CSTRING },
|
||||
{ NULL, 0, 0 }
|
||||
|
||||
@@ -59,8 +59,12 @@
|
||||
#define OPTION6_REMOTE_ID 37
|
||||
#define OPTION6_SUBSCRIBER_ID 38
|
||||
#define OPTION6_FQDN 39
|
||||
#define OPTION6_NTP_SERVER 56
|
||||
#define OPTION6_CLIENT_MAC 79
|
||||
|
||||
#define NTP_SUBOPTION_SRV_ADDR 1
|
||||
#define NTP_SUBOPTION_MC_ADDR 2
|
||||
#define NTP_SUBOPTION_SRV_FQDN 3
|
||||
|
||||
#define DHCP6SUCCESS 0
|
||||
#define DHCP6UNSPEC 1
|
||||
|
||||
+41
-31
@@ -58,6 +58,7 @@ int main (int argc, char **argv)
|
||||
char *bound_device = NULL;
|
||||
int did_bind = 0;
|
||||
struct server *serv;
|
||||
char *netlink_warn;
|
||||
#endif
|
||||
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
|
||||
struct dhcp_context *context;
|
||||
@@ -89,11 +90,15 @@ int main (int argc, char **argv)
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
|
||||
umask(022); /* known umask, create leases and pid files as 0644 */
|
||||
|
||||
|
||||
rand_init(); /* Must precede read_opts() */
|
||||
|
||||
read_opts(argc, argv, compile_opts);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
daemon->kernel_version = kernel_version();
|
||||
#endif
|
||||
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = PACKETSZ;
|
||||
|
||||
@@ -323,7 +328,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
netlink_init();
|
||||
netlink_warn = netlink_init();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
route_init();
|
||||
#endif
|
||||
@@ -942,6 +947,9 @@ int main (int argc, char **argv)
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
if (did_bind)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
|
||||
|
||||
if (netlink_warn)
|
||||
my_syslog(LOG_WARNING, netlink_warn);
|
||||
# endif
|
||||
|
||||
/* after dhcp_construct_contexts */
|
||||
@@ -1679,7 +1687,7 @@ static int set_dns_listeners(time_t now)
|
||||
|
||||
/* will we be able to get memory? */
|
||||
if (daemon->port != 0)
|
||||
get_new_frec(now, &wait, 0);
|
||||
get_new_frec(now, &wait, NULL);
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
poll_listen(serverfdp->fd, POLLIN);
|
||||
@@ -1816,7 +1824,8 @@ static void check_dns_listeners(time_t now)
|
||||
addr.addr4 = tcp_addr.in.sin_addr;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
if (iface->index == if_index &&
|
||||
iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
@@ -1855,30 +1864,30 @@ static void check_dns_listeners(time_t now)
|
||||
else
|
||||
{
|
||||
int i;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* The child process inherits the netlink socket,
|
||||
which it never uses, but when the parent (us)
|
||||
uses it in the future, the answer may go to the
|
||||
child, resulting in the parent blocking
|
||||
forever awaiting the result. To avoid this
|
||||
the child closes the netlink socket, but there's
|
||||
a nasty race, since the parent may use netlink
|
||||
before the child has done the close.
|
||||
|
||||
To avoid this, the parent blocks here until a
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
|
||||
unsigned char a;
|
||||
read_write(pipefd[0], &a, 1, 1);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
{
|
||||
char a;
|
||||
|
||||
daemon->tcp_pids[i] = p;
|
||||
daemon->tcp_pipes[i] = pipefd[0];
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* The child process inherits the netlink socket,
|
||||
which it never uses, but when the parent (us)
|
||||
uses it in the future, the answer may go to the
|
||||
child, resulting in the parent blocking
|
||||
forever awaiting the result. To avoid this
|
||||
the child closes the netlink socket, but there's
|
||||
a nasty race, since the parent may use netlink
|
||||
before the child has done the close.
|
||||
|
||||
To avoid this, the parent blocks here until a
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
retry_send(read(pipefd[0], &a, 1));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1910,15 +1919,16 @@ static void check_dns_listeners(time_t now)
|
||||
terminate the process. */
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
char a = 0;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re: netlink socket. */
|
||||
unsigned char a = 0;
|
||||
|
||||
close(daemon->netlinkfd);
|
||||
read_write(pipefd[1], &a, 1, 0);
|
||||
#endif
|
||||
alarm(CHILD_LIFETIME);
|
||||
close(pipefd[0]); /* close read end in child. */
|
||||
daemon->pipe_to_parent = pipefd[1];
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re netlink socket. */
|
||||
close(daemon->netlinkfd);
|
||||
retry_send(write(pipefd[1], &a, 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* start with no upstream connections. */
|
||||
@@ -1945,8 +1955,10 @@ static void check_dns_listeners(time_t now)
|
||||
shutdown(s->tcpfd, SHUT_RDWR);
|
||||
close(s->tcpfd);
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
close(daemon->pipe_to_parent);
|
||||
flush_log();
|
||||
_exit(0);
|
||||
}
|
||||
@@ -2106,6 +2118,4 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HAVE_DHCP */
|
||||
+43
-20
@@ -141,6 +141,7 @@ typedef unsigned long long u64;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
#include <linux/version.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/capability.h>
|
||||
/* There doesn't seem to be a universally-available
|
||||
@@ -156,7 +157,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
@@ -384,10 +385,12 @@ struct ds_config {
|
||||
#define ADDRLIST_REVONLY 4
|
||||
#define ADDRLIST_PREFIX 8
|
||||
#define ADDRLIST_WILDCARD 16
|
||||
#define ADDRLIST_DECLINED 32
|
||||
|
||||
struct addrlist {
|
||||
union all_addr addr;
|
||||
int flags, prefixlen;
|
||||
int flags, prefixlen;
|
||||
time_t decline_time;
|
||||
struct addrlist *next;
|
||||
};
|
||||
|
||||
@@ -569,7 +572,8 @@ struct irec {
|
||||
};
|
||||
|
||||
struct listener {
|
||||
int fd, tcpfd, tftpfd, family;
|
||||
int fd, tcpfd, tftpfd, used;
|
||||
union mysockaddr addr;
|
||||
struct irec *iface; /* only sometimes valid for non-wildcard */
|
||||
struct listener *next;
|
||||
};
|
||||
@@ -649,23 +653,25 @@ struct hostsfile {
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
#define FREC_HAS_PHEADER 1024
|
||||
#define FREC_NO_CACHE 2048
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
#else
|
||||
#define HASH_SIZE sizeof(int)
|
||||
#endif
|
||||
#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
struct frec_src {
|
||||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
unsigned int iface, log_id;
|
||||
unsigned short orig_id;
|
||||
struct frec_src *next;
|
||||
} frec_src;
|
||||
struct server *sentto; /* NULL means free */
|
||||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int log_id, fd, forwardall, flags;
|
||||
unsigned short new_id;
|
||||
int fd, forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -825,6 +831,7 @@ struct dhcp_opt {
|
||||
#define DHOPT_RFC3925 2048
|
||||
#define DHOPT_TAGOK 4096
|
||||
#define DHOPT_ADDR6 8192
|
||||
#define DHOPT_VENDOR_PXE 16384
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname, *tftp_sname;
|
||||
@@ -848,6 +855,8 @@ struct pxe_service {
|
||||
struct pxe_service *next;
|
||||
};
|
||||
|
||||
#define DHCP_PXE_DEF_VENDOR "PXEClient"
|
||||
|
||||
#define MATCH_VENDOR 1
|
||||
#define MATCH_USER 2
|
||||
#define MATCH_CIRCUIT 3
|
||||
@@ -863,6 +872,11 @@ struct dhcp_vendor {
|
||||
struct dhcp_vendor *next;
|
||||
};
|
||||
|
||||
struct dhcp_pxe_vendor {
|
||||
char *data;
|
||||
struct dhcp_pxe_vendor *next;
|
||||
};
|
||||
|
||||
struct dhcp_mac {
|
||||
unsigned int mask;
|
||||
int hwaddr_len, hwaddr_type;
|
||||
@@ -938,6 +952,7 @@ struct shared_network {
|
||||
#define CONTEXT_OLD (1u<<16)
|
||||
#define CONTEXT_V6 (1u<<17)
|
||||
#define CONTEXT_RA_OFF_LINK (1u<<18)
|
||||
#define CONTEXT_SETLEASE (1u<<19)
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -1035,6 +1050,7 @@ extern struct daemon {
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
||||
struct dhcp_match_name *dhcp_name_match;
|
||||
struct dhcp_pxe_vendor *dhcp_pxe_vendors;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
struct dhcp_mac *dhcp_macs;
|
||||
struct dhcp_boot *boot_config;
|
||||
@@ -1060,6 +1076,7 @@ extern struct daemon {
|
||||
unsigned int duid_enterprise, duid_config_len;
|
||||
unsigned char *duid_config;
|
||||
char *dbus_name;
|
||||
char *ubus_name;
|
||||
char *dump_file;
|
||||
int dump_mask;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
@@ -1082,6 +1099,8 @@ extern struct daemon {
|
||||
int back_to_the_future;
|
||||
#endif
|
||||
struct frec *frec_list;
|
||||
struct frec_src *free_frec_src;
|
||||
int frec_src_count;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
@@ -1106,7 +1125,7 @@ extern struct daemon {
|
||||
int inotifyfd;
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
int netlinkfd;
|
||||
int netlinkfd, kernel_version;
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
|
||||
#endif
|
||||
@@ -1214,7 +1233,6 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *baddr, time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
@@ -1239,9 +1257,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
/* hash_questions.c */
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
|
||||
@@ -1286,6 +1306,9 @@ int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
int kernel_version(void);
|
||||
#endif
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code) ATTRIBUTE_NORETURN;
|
||||
@@ -1317,7 +1340,7 @@ void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait, int force);
|
||||
struct frec *get_new_frec(time_t now, int *wait, struct frec *force);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, union all_addr *source,
|
||||
unsigned int iface);
|
||||
@@ -1443,7 +1466,7 @@ void clear_cache_and_reload(time_t now);
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
char *netlink_init(void);
|
||||
void netlink_multicast(void);
|
||||
#endif
|
||||
|
||||
@@ -1636,7 +1659,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet);
|
||||
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable);
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
|
||||
/* arp.c */
|
||||
|
||||
+175
-159
@@ -223,138 +223,147 @@ static int check_date_range(unsigned long curtime, u32 date_start, u32 date_end)
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
|
||||
data, pointed to by *p, should be used raw. */
|
||||
static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
|
||||
unsigned char **p, u16 **desc)
|
||||
/* Return bytes of canonicalised rrdata one by one.
|
||||
Init state->ip with the RR, and state->end with the end of same.
|
||||
Init state->op to NULL.
|
||||
Init state->desc to RR descriptor.
|
||||
Init state->buff with a MAXDNAME * 2 buffer.
|
||||
|
||||
After each call which returns 1, state->op points to the next byte of data.
|
||||
On returning 0, the end has been reached.
|
||||
*/
|
||||
struct rdata_state {
|
||||
u16 *desc;
|
||||
size_t c;
|
||||
unsigned char *end, *ip, *op;
|
||||
char *buff;
|
||||
};
|
||||
|
||||
static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state *state)
|
||||
{
|
||||
int d = **desc;
|
||||
int d;
|
||||
|
||||
/* No more data needs mangling */
|
||||
if (d == (u16)-1)
|
||||
if (state->op && state->c != 1)
|
||||
{
|
||||
/* If there's more data than we have space for, just return what fits,
|
||||
we'll get called again for more chunks */
|
||||
if (end - *p > bufflen)
|
||||
{
|
||||
memcpy(buff, *p, bufflen);
|
||||
*p += bufflen;
|
||||
return bufflen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
state->op++;
|
||||
state->c--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
(*desc)++;
|
||||
|
||||
if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
|
||||
/* domain-name, canonicalise */
|
||||
return to_wire(buff);
|
||||
else
|
||||
{
|
||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
||||
if ((end - *p) < d)
|
||||
d = end - *p;
|
||||
|
||||
while (1)
|
||||
{
|
||||
d = *(state->desc);
|
||||
|
||||
if (d != 0)
|
||||
if (d == (u16)-1)
|
||||
{
|
||||
memcpy(buff, *p, d);
|
||||
*p += d;
|
||||
/* all the bytes to the end. */
|
||||
if ((state->c = state->end - state->ip) != 0)
|
||||
{
|
||||
state->op = state->ip;
|
||||
state->ip = state->end;;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->desc++;
|
||||
|
||||
if (d == (u16)0)
|
||||
{
|
||||
/* domain-name, canonicalise */
|
||||
int len;
|
||||
|
||||
if (!extract_name(header, plen, &state->ip, state->buff, 1, 0) ||
|
||||
(len = to_wire(state->buff)) == 0)
|
||||
continue;
|
||||
|
||||
state->c = len;
|
||||
state->op = (unsigned char *)state->buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
||||
if ((state->end - state->ip) < d)
|
||||
d = state->end - state->ip;
|
||||
|
||||
if (d == 0)
|
||||
continue;
|
||||
|
||||
state->op = state->ip;
|
||||
state->c = d;
|
||||
state->ip += d;
|
||||
}
|
||||
}
|
||||
|
||||
return d;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bubble sort the RRset into the canonical order.
|
||||
Note that the byte-streams from two RRs may get unsynced: consider
|
||||
RRs which have two domain-names at the start and then other data.
|
||||
The domain-names may have different lengths in each RR, but sort equal
|
||||
|
||||
------------
|
||||
|abcde|fghi|
|
||||
------------
|
||||
|abcd|efghi|
|
||||
------------
|
||||
|
||||
leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
*/
|
||||
/* Bubble sort the RRset into the canonical order. */
|
||||
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
int swap, quit, i, j;
|
||||
int swap, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
for (swap = 0, i = 0; i < rrsetidx-1; i++)
|
||||
{
|
||||
int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
|
||||
u16 *dp1, *dp2;
|
||||
unsigned char *end1, *end2;
|
||||
int rdlen1, rdlen2;
|
||||
struct rdata_state state1, state2;
|
||||
|
||||
/* Note that these have been determined to be OK previously,
|
||||
so we don't need to check for NULL return here. */
|
||||
unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
|
||||
unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
|
||||
state1.ip = skip_name(rrset[i], header, plen, 10);
|
||||
state2.ip = skip_name(rrset[i+1], header, plen, 10);
|
||||
state1.op = state2.op = NULL;
|
||||
state1.buff = buff1;
|
||||
state2.buff = buff2;
|
||||
state1.desc = state2.desc = rr_desc;
|
||||
|
||||
p1 += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen1, p1);
|
||||
end1 = p1 + rdlen1;
|
||||
state1.ip += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen1, state1.ip);
|
||||
if (!CHECK_LEN(header, state1.ip, plen, rdlen1))
|
||||
return rrsetidx; /* short packet */
|
||||
state1.end = state1.ip + rdlen1;
|
||||
|
||||
p2 += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen2, p2);
|
||||
end2 = p2 + rdlen2;
|
||||
|
||||
dp1 = dp2 = rr_desc;
|
||||
|
||||
for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
|
||||
state2.ip += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen2, state2.ip);
|
||||
if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
|
||||
return rrsetidx; /* short packet */
|
||||
state2.end = state2.ip + rdlen2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (left1 != 0)
|
||||
memmove(buff1, buff1 + len1 - left1, left1);
|
||||
int ok1, ok2;
|
||||
|
||||
if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
|
||||
{
|
||||
quit = 1;
|
||||
len1 = end1 - p1;
|
||||
memcpy(buff1 + left1, p1, len1);
|
||||
}
|
||||
len1 += left1;
|
||||
|
||||
if (left2 != 0)
|
||||
memmove(buff2, buff2 + len2 - left2, left2);
|
||||
|
||||
if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
|
||||
{
|
||||
quit = 1;
|
||||
len2 = end2 - p2;
|
||||
memcpy(buff2 + left2, p2, len2);
|
||||
}
|
||||
len2 += left2;
|
||||
|
||||
if (len1 > len2)
|
||||
left1 = len1 - len2, left2 = 0, len = len2;
|
||||
else
|
||||
left2 = len2 - len1, left1 = 0, len = len1;
|
||||
|
||||
rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
|
||||
|
||||
if (rc > 0 || (rc == 0 && quit && len1 > len2))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = quit = 1;
|
||||
}
|
||||
else if (rc == 0 && quit && len1 == len2)
|
||||
ok1 = get_rdata(header, plen, &state1);
|
||||
ok2 = get_rdata(header, plen, &state2);
|
||||
|
||||
if (!ok1 && !ok2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
else if (rc < 0)
|
||||
quit = 1;
|
||||
else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = 1;
|
||||
break;
|
||||
}
|
||||
else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
break;
|
||||
|
||||
/* arrive here when bytes are equal, go round the loop again
|
||||
and compare the next ones. */
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
@@ -569,15 +578,18 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
wire_len = to_wire(keyname);
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
|
||||
from_wire(keyname);
|
||||
|
||||
#define RRBUFLEN 128 /* Most RRs are smaller than this. */
|
||||
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
int seg;
|
||||
unsigned char *end, *cp;
|
||||
u16 len, *dp;
|
||||
int j;
|
||||
struct rdata_state state;
|
||||
u16 len;
|
||||
unsigned char rrbuf[RRBUFLEN];
|
||||
|
||||
p = rrset[i];
|
||||
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -586,12 +598,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
|
||||
if (labels < name_labels)
|
||||
{
|
||||
int k;
|
||||
for (k = name_labels - labels; k != 0; k--)
|
||||
for (j = name_labels - labels; j != 0; j--)
|
||||
{
|
||||
while (*name_start != '.' && *name_start != 0)
|
||||
name_start++;
|
||||
if (k != 1 && *name_start == '.')
|
||||
if (j != 1 && *name_start == '.')
|
||||
name_start++;
|
||||
}
|
||||
|
||||
@@ -606,30 +617,66 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
|
||||
hash->update(ctx, 4, p); /* class and type */
|
||||
hash->update(ctx, 4, (unsigned char *)&nsigttl);
|
||||
|
||||
p += 8; /* skip class, type, ttl */
|
||||
|
||||
p += 8; /* skip type, class, ttl */
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS;
|
||||
|
||||
end = p + rdlen;
|
||||
|
||||
/* canonicalise rdata and calculate length of same, use name buffer as workspace.
|
||||
Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
|
||||
cp = p;
|
||||
dp = rr_desc;
|
||||
for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
|
||||
len += end - cp;
|
||||
len = htons(len);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
|
||||
/* Now canonicalise again and digest. */
|
||||
cp = p;
|
||||
dp = rr_desc;
|
||||
while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
|
||||
hash->update(ctx, seg, (unsigned char *)name);
|
||||
if (cp != end)
|
||||
hash->update(ctx, end - cp, cp);
|
||||
|
||||
/* 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
|
||||
name buffer as workspace for get_rdata. */
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
state.buff = name;
|
||||
state.end = p + rdlen;
|
||||
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
if (j < RRBUFLEN)
|
||||
rrbuf[j] = *state.op;
|
||||
|
||||
len = htons((u16)j);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
|
||||
/* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
go back to the start and do it in chunks. */
|
||||
if (j >= RRBUFLEN)
|
||||
{
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
{
|
||||
rrbuf[j] = *state.op;
|
||||
|
||||
if (j == RRBUFLEN - 1)
|
||||
{
|
||||
hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
j = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (j != 0)
|
||||
hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
@@ -1003,7 +1050,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS");
|
||||
}
|
||||
|
||||
return STAT_OK;
|
||||
@@ -2056,35 +2103,4 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned int len;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
const struct nettle_hash *hash;
|
||||
void *ctx;
|
||||
unsigned char *digest;
|
||||
|
||||
if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
|
||||
return NULL;
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
break; /* bad packet */
|
||||
|
||||
len = to_wire(name);
|
||||
hash->update(ctx, len, (unsigned char *)name);
|
||||
/* CRC the class and type as well */
|
||||
hash->update(ctx, 4, p);
|
||||
|
||||
p += 4;
|
||||
if (!CHECK_LEN(header, p, plen, 0))
|
||||
break; /* bad packet */
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
return digest;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DNSSEC */
|
||||
+6
-2
@@ -132,8 +132,12 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio
|
||||
}
|
||||
|
||||
/* start UDP checksum */
|
||||
for (sum = 0, i = 0; i < IN6ADDRSZ; i++)
|
||||
sum += ((u16 *)&ip6.ip6_src)[i];
|
||||
for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
|
||||
{
|
||||
sum += ip6.ip6_src.s6_addr[i] + (ip6.ip6_src.s6_addr[i+1] << 8) ;
|
||||
sum += ip6.ip6_dst.s6_addr[i] + (ip6.ip6_dst.s6_addr[i+1] << 8) ;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+47
-28
@@ -264,7 +264,8 @@ static void encoder(unsigned char *in, char *out)
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
@@ -273,6 +274,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
replace = 1;
|
||||
*cacheablep = 0;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
@@ -288,14 +290,18 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
|
||||
}
|
||||
|
||||
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
|
||||
{
|
||||
*cacheablep = 0;
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
}
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
@@ -313,17 +319,18 @@ static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp = NULL;
|
||||
int sa_family = source->sa.sa_family;
|
||||
|
||||
int cacheable = 0;
|
||||
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
|
||||
|
||||
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet6->mask;
|
||||
@@ -331,6 +338,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
cacheable = 1;
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
@@ -343,6 +351,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
cacheable = 1; /* Address is constant */
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
@@ -350,8 +359,6 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
|
||||
len = 0;
|
||||
|
||||
if (addrp && opt->source_netmask != 0)
|
||||
{
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
@@ -359,18 +366,26 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
if (opt->source_netmask & 7)
|
||||
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheable = 1; /* No address ever supplied. */
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (cacheablep)
|
||||
*cacheablep = cacheable;
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
struct subnet_opt opt;
|
||||
|
||||
len = calc_subnet_opt(&opt, source);
|
||||
len = calc_subnet_opt(&opt, source, cacheable);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
|
||||
}
|
||||
|
||||
@@ -383,18 +398,18 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
calc_len = calc_subnet_opt(&opt, peer);
|
||||
calc_len = calc_subnet_opt(&opt, peer, NULL);
|
||||
|
||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
return 1;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return 1; /* bad packet */
|
||||
|
||||
/* check if option there */
|
||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
return 1;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return 1; /* bad packet */
|
||||
|
||||
/* check if option there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
@@ -412,24 +427,28 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||
in the reply. Set *cacheable to zero if we add an option which the answer
|
||||
may depend on. */
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet)
|
||||
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)
|
||||
{
|
||||
*check_subnet = 0;
|
||||
|
||||
*cacheable = 1;
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, limit, source, now);
|
||||
plen = add_mac(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
|
||||
plen = add_dns_client(header, plen, limit, source, now);
|
||||
|
||||
plen = add_dns_client(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
plen = add_source_addr(header, plen, limit, source);
|
||||
plen = add_source_addr(header, plen, limit, source, cacheable);
|
||||
*check_subnet = 1;
|
||||
}
|
||||
|
||||
|
||||
+220
-106
@@ -16,10 +16,12 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct frec *lookup_frec(unsigned short id, void *hash);
|
||||
static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
|
||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
union mysockaddr *addr,
|
||||
void *hash);
|
||||
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
|
||||
|
||||
static unsigned short get_id(void);
|
||||
static void free_frec(struct frec *f);
|
||||
|
||||
@@ -93,10 +95,13 @@ int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
|
||||
while (retry_send(sendmsg(fd, &msg, 0)));
|
||||
|
||||
/* If interface is still in DAD, EINVAL results - ignore that. */
|
||||
if (errno != 0 && errno != EINVAL)
|
||||
if (errno != 0)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* If interface is still in DAD, EINVAL results - ignore that. */
|
||||
if (errno != EINVAL)
|
||||
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -252,20 +257,29 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
int type = SERV_DO_DNSSEC, norebind = 0;
|
||||
union all_addr *addrp = NULL;
|
||||
unsigned int flags = 0;
|
||||
unsigned int fwd_flags = 0;
|
||||
struct server *start = NULL;
|
||||
#ifdef HAVE_DNSSEC
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
#ifdef HAVE_DNSSEC
|
||||
int do_dnssec = 0;
|
||||
#else
|
||||
unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
void *hash = &crc;
|
||||
#endif
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
(void)do_bit;
|
||||
|
||||
|
||||
if (header->hb4 & HB4_CD)
|
||||
fwd_flags |= FREC_CHECKING_DISABLED;
|
||||
if (ad_reqd)
|
||||
fwd_flags |= FREC_AD_QUESTION;
|
||||
if (oph)
|
||||
fwd_flags |= FREC_HAS_PHEADER;
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (do_bit)
|
||||
fwd_flags |= FREC_DO_QUESTION;
|
||||
#endif
|
||||
|
||||
/* may be no servers available. */
|
||||
if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||
if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
||||
{
|
||||
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
||||
fall back to 1280, which should work everywhere on IPv6.
|
||||
@@ -336,6 +350,39 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Query from new source, but the same query may be in progress
|
||||
from another source. If so, just add this client to the
|
||||
list that will get the reply.*/
|
||||
|
||||
if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
|
||||
(forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
{
|
||||
/* Note whine_malloc() zeros memory. */
|
||||
if (!daemon->free_frec_src &&
|
||||
daemon->frec_src_count < daemon->ftabsize &&
|
||||
(daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
{
|
||||
daemon->frec_src_count++;
|
||||
daemon->free_frec_src->next = NULL;
|
||||
}
|
||||
|
||||
/* If we've been spammed with many duplicates, just drop the query. */
|
||||
if (daemon->free_frec_src)
|
||||
{
|
||||
struct frec_src *new = daemon->free_frec_src;
|
||||
daemon->free_frec_src = new->next;
|
||||
new->next = forward->frec_src.next;
|
||||
forward->frec_src.next = new;
|
||||
new->orig_id = ntohs(header->id);
|
||||
new->source = *udpaddr;
|
||||
new->dest = *dst_addr;
|
||||
new->log_id = daemon->log_id;
|
||||
new->iface = dst_iface;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
@@ -343,22 +390,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
do_dnssec = type & SERV_DO_DNSSEC;
|
||||
#endif
|
||||
type &= ~SERV_DO_DNSSEC;
|
||||
|
||||
|
||||
if (daemon->servers && !flags)
|
||||
forward = get_new_frec(now, NULL, 0);
|
||||
forward = get_new_frec(now, NULL, NULL);
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
|
||||
if (forward)
|
||||
{
|
||||
forward->source = *udpaddr;
|
||||
forward->dest = *dst_addr;
|
||||
forward->iface = dst_iface;
|
||||
forward->orig_id = ntohs(header->id);
|
||||
forward->frec_src.source = *udpaddr;
|
||||
forward->frec_src.orig_id = ntohs(header->id);
|
||||
forward->frec_src.dest = *dst_addr;
|
||||
forward->frec_src.iface = dst_iface;
|
||||
forward->frec_src.next = NULL;
|
||||
forward->new_id = get_id();
|
||||
forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
forward->forwardall = 0;
|
||||
forward->flags = 0;
|
||||
forward->flags = fwd_flags;
|
||||
if (norebind)
|
||||
forward->flags |= FREC_NOREBIND;
|
||||
if (header->hb4 & HB4_CD)
|
||||
@@ -408,18 +456,21 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (!flags && forward)
|
||||
{
|
||||
struct server *firstsentto = start;
|
||||
int subnet, forwarded = 0;
|
||||
int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
forward->log_id = daemon->log_id;
|
||||
forward->frec_src.log_id = daemon->log_id;
|
||||
|
||||
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
|
||||
|
||||
if (!cacheable)
|
||||
forward->flags |= FREC_NO_CACHE;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
|
||||
{
|
||||
@@ -487,7 +538,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
|
||||
if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -552,7 +603,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
return 1;
|
||||
|
||||
/* could not send on, prepare to return */
|
||||
header->id = htons(forward->orig_id);
|
||||
header->id = htons(forward->frec_src.orig_id);
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
|
||||
@@ -603,7 +654,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
{
|
||||
/* Get extended RCODE. */
|
||||
@@ -673,7 +724,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
|
||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
(void)prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
if (!option_bool(OPT_LOG))
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
@@ -766,9 +817,6 @@ void reply_query(int fd, int family, time_t now)
|
||||
size_t nn;
|
||||
struct server *server;
|
||||
void *hash;
|
||||
#ifndef HAVE_DNSSEC
|
||||
unsigned int crc;
|
||||
#endif
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -795,14 +843,9 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
|
||||
server->edns_pktsz = daemon->edns_pktsz;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
hash = hash_questions(header, n, daemon->namebuff);
|
||||
#else
|
||||
hash = &crc;
|
||||
crc = questions_crc(header, n, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
if (!(forward = lookup_frec(ntohs(header->id), hash)))
|
||||
if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
@@ -812,8 +855,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
/* log_query gets called indirectly all over the place, so
|
||||
pass these in global variables - sorry. */
|
||||
daemon->log_display_id = forward->log_id;
|
||||
daemon->log_source_addr = &forward->source;
|
||||
daemon->log_display_id = forward->frec_src.log_id;
|
||||
daemon->log_source_addr = &forward->frec_src.source;
|
||||
|
||||
if (daemon->ignore_addr && RCODE(header) == NOERROR &&
|
||||
check_for_ignored_address(header, n, daemon->ignore_addr))
|
||||
@@ -831,7 +874,6 @@ void reply_query(int fd, int family, time_t now)
|
||||
int is_sign;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* For DNSSEC originated queries, just retry the query to the same server. */
|
||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||
{
|
||||
struct server *start;
|
||||
@@ -857,6 +899,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
|
||||
|
||||
fd = -1;
|
||||
|
||||
if (start->sfd)
|
||||
fd = start->sfd->fd;
|
||||
else
|
||||
@@ -864,19 +908,21 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (start->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
/* may have changed family */
|
||||
if (!forward->rfd6)
|
||||
forward->rfd6 = allocate_rfd(AF_INET6);
|
||||
fd = forward->rfd6->fd;
|
||||
if (forward->rfd6 || (forward->rfd6 = allocate_rfd(AF_INET6)))
|
||||
fd = forward->rfd6->fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* may have changed family */
|
||||
if (!forward->rfd4)
|
||||
forward->rfd4 = allocate_rfd(AF_INET);
|
||||
fd = forward->rfd4->fd;
|
||||
if (forward->rfd4 || (forward->rfd4 = allocate_rfd(AF_INET)))
|
||||
fd = forward->rfd4->fd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Can't get socket. */
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start->addr);
|
||||
#endif
|
||||
@@ -957,7 +1003,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
{
|
||||
forward->sentto->edns_pktsz = SAFE_PKTSZ;
|
||||
forward->sentto->pktsz_reduced = now;
|
||||
prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
|
||||
}
|
||||
|
||||
@@ -1036,7 +1082,9 @@ void reply_query(int fd, int family, time_t now)
|
||||
/* Find the original query that started it all.... */
|
||||
for (orig = forward; orig->dependent; orig = orig->dependent);
|
||||
|
||||
if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
|
||||
/* Make sure we don't expire and free the orig frec during the
|
||||
allocation of a new one. */
|
||||
if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
|
||||
status = STAT_ABANDONED;
|
||||
else
|
||||
{
|
||||
@@ -1083,6 +1131,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
new->sentto = server;
|
||||
new->rfd4 = NULL;
|
||||
new->rfd6 = NULL;
|
||||
new->frec_src.next = NULL;
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
|
||||
new->forwardall = 0;
|
||||
|
||||
@@ -1110,8 +1159,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
|
||||
querystr("dnssec-query", querytype));
|
||||
|
||||
if ((hash = hash_questions(header, nn, daemon->namebuff)))
|
||||
memcpy(new->hash, hash, HASH_SIZE);
|
||||
memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
|
||||
new->new_id = get_id();
|
||||
header->id = htons(new->new_id);
|
||||
/* Save query for retransmission */
|
||||
@@ -1145,7 +1193,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
|
||||
if (get_incoming_mark(&orig->frec_src.source, &orig->frec_src.dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -1216,12 +1264,19 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->hb4 |= HB4_CD;
|
||||
else
|
||||
header->hb4 &= ~HB4_CD;
|
||||
|
||||
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||
since the cache is ignorant of such things. */
|
||||
if (forward->flags & FREC_NO_CACHE)
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
struct frec_src *src;
|
||||
|
||||
header->id = htons(forward->frec_src.orig_id);
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
|
||||
@@ -1237,13 +1292,26 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
for (src = &forward->frec_src; src; src = src->next)
|
||||
{
|
||||
header->id = htons(src->orig_id);
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
|
||||
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
|
||||
#endif
|
||||
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&src->source, &src->dest, src->iface);
|
||||
|
||||
if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
{
|
||||
daemon->log_display_id = src->log_id;
|
||||
daemon->log_source_addr = &src->source;
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
}
|
||||
@@ -1279,8 +1347,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||
#endif
|
||||
} control_u;
|
||||
int family = listen->addr.sa.sa_family;
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
|
||||
int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -1292,7 +1361,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
auth_dns = listen->iface->dns_auth;
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
@@ -1322,9 +1391,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
information disclosure. */
|
||||
memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
source_addr.sa.sa_family = family;
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
/* Source-port == 0 is an error, we can't send back to that.
|
||||
http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
|
||||
@@ -1344,7 +1413,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
struct addrlist *addr;
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
if ((addr->flags & ADDRLIST_IPV6) &&
|
||||
@@ -1382,7 +1451,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
@@ -1395,7 +1464,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
@@ -1420,7 +1489,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
@@ -1441,16 +1510,16 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
|
||||
!label_exception(if_index, listen->family, &dst_addr))
|
||||
if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
|
||||
!label_exception(if_index, family, &dst_addr))
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||
if (family == AF_INET && option_bool(OPT_LOCALISE))
|
||||
{
|
||||
struct irec *iface;
|
||||
|
||||
@@ -1495,7 +1564,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
char *types = querystr(auth_dns ? "auth" : "query", type);
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(union all_addr *)&source_addr.in.sin_addr, types);
|
||||
else
|
||||
@@ -1761,7 +1830,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
|
||||
int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
size_t m;
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
@@ -1932,7 +2001,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
char *domain = NULL;
|
||||
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
|
||||
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
@@ -1964,15 +2033,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (!flags && last_server)
|
||||
{
|
||||
struct server *firstsendto = NULL;
|
||||
#ifdef HAVE_DNSSEC
|
||||
unsigned char *newhash, hash[HASH_SIZE];
|
||||
if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
|
||||
memcpy(hash, newhash, HASH_SIZE);
|
||||
else
|
||||
memset(hash, 0, HASH_SIZE);
|
||||
#else
|
||||
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
|
||||
#endif
|
||||
unsigned char hash[HASH_SIZE];
|
||||
memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
|
||||
|
||||
/* Loop round available servers until we succeed in connecting to one.
|
||||
Note that this code subtly ensures that consecutive queries on this connection
|
||||
which can go to the same server, do so. */
|
||||
@@ -2111,21 +2174,17 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* If the crc of the question section doesn't match the crc we sent, then
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
#ifdef HAVE_DNSSEC
|
||||
newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
|
||||
if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
|
||||
if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
|
||||
{
|
||||
m = 0;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
{
|
||||
m = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||
since the cache is ignorant of such things. */
|
||||
if (!cacheable)
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
@@ -2220,6 +2279,17 @@ void free_rfd(struct randfd *rfd)
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
struct frec_src *last;
|
||||
|
||||
/* add back to freelist if not the record builtin to every frec. */
|
||||
for (last = f->frec_src.next; last && last->next; last = last->next) ;
|
||||
if (last)
|
||||
{
|
||||
last->next = daemon->free_frec_src;
|
||||
daemon->free_frec_src = f->frec_src.next;
|
||||
}
|
||||
|
||||
f->frec_src.next = NULL;
|
||||
free_rfd(f->rfd4);
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
@@ -2248,9 +2318,10 @@ static void free_frec(struct frec *f)
|
||||
else return *wait zero if one available, or *wait is delay to
|
||||
when the oldest in-use record will expire. Impose an absolute
|
||||
limit of 4*TIMEOUT before we wipe things (for random sockets).
|
||||
If force is set, always return a result, even if we have
|
||||
to allocate above the limit. */
|
||||
struct frec *get_new_frec(time_t now, int *wait, int force)
|
||||
If force is non-NULL, always return a result, even if we have
|
||||
to allocate above the limit, and never free the record pointed
|
||||
to by the force argument. */
|
||||
struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
|
||||
{
|
||||
struct frec *f, *oldest, *target;
|
||||
int count;
|
||||
@@ -2267,7 +2338,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
|
||||
/* Don't free DNSSEC sub-queries here, as we may end up with
|
||||
dangling references to them. They'll go when their "real" query
|
||||
is freed. */
|
||||
if (!f->dependent)
|
||||
if (!f->dependent && f != force)
|
||||
#endif
|
||||
{
|
||||
if (difftime(now, f->time) >= 4*TIMEOUT)
|
||||
@@ -2331,15 +2402,25 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
|
||||
return f; /* OK if malloc fails and this is NULL */
|
||||
}
|
||||
|
||||
/* crc is all-ones if not known. */
|
||||
static struct frec *lookup_frec(unsigned short id, void *hash)
|
||||
static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == id &&
|
||||
(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
return f;
|
||||
(memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
{
|
||||
/* sent from random port */
|
||||
if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
|
||||
return f;
|
||||
|
||||
if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
|
||||
return f;
|
||||
|
||||
/* sent to upstream from bound socket. */
|
||||
if (f->sentto->sfd && f->sentto->sfd->fd == fd)
|
||||
return f;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -2349,17 +2430,42 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
struct frec_src *src;
|
||||
|
||||
for (f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
!(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
|
||||
memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
for (src = &f->frec_src; src; src = src->next)
|
||||
if (src->orig_id == id &&
|
||||
sockaddr_isequal(&src->source, addr))
|
||||
return f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
/* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||
ensures that no frec created for internal DNSSEC query can be returned here.
|
||||
|
||||
Similarly FREC_NO_CACHE is never set in flags, so a query which is
|
||||
contigent on a particular source address EDNS0 option will never be matched. */
|
||||
|
||||
#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
|
||||
| FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
f->orig_id == id &&
|
||||
memcmp(hash, f->hash, HASH_SIZE) == 0 &&
|
||||
sockaddr_isequal(&f->source, addr))
|
||||
(f->flags & FLAGMASK) == flags &&
|
||||
memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
return f;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Send query packet again, if we can. */
|
||||
void resend_query()
|
||||
{
|
||||
@@ -2400,12 +2506,20 @@ void server_gone(struct server *server)
|
||||
static unsigned short get_id(void)
|
||||
{
|
||||
unsigned short ret = 0;
|
||||
struct frec *f;
|
||||
|
||||
do
|
||||
ret = rand16();
|
||||
while (lookup_frec(ret, NULL));
|
||||
|
||||
return ret;
|
||||
while (1)
|
||||
{
|
||||
ret = rand16();
|
||||
|
||||
/* ensure id is unique. */
|
||||
for (f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == ret)
|
||||
break;
|
||||
|
||||
if (!f)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/* 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_NETTLEHASH)
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
const struct nettle_hash *hash;
|
||||
void *ctx;
|
||||
unsigned char *digest;
|
||||
|
||||
if (!(hash = hash_find("sha256")) || !hash_init(hash, &ctx, &digest))
|
||||
{
|
||||
/* don't think this can ever happen. */
|
||||
static unsigned char dummy[HASH_SIZE];
|
||||
static int warned = 0;
|
||||
|
||||
if (!warned)
|
||||
my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object"));
|
||||
warned = 1;
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
#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[]);
|
||||
|
||||
|
||||
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
-16
@@ -22,9 +22,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/* We want to be able to compile against old header files
|
||||
@@ -87,20 +85,7 @@ static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, con
|
||||
|
||||
void ipset_init(void)
|
||||
{
|
||||
struct utsname utsname;
|
||||
int version;
|
||||
char *split;
|
||||
|
||||
if (uname(&utsname) < 0)
|
||||
die(_("failed to find kernel version: %s"), NULL, EC_MISC);
|
||||
|
||||
split = strtok(utsname.release, ".");
|
||||
version = (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
old_kernel = (version < KERNEL_VERSION(2,6,32));
|
||||
old_kernel = (daemon->kernel_version < KERNEL_VERSION(2,6,32));
|
||||
|
||||
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
|
||||
return;
|
||||
|
||||
+19
-2
@@ -22,6 +22,15 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
/* Blergh. Radv does this, so that's our excuse. */
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
||||
#ifndef NETLINK_NO_ENOBUFS
|
||||
#define NETLINK_NO_ENOBUFS 5
|
||||
#endif
|
||||
|
||||
/* linux 2.6.19 buggers up the headers, patch it up here. */
|
||||
#ifndef IFA_RTA
|
||||
# define IFA_RTA(r) \
|
||||
@@ -40,10 +49,11 @@ static u32 netlink_pid;
|
||||
|
||||
static void nl_async(struct nlmsghdr *h);
|
||||
|
||||
void netlink_init(void)
|
||||
char *netlink_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
int opt = 1;
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
@@ -74,12 +84,19 @@ void netlink_init(void)
|
||||
if (daemon->netlinkfd == -1 ||
|
||||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
|
||||
die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
|
||||
/* save pid assigned by bind() and retrieved by getsockname() */
|
||||
netlink_pid = addr.nl_pid;
|
||||
|
||||
iov.iov_len = 100;
|
||||
iov.iov_base = safe_malloc(iov.iov_len);
|
||||
|
||||
if (daemon->kernel_version >= KERNEL_VERSION(2,6,30) &&
|
||||
setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1)
|
||||
return _("warning: failed to set NETLINK_NO_ENOBUFS on netlink socket");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t netlink_recv(void)
|
||||
|
||||
+168
-32
@@ -388,10 +388,11 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
/* check whether the interface IP has been added already
|
||||
we call this routine multiple times. */
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
|
||||
{
|
||||
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
|
||||
iface->found = 1; /* for garbage collection */
|
||||
iface->netmask = netmask;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -532,7 +533,82 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
|
||||
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Clean old interfaces no longer found.
|
||||
*/
|
||||
static void clean_interfaces()
|
||||
{
|
||||
struct irec *iface;
|
||||
struct irec **up = &daemon->interfaces;
|
||||
|
||||
for (iface = *up; iface; iface = *up)
|
||||
{
|
||||
if (!iface->found && !iface->done)
|
||||
{
|
||||
*up = iface->next;
|
||||
free(iface->name);
|
||||
free(iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
up = &iface->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Release listener if no other interface needs it.
|
||||
*
|
||||
* @return 1 if released, 0 if still required
|
||||
*/
|
||||
static int release_listener(struct listener *l)
|
||||
{
|
||||
if (l->used > 1)
|
||||
{
|
||||
struct irec *iface;
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
|
||||
{
|
||||
if (iface->found)
|
||||
{
|
||||
/* update listener to point to active interface instead */
|
||||
if (!l->iface->found)
|
||||
l->iface = iface;
|
||||
}
|
||||
else
|
||||
{
|
||||
l->used--;
|
||||
iface->done = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Someone is still using this listener, skip its deletion */
|
||||
if (l->used > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l->iface->done)
|
||||
{
|
||||
int port;
|
||||
|
||||
port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
|
||||
l->iface->name, l->iface->index, daemon->addrbuff, port);
|
||||
/* In case it ever returns */
|
||||
l->iface->done = 0;
|
||||
}
|
||||
|
||||
if (l->fd != -1)
|
||||
close(l->fd);
|
||||
if (l->tcpfd != -1)
|
||||
close(l->tcpfd);
|
||||
if (l->tftpfd != -1)
|
||||
close(l->tftpfd);
|
||||
|
||||
free(l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int enumerate_interfaces(int reset)
|
||||
{
|
||||
static struct addrlist *spare = NULL;
|
||||
@@ -630,6 +706,7 @@ int enumerate_interfaces(int reset)
|
||||
in OPT_CLEVERBIND mode, that at listener will just disappear after
|
||||
a call to enumerate_interfaces, this is checked OK on all calls. */
|
||||
struct listener *l, *tmp, **up;
|
||||
int freed = 0;
|
||||
|
||||
for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
|
||||
{
|
||||
@@ -637,25 +714,17 @@ int enumerate_interfaces(int reset)
|
||||
|
||||
if (!l->iface || l->iface->found)
|
||||
up = &l->next;
|
||||
else
|
||||
else if (release_listener(l))
|
||||
{
|
||||
*up = l->next;
|
||||
|
||||
/* In case it ever returns */
|
||||
l->iface->done = 0;
|
||||
|
||||
if (l->fd != -1)
|
||||
close(l->fd);
|
||||
if (l->tcpfd != -1)
|
||||
close(l->tcpfd);
|
||||
if (l->tftpfd != -1)
|
||||
close(l->tftpfd);
|
||||
|
||||
free(l);
|
||||
*up = tmp;
|
||||
freed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (freed)
|
||||
clean_interfaces();
|
||||
}
|
||||
|
||||
|
||||
errno = errsave;
|
||||
spare = param.spare;
|
||||
|
||||
@@ -728,7 +797,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||
{
|
||||
#ifdef TCP_FASTOPEN
|
||||
int qlen = 5;
|
||||
setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
|
||||
#endif
|
||||
|
||||
if (listen(fd, TCP_BACKLOG) == -1)
|
||||
@@ -785,6 +854,8 @@ int set_ipv6pktinfo(int fd)
|
||||
/* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
|
||||
int tcp_interface(int fd, int af)
|
||||
{
|
||||
(void)fd; /* suppress potential unused warning */
|
||||
(void)af; /* suppress potential unused warning */
|
||||
int if_index = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
@@ -893,10 +964,11 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
|
||||
{
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->next = NULL;
|
||||
l->family = addr->sa.sa_family;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->addr = *addr;
|
||||
l->used = 1;
|
||||
l->iface = NULL;
|
||||
}
|
||||
|
||||
@@ -935,20 +1007,48 @@ void create_wildcard_listeners(void)
|
||||
daemon->listeners = l;
|
||||
}
|
||||
|
||||
static struct listener *find_listener(union mysockaddr *addr)
|
||||
{
|
||||
struct listener *l;
|
||||
for (l = daemon->listeners; l; l = l->next)
|
||||
if (sockaddr_isequal(&l->addr, addr))
|
||||
return l;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void create_bound_listeners(int dienow)
|
||||
{
|
||||
struct listener *new;
|
||||
struct irec *iface;
|
||||
struct iname *if_tmp;
|
||||
struct listener *existing;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (!iface->done && !iface->dad && iface->found &&
|
||||
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||
if (!iface->done && !iface->dad && iface->found)
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
existing = find_listener(&iface->addr);
|
||||
if (existing)
|
||||
{
|
||||
iface->done = 1;
|
||||
existing->used++; /* increase usage counter */
|
||||
}
|
||||
else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
|
||||
/* Don't log the initial set of listen addresses created
|
||||
at startup, since this is happening before the logging
|
||||
system is initialised and the sign-on printed. */
|
||||
if (!dienow)
|
||||
{
|
||||
int port = prettyprint_addr(&iface->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s port %d"),
|
||||
iface->name, iface->index, daemon->addrbuff, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for --listen-address options that haven't been used because there's
|
||||
@@ -968,6 +1068,12 @@ void create_bound_listeners(int dienow)
|
||||
{
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
|
||||
if (!dienow)
|
||||
{
|
||||
int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,17 +1262,46 @@ int random_sock(int family)
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
|
||||
{
|
||||
union mysockaddr addr_copy = *addr;
|
||||
unsigned short port;
|
||||
int tries = 1, done = 0;
|
||||
unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
|
||||
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
port = addr_copy.in.sin_port;
|
||||
else
|
||||
port = addr_copy.in6.sin6_port;
|
||||
|
||||
/* cannot set source _port_ for TCP connections. */
|
||||
if (is_tcp)
|
||||
port = 0;
|
||||
|
||||
/* Bind a random port within the range given by min-port and max-port */
|
||||
if (port == 0)
|
||||
{
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
addr_copy.in.sin_port = 0;
|
||||
else
|
||||
addr_copy.in6.sin6_port = 0;
|
||||
tries = ports_avail < 30 ? 3 * ports_avail : 100;
|
||||
port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
|
||||
while (tries--)
|
||||
{
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
addr_copy.in.sin_port = port;
|
||||
else
|
||||
addr_copy.in6.sin6_port = port;
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)
|
||||
{
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno != EADDRINUSE && errno != EACCES)
|
||||
return 0;
|
||||
|
||||
port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
|
||||
}
|
||||
|
||||
if (!done)
|
||||
return 0;
|
||||
|
||||
if (!is_tcp && ifindex > 0)
|
||||
@@ -1187,6 +1322,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
|
||||
#endif
|
||||
}
|
||||
|
||||
(void)intname; /* suppress potential unused warning */
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (intname[0] != 0 &&
|
||||
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
|
||||
@@ -1298,7 +1434,7 @@ void pre_allocate_sfds(void)
|
||||
errno != 0 &&
|
||||
option_bool(OPT_NOWILD))
|
||||
{
|
||||
prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
(void)prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
if (srv->interface[0] != 0)
|
||||
{
|
||||
strcat(daemon->namebuff, " ");
|
||||
|
||||
+62
-12
@@ -167,6 +167,7 @@ struct myoption {
|
||||
#define LOPT_IGNORE_CLID 358
|
||||
#define LOPT_SINGLE_PORT 359
|
||||
#define LOPT_SCRIPT_TIME 360
|
||||
#define LOPT_PXE_VENDOR 361
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -238,7 +239,7 @@ static const struct myoption opts[] =
|
||||
{ "caa-record", 1, 0 , LOPT_CAA },
|
||||
{ "dns-rr", 1, 0, LOPT_RR },
|
||||
{ "enable-dbus", 2, 0, '1' },
|
||||
{ "enable-ubus", 0, 0, LOPT_UBUS },
|
||||
{ "enable-ubus", 2, 0, LOPT_UBUS },
|
||||
{ "bootp-dynamic", 2, 0, '3' },
|
||||
{ "dhcp-mac", 1, 0, '4' },
|
||||
{ "no-ping", 0, 0, '5' },
|
||||
@@ -270,6 +271,7 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
|
||||
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE },
|
||||
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
|
||||
{ "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
|
||||
{ "interface-name", 1, 0, LOPT_INTNAME },
|
||||
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
|
||||
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
|
||||
@@ -383,6 +385,7 @@ static struct {
|
||||
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
|
||||
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
|
||||
{ LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
|
||||
{ LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
|
||||
{ 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
|
||||
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
|
||||
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
|
||||
@@ -428,7 +431,7 @@ static struct {
|
||||
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
|
||||
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
|
||||
{ '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
||||
{ LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL },
|
||||
{ LOPT_UBUS, ARG_ONE, "[=<busname>]", gettext_noop("Enable the UBus interface."), NULL },
|
||||
{ '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
|
||||
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
|
||||
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
|
||||
@@ -1225,7 +1228,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
is_addr6 = is_dec = is_hex = 0;
|
||||
is_dec = is_hex = 0;
|
||||
dots++;
|
||||
}
|
||||
else if (c == '-')
|
||||
@@ -1260,6 +1263,12 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
|
||||
if (!found_colon)
|
||||
is_addr6 = 0;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* NTP server option takes hex, addresses or FQDN */
|
||||
if (is6 && new->opt == OPTION6_NTP_SERVER && !is_hex)
|
||||
opt_len |= is_addr6 ? OT_ADDR_LIST : OT_RFC1035_NAME;
|
||||
#endif
|
||||
|
||||
/* We know that some options take addresses */
|
||||
if (opt_len & OT_ADDR_LIST)
|
||||
@@ -1521,8 +1530,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
}
|
||||
else if (comma && (opt_len & OT_RFC1035_NAME))
|
||||
{
|
||||
unsigned char *p = NULL, *newp, *end;
|
||||
unsigned char *p = NULL, *q, *newp, *end;
|
||||
int len = 0;
|
||||
int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
|
||||
@@ -1532,7 +1542,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
if (!dom)
|
||||
goto_err(_("bad domain in dhcp-option"));
|
||||
|
||||
newp = opt_malloc(len + strlen(dom) + 2);
|
||||
newp = opt_malloc(len + header_size + strlen(dom) + 2);
|
||||
|
||||
if (p)
|
||||
{
|
||||
@@ -1541,8 +1551,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
}
|
||||
|
||||
p = newp;
|
||||
end = do_rfc1035_name(p + len, dom, NULL);
|
||||
q = p + len;
|
||||
end = do_rfc1035_name(q + header_size, dom, NULL);
|
||||
*end++ = 0;
|
||||
if (is6 && new->opt == OPTION6_NTP_SERVER)
|
||||
{
|
||||
PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
|
||||
PUTSHORT(end - q - 2, q);
|
||||
}
|
||||
len = end - p;
|
||||
free(dom);
|
||||
|
||||
@@ -1868,7 +1884,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
daemon->dbus_name = DNSMASQ_SERVICE;
|
||||
break;
|
||||
|
||||
|
||||
case LOPT_UBUS: /* --enable-ubus */
|
||||
set_option_bool(OPT_UBUS);
|
||||
if (arg)
|
||||
daemon->ubus_name = opt_string_alloc(arg);
|
||||
else
|
||||
daemon->ubus_name = DNSMASQ_UBUS_NAME;
|
||||
break;
|
||||
|
||||
case '8': /* --log-facility */
|
||||
/* may be a filename */
|
||||
if (strchr(arg, '/') || strcmp (arg, "-") == 0)
|
||||
@@ -2970,7 +2994,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
|
||||
|
||||
memset (new, 0, sizeof(*new));
|
||||
new->lease_time = DEFLEASE;
|
||||
|
||||
while(1)
|
||||
{
|
||||
@@ -3020,6 +3043,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (inet_pton(AF_INET, a[0], &new->start))
|
||||
{
|
||||
new->next = daemon->dhcp;
|
||||
new->lease_time = DEFLEASE;
|
||||
daemon->dhcp = new;
|
||||
new->end = new->start;
|
||||
if (strcmp(a[1], "static") == 0)
|
||||
@@ -3067,6 +3091,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->flags |= CONTEXT_V6;
|
||||
new->prefix = 64; /* default */
|
||||
new->end6 = new->start6;
|
||||
new->lease_time = DEFLEASE6;
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
|
||||
@@ -3166,7 +3191,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (strcmp(a[leasepos], "infinite") == 0)
|
||||
new->lease_time = 0xffffffff;
|
||||
{
|
||||
new->lease_time = 0xffffffff;
|
||||
new->flags |= CONTEXT_SETLEASE;
|
||||
}
|
||||
else if (strcmp(a[leasepos], "deprecated") == 0)
|
||||
new->flags |= CONTEXT_DEPRECATE;
|
||||
else
|
||||
@@ -3205,6 +3233,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err_free(_("bad dhcp-range"), new);
|
||||
|
||||
new->lease_time = atoi(a[leasepos]) * fac;
|
||||
new->flags |= CONTEXT_SETLEASE;
|
||||
/* Leases of a minute or less confuse
|
||||
some clients, notably Apple's */
|
||||
if (new->lease_time < 120)
|
||||
@@ -3212,6 +3241,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3309,7 +3339,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (!atoi_check(pref, &new_addr->prefixlen) ||
|
||||
new_addr->prefixlen > 128 ||
|
||||
(((1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
|
||||
((((u64)1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
|
||||
{
|
||||
dhcp_config_free(new);
|
||||
ret_err(_("bad IPv6 prefix"));
|
||||
@@ -3645,8 +3675,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->val = opt_malloc(new->len);
|
||||
memcpy(new->val + 1, arg, new->len - 1);
|
||||
|
||||
new->u.vendor_class = (unsigned char *)"PXEClient";
|
||||
new->flags = DHOPT_VENDOR;
|
||||
new->u.vendor_class = NULL;
|
||||
new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
|
||||
|
||||
if (comma && atoi_check(comma, &timeout))
|
||||
*(new->val) = timeout;
|
||||
@@ -3908,6 +3938,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->override_relays;
|
||||
daemon->override_relays = new;
|
||||
arg = comma;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOPT_PXE_VENDOR: /* --dhcp-pxe-vendor */
|
||||
{
|
||||
while (arg) {
|
||||
struct dhcp_pxe_vendor *new = opt_malloc(sizeof(struct dhcp_pxe_vendor));
|
||||
comma = split(arg);
|
||||
new->data = opt_string_alloc(arg);
|
||||
new->next = daemon->dhcp_pxe_vendors;
|
||||
daemon->dhcp_pxe_vendors = new;
|
||||
arg = comma;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -5185,6 +5228,13 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
strcat(buff, daemon->authserver);
|
||||
daemon->hostmaster = opt_string_alloc(buff);
|
||||
}
|
||||
|
||||
if (!daemon->dhcp_pxe_vendors)
|
||||
{
|
||||
daemon->dhcp_pxe_vendors = opt_malloc(sizeof(struct dhcp_pxe_vendor));
|
||||
daemon->dhcp_pxe_vendors->data = opt_string_alloc(DHCP_PXE_DEF_VENDOR);
|
||||
daemon->dhcp_pxe_vendors->next = NULL;
|
||||
}
|
||||
|
||||
/* only one of these need be specified: the other defaults to the host-name */
|
||||
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||
|
||||
+5
-2
@@ -626,8 +626,11 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
real_prefix = context->prefix;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
/* find floor time, don't reduce below 3 * RA interval.
|
||||
If the lease time has been left as default, don't
|
||||
use that as a floor. */
|
||||
if ((context->flags & CONTEXT_SETLEASE) &&
|
||||
time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)(3 * param->adv_interval)))
|
||||
|
||||
+23
-56
@@ -333,55 +333,6 @@ unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *h
|
||||
return ansp;
|
||||
}
|
||||
|
||||
/* CRC the question section. This is used to safely detect query
|
||||
retransmission and to detect answers to questions we didn't ask, which
|
||||
might be poisoning attacks. Note that we decode the name rather
|
||||
than CRC the raw bytes, since replies might be compressed differently.
|
||||
We ignore case in the names for the same reason. Return all-ones
|
||||
if there is not question section. */
|
||||
#ifndef HAVE_DNSSEC
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned int crc = 0xffffffff;
|
||||
unsigned char *p1, *p = (unsigned char *)(header+1);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return crc; /* bad packet */
|
||||
|
||||
for (p1 = (unsigned char *)name; *p1; p1++)
|
||||
{
|
||||
int i = 8;
|
||||
char c = *p1;
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
|
||||
crc ^= c << 24;
|
||||
while (i--)
|
||||
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||
}
|
||||
|
||||
/* CRC the class and type as well */
|
||||
for (p1 = p; p1 < p+4; p1++)
|
||||
{
|
||||
int i = 8;
|
||||
crc ^= *p1 << 24;
|
||||
while (i--)
|
||||
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||
}
|
||||
|
||||
p += 4;
|
||||
if (!CHECK_LEN(header, p, plen, 0))
|
||||
return crc; /* bad packet */
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
{
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
@@ -843,17 +794,31 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if ((flags & F_IPV4) &&
|
||||
private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
|
||||
if ((flags & F_IPV6) &&
|
||||
IN6_IS_ADDR_V4MAPPED(&addr.addr6))
|
||||
|
||||
/* Block IPv4-mapped IPv6 addresses in private IPv4 address space */
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
struct in_addr v4;
|
||||
v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
|
||||
if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr.addr6))
|
||||
{
|
||||
struct in_addr v4;
|
||||
v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
|
||||
if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for link-local (LL) and site-local (ULA) IPv6 addresses */
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&addr.addr6) ||
|
||||
IN6_IS_ADDR_SITELOCAL(&addr.addr6))
|
||||
return 1;
|
||||
|
||||
/* Check for the IPv6 loopback address (::1) when
|
||||
option rebind-localhost-ok is NOT set */
|
||||
if (!option_bool(OPT_LOCAL_REBIND) &&
|
||||
IN6_IS_ADDR_LOOPBACK(&addr.addr6))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
{
|
||||
@@ -1394,6 +1359,8 @@ 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);
|
||||
}
|
||||
|
||||
+72
-27
@@ -30,7 +30,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
||||
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
|
||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||
int opt, char *string, int null_term);
|
||||
int opt, const char *string, int null_term);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int offset, int size);
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
@@ -54,17 +54,19 @@ static void do_options(struct dhcp_context *context,
|
||||
int vendor_class_len,
|
||||
time_t now,
|
||||
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 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);
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
|
||||
static int prune_vendor_opts(struct dhcp_netid *netid);
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
||||
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
||||
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
|
||||
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
|
||||
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
|
||||
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int loopback,
|
||||
@@ -76,6 +78,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
struct dhcp_mac *mac;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
|
||||
const char *pxevendor = NULL;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
unsigned char *end = (unsigned char *)(mess + 1);
|
||||
unsigned char *real_end = (unsigned char *)(mess + 1);
|
||||
@@ -413,7 +416,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
if ((o2 + elen + 1 <= (unsigned)option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
@@ -647,7 +650,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,9 +838,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
clid = NULL;
|
||||
|
||||
/* Check if client is PXE client. */
|
||||
if (daemon->enable_pxe &&
|
||||
(opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
|
||||
strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
|
||||
if (daemon->enable_pxe &&
|
||||
is_pxe_client(mess, sz, &pxevendor))
|
||||
{
|
||||
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
|
||||
{
|
||||
@@ -899,7 +901,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
pxe_misc(mess, end, uuid, pxevendor);
|
||||
|
||||
prune_vendor_opts(tagif_netid);
|
||||
opt71.val = save71;
|
||||
@@ -979,7 +981,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
pxe_misc(mess, end, uuid, pxevendor);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
if ((pxe && !workaround) || !redirect4011)
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
@@ -1150,7 +1152,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
|
||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
@@ -1499,7 +1501,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (rapid_commit)
|
||||
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
|
||||
}
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1566,7 +1568,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
|
||||
|
||||
*is_inform = 1; /* handle reply differently */
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1948,7 +1950,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,
|
||||
char *string, int null_term)
|
||||
const char *string, int null_term)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t len = strlen(string);
|
||||
@@ -2026,15 +2028,32 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
|
||||
dopt->flags &= ~DHOPT_VENDOR_MATCH;
|
||||
if (opt && (dopt->flags & DHOPT_VENDOR))
|
||||
{
|
||||
int i, len = 0;
|
||||
if (dopt->u.vendor_class)
|
||||
len = strlen((char *)dopt->u.vendor_class);
|
||||
for (i = 0; i <= (option_len(opt) - len); i++)
|
||||
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
|
||||
{
|
||||
dopt->flags |= DHOPT_VENDOR_MATCH;
|
||||
break;
|
||||
}
|
||||
const struct dhcp_pxe_vendor *pv;
|
||||
struct dhcp_pxe_vendor dummy_vendor = {
|
||||
.data = (char *)dopt->u.vendor_class,
|
||||
.next = NULL,
|
||||
};
|
||||
if (dopt->flags & DHOPT_VENDOR_PXE)
|
||||
pv = daemon->dhcp_pxe_vendors;
|
||||
else
|
||||
pv = &dummy_vendor;
|
||||
for (; pv; pv = pv->next)
|
||||
{
|
||||
int i, len = 0, matched = 0;
|
||||
if (pv->data)
|
||||
len = strlen(pv->data);
|
||||
for (i = 0; i <= (option_len(opt) - len); i++)
|
||||
if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
|
||||
{
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
if (matched)
|
||||
{
|
||||
dopt->flags |= DHOPT_VENDOR_MATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2087,11 +2106,13 @@ static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
|
||||
if (!pxevendor)
|
||||
pxevendor="PXEClient";
|
||||
option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
|
||||
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
|
||||
memcpy(p, uuid, 17);
|
||||
}
|
||||
@@ -2308,6 +2329,29 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid)
|
||||
return boot;
|
||||
}
|
||||
|
||||
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
|
||||
{
|
||||
const unsigned char *opt = NULL;
|
||||
ssize_t conf_len = 0;
|
||||
const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
|
||||
opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
|
||||
if (!opt)
|
||||
return 0;
|
||||
for (; conf; conf = conf->next)
|
||||
{
|
||||
conf_len = strlen(conf->data);
|
||||
if (option_len(opt) < conf_len)
|
||||
continue;
|
||||
if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
|
||||
{
|
||||
if (pxe_vendor)
|
||||
*pxe_vendor = conf->data;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *end,
|
||||
@@ -2322,7 +2366,8 @@ static void do_options(struct dhcp_context *context,
|
||||
int vendor_class_len,
|
||||
time_t now,
|
||||
unsigned int lease_time,
|
||||
unsigned short fuzz)
|
||||
unsigned short fuzz,
|
||||
const char *pxevendor)
|
||||
{
|
||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||
struct dhcp_boot *boot;
|
||||
@@ -2696,7 +2741,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (context && pxe_arch != -1)
|
||||
{
|
||||
pxe_misc(mess, end, uuid);
|
||||
pxe_misc(mess, end, uuid, pxevendor);
|
||||
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
|
||||
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
||||
}
|
||||
|
||||
+65
-46
@@ -49,8 +49,8 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
|
||||
static void mark_context_used(struct state *state, struct in6_addr *addr);
|
||||
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
|
||||
static int check_address(struct state *state, struct in6_addr *addr);
|
||||
static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state);
|
||||
static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
|
||||
static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now);
|
||||
static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
|
||||
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
|
||||
unsigned int *min_time, struct in6_addr *addr, time_t now);
|
||||
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
|
||||
@@ -679,7 +679,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
/* If the client asks for an address on the same network as a configured address,
|
||||
offer the configured address instead, to make moving to newly-configured
|
||||
addresses automatic. */
|
||||
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state))
|
||||
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state, now))
|
||||
{
|
||||
req_addr = addr;
|
||||
mark_config_used(c, &addr);
|
||||
@@ -703,7 +703,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
for (c = state->context; c; c = c->current)
|
||||
if (!(c->flags & CONTEXT_CONF_USED) &&
|
||||
match_netid(c->filter, solicit_tags, plain_range) &&
|
||||
config_valid(config, c, &addr, state))
|
||||
config_valid(config, c, &addr, state, now))
|
||||
{
|
||||
mark_config_used(state->context, &addr);
|
||||
if (have_config(config, CONFIG_TIME))
|
||||
@@ -847,7 +847,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
|
||||
config_ok = config_implies(config, c, &req_addr);
|
||||
config_ok = (config_implies(config, c, &req_addr) != NULL);
|
||||
|
||||
if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
|
||||
{
|
||||
@@ -1186,18 +1186,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
struct in6_addr addr;
|
||||
|
||||
struct addrlist *addr_list;
|
||||
|
||||
/* align */
|
||||
memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
|
||||
if ((addr_list = config_implies(config, state->context, &addr)))
|
||||
{
|
||||
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
|
||||
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
|
||||
daemon->addrbuff, daemon->dhcp_buff3);
|
||||
config->flags |= CONFIG_DECLINED;
|
||||
config->decline_time = now;
|
||||
addr_list->flags |= ADDRLIST_DECLINED;
|
||||
addr_list->decline_time = now;
|
||||
}
|
||||
else
|
||||
/* make sure this host gets a different address next time. */
|
||||
@@ -1310,23 +1311,39 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
|
||||
|
||||
for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
|
||||
{
|
||||
struct in6_addr *p = NULL;
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
||||
{
|
||||
if (!add_local_addrs(state->context))
|
||||
put_opt6(state->fallback, IN6ADDRSZ);
|
||||
p = state->fallback;
|
||||
}
|
||||
else if (IN6_IS_ADDR_ULA_ZERO(a))
|
||||
{
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
|
||||
put_opt6(state->ula_addr, IN6ADDRSZ);
|
||||
p = state->ula_addr;
|
||||
}
|
||||
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
|
||||
{
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
|
||||
put_opt6(state->ll_addr, IN6ADDRSZ);
|
||||
p = state->ll_addr;
|
||||
}
|
||||
else
|
||||
put_opt6(a, IN6ADDRSZ);
|
||||
p = a;
|
||||
|
||||
if (!p)
|
||||
continue;
|
||||
else if (opt_cfg->opt == OPTION6_NTP_SERVER)
|
||||
{
|
||||
if (IN6_IS_ADDR_MULTICAST(p))
|
||||
o1 = new_opt6(NTP_SUBOPTION_MC_ADDR);
|
||||
else
|
||||
o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR);
|
||||
put_opt6(p, IN6ADDRSZ);
|
||||
end_opt6(o1);
|
||||
}
|
||||
else
|
||||
put_opt6(p, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
end_opt6(o);
|
||||
@@ -1669,14 +1686,14 @@ static int check_address(struct state *state, struct in6_addr *addr)
|
||||
|
||||
|
||||
/* return true of *addr could have been generated from config. */
|
||||
static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
|
||||
static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
int prefix;
|
||||
struct in6_addr wild_addr;
|
||||
struct addrlist *addr_list;
|
||||
|
||||
if (!config || !(config->flags & CONFIG_ADDR6))
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
||||
{
|
||||
@@ -1692,13 +1709,13 @@ static int config_implies(struct dhcp_config *config, struct dhcp_context *conte
|
||||
continue;
|
||||
|
||||
if (is_same_net6(&wild_addr, addr, prefix))
|
||||
return 1;
|
||||
return addr_list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state)
|
||||
static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now)
|
||||
{
|
||||
u64 addrpart, i, addresses;
|
||||
struct addrlist *addr_list;
|
||||
@@ -1707,34 +1724,36 @@ static int config_valid(struct dhcp_config *config, struct dhcp_context *context
|
||||
return 0;
|
||||
|
||||
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
||||
{
|
||||
addrpart = addr6part(&addr_list->addr.addr6);
|
||||
addresses = 1;
|
||||
|
||||
if (addr_list->flags & ADDRLIST_PREFIX)
|
||||
addresses = 1<<(128-addr_list->prefixlen);
|
||||
|
||||
if ((addr_list->flags & ADDRLIST_WILDCARD))
|
||||
{
|
||||
if (context->prefix != 64)
|
||||
continue;
|
||||
|
||||
*addr = context->start6;
|
||||
}
|
||||
else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
|
||||
*addr = addr_list->addr.addr6;
|
||||
else
|
||||
continue;
|
||||
|
||||
for (i = 0 ; i < addresses; i++)
|
||||
{
|
||||
setaddr6part(addr, addrpart+i);
|
||||
|
||||
if (check_address(state, addr))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(addr_list->flags & ADDRLIST_DECLINED) ||
|
||||
difftime(now, addr_list->decline_time) >= (float)DECLINE_BACKOFF)
|
||||
{
|
||||
addrpart = addr6part(&addr_list->addr.addr6);
|
||||
addresses = 1;
|
||||
|
||||
if (addr_list->flags & ADDRLIST_PREFIX)
|
||||
addresses = (u64)1<<(128-addr_list->prefixlen);
|
||||
|
||||
if ((addr_list->flags & ADDRLIST_WILDCARD))
|
||||
{
|
||||
if (context->prefix != 64)
|
||||
continue;
|
||||
|
||||
*addr = context->start6;
|
||||
}
|
||||
else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
|
||||
*addr = addr_list->addr.addr6;
|
||||
else
|
||||
continue;
|
||||
|
||||
for (i = 0 ; i < addresses; i++)
|
||||
{
|
||||
setaddr6part(addr, addrpart+i);
|
||||
|
||||
if (check_address(state, addr))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+19
-18
@@ -61,8 +61,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
union all_addr addra;
|
||||
int family = listen->addr.sa.sa_family;
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
|
||||
int check_dest = !option_bool(OPT_NOWILD) || family == AF_INET6;
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
@@ -121,10 +122,10 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
addr.sa.sa_family = listen->family;
|
||||
addr.sa.sa_family = family;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
@@ -138,7 +139,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
@@ -154,7 +155,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
@@ -171,7 +172,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
#endif
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
@@ -194,7 +195,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
addra.addr4 = addr.in.sin_addr;
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
addra.addr6 = addr.in6.sin6_addr;
|
||||
|
||||
if (daemon->tftp_interfaces)
|
||||
@@ -210,12 +211,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
else
|
||||
{
|
||||
/* Do the same as DHCP */
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
if (!iface_check(family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
|
||||
!label_exception(if_index, listen->family, &addra))
|
||||
if (!loopback_exception(listen->tftpfd, family, &addra, name) &&
|
||||
!label_exception(if_index, family, &addra))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +282,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
prefix = pref->prefix;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -304,7 +305,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
if (option_bool(OPT_SINGLE_PORT))
|
||||
transfer->sockfd = listen->tftpfd;
|
||||
else if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
|
||||
else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
free(transfer);
|
||||
return;
|
||||
@@ -322,7 +323,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&peer, daemon->addrbuff);
|
||||
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (!option_bool(OPT_SINGLE_PORT))
|
||||
@@ -337,7 +338,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
else
|
||||
addr.in6.sin6_port = htons(port);
|
||||
@@ -375,7 +376,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
|
||||
{
|
||||
/* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
|
||||
int overhead = (listen->family == AF_INET) ? 32 : 52;
|
||||
int overhead = (family == AF_INET) ? 32 : 52;
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
transfer->blocksize = 1;
|
||||
@@ -611,7 +612,7 @@ void check_tftp_listeners(time_t now)
|
||||
{
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
if (len == transfer->blocksize + 4)
|
||||
if ((unsigned)len == transfer->blocksize + 4)
|
||||
endcon = 1;
|
||||
len = 0;
|
||||
}
|
||||
@@ -624,7 +625,7 @@ void check_tftp_listeners(time_t now)
|
||||
{
|
||||
strcpy(daemon->namebuff, transfer->file->filename);
|
||||
sanitise(daemon->namebuff);
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
@@ -667,7 +668,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
char *end = daemon->packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
|
||||
/* Sanitise error message */
|
||||
if (!err)
|
||||
|
||||
+3
-1
@@ -38,7 +38,7 @@ static struct ubus_object_type ubus_object_type =
|
||||
UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
|
||||
|
||||
static struct ubus_object ubus_object = {
|
||||
.name = "dnsmasq",
|
||||
.name = NULL,
|
||||
.type = &ubus_object_type,
|
||||
.methods = ubus_object_methods,
|
||||
.n_methods = ARRAY_SIZE(ubus_object_methods),
|
||||
@@ -94,6 +94,7 @@ void ubus_init()
|
||||
return;
|
||||
}
|
||||
|
||||
ubus_object.name = daemon->ubus_name;
|
||||
ret = ubus_add_object(ubus, &ubus_object);
|
||||
if (ret)
|
||||
{
|
||||
@@ -102,6 +103,7 @@ void ubus_init()
|
||||
my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));
|
||||
error_logged = 1;
|
||||
}
|
||||
ubus_destroy(ubus);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+24
-1
@@ -30,6 +30,10 @@
|
||||
#include <idna.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
static u32 seed[32];
|
||||
@@ -731,7 +735,7 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
||||
fd == spare1 || fd == spare2 || fd == spare3)
|
||||
continue;
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
@@ -782,3 +786,22 @@ int wildcard_matchn(const char* wildcard, const char* match, int num)
|
||||
|
||||
return (!num) || (*wildcard == *match);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
int kernel_version(void)
|
||||
{
|
||||
struct utsname utsname;
|
||||
int version;
|
||||
char *split;
|
||||
|
||||
if (uname(&utsname) < 0)
|
||||
die(_("failed to find kernel version: %s"), NULL, EC_MISC);
|
||||
|
||||
split = strtok(utsname.release, ".");
|
||||
version = (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
return version * 256 + (split ? atoi(split) : 0);
|
||||
}
|
||||
#endif
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
# The root DNSSEC trust anchor, valid as at 10/02/2017
|
||||
# The root DNSSEC trust anchor, valid as at 11/01/2019
|
||||
|
||||
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
|
||||
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
|
||||
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user