Compare commits
114 Commits
v2.69test9
...
v2.72
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25e27235dd | ||
|
|
bf2db4b084 | ||
|
|
5782649ad9 | ||
|
|
288df49c96 | ||
|
|
10cfc0ddb3 | ||
|
|
15b1b7e9c3 | ||
|
|
00c0f69aa5 | ||
|
|
51943369e3 | ||
|
|
2d75f2e4a5 | ||
|
|
976afc93e4 | ||
|
|
7f68f82146 | ||
|
|
85900a246c | ||
|
|
b4f971a081 | ||
|
|
3e1551a1de | ||
|
|
af292dae6d | ||
|
|
933878f2c8 | ||
|
|
d54409dcd3 | ||
|
|
5bf50af2d0 | ||
|
|
c43b8a6326 | ||
|
|
b06900d1a3 | ||
|
|
f2f02fc3fb | ||
|
|
aaeea9f6ed | ||
|
|
2bb6f7735f | ||
|
|
40766e55e8 | ||
|
|
b5ea1cc255 | ||
|
|
6d8e8ac0fa | ||
|
|
24b167ada8 | ||
|
|
993f8cbb1b | ||
|
|
47a9516980 | ||
|
|
dc8a1b1bcf | ||
|
|
cdb755c5f1 | ||
|
|
063efb330a | ||
|
|
70772c9091 | ||
|
|
10d8540f62 | ||
|
|
006c162382 | ||
|
|
6799a46605 | ||
|
|
c4638f9e66 | ||
|
|
4b34f5d22f | ||
|
|
a0358e5ddb | ||
|
|
a03f8d4c37 | ||
|
|
c4a0937683 | ||
|
|
2f4c4b6076 | ||
|
|
a008a843cf | ||
|
|
d92c53e700 | ||
|
|
a754e1d7b2 | ||
|
|
8e9ffba66e | ||
|
|
15a97ad6fb | ||
|
|
91f4a5e4b5 | ||
|
|
0fa7e62947 | ||
|
|
62f992f06c | ||
|
|
a23949d44d | ||
|
|
b692f23466 | ||
|
|
8aa999ef69 | ||
|
|
20b215f293 | ||
|
|
e6096e643a | ||
|
|
8938ae05ac | ||
|
|
9d1b22aac2 | ||
|
|
1fc02680af | ||
|
|
4872aa747b | ||
|
|
7ea3d3fdca | ||
|
|
50f86ce8e4 | ||
|
|
7e22cf28f8 | ||
|
|
3b1b3e9d50 | ||
|
|
ab72091de2 | ||
|
|
66f57867d8 | ||
|
|
6375838445 | ||
|
|
82a14af5e7 | ||
|
|
97dce08ed7 | ||
|
|
198d940af6 | ||
|
|
1d7e0a36e3 | ||
|
|
10068600f8 | ||
|
|
b7639d5815 | ||
|
|
49752b90d5 | ||
|
|
e98bd52e25 | ||
|
|
8a8bbad0cf | ||
|
|
fec216df32 | ||
|
|
4e1fe44428 | ||
|
|
51967f9807 | ||
|
|
b37f8b99ae | ||
|
|
fc2833f172 | ||
|
|
490f90758d | ||
|
|
56618c31f6 | ||
|
|
604f7598c2 | ||
|
|
2a7a2b84ec | ||
|
|
3e21a1a6fa | ||
|
|
2b29191e7c | ||
|
|
03431d6373 | ||
|
|
cc1a29e250 | ||
|
|
e62e9b6187 | ||
|
|
19c51cfa49 | ||
|
|
d5082158ee | ||
|
|
3f7483e816 | ||
|
|
0c8584eabc | ||
|
|
f00690f93e | ||
|
|
89b12ed35b | ||
|
|
1a9a3489ec | ||
|
|
c8a80487cd | ||
|
|
4ea8e80dd9 | ||
|
|
c07d30dcb1 | ||
|
|
d588ab54d4 | ||
|
|
f8b422a7b6 | ||
|
|
29fe922b14 | ||
|
|
8707019237 | ||
|
|
d1fbb77e0f | ||
|
|
1fbe4d2f5f | ||
|
|
0575610fa1 | ||
|
|
e3f1455850 | ||
|
|
bd9b3cf55b | ||
|
|
14db4212ab | ||
|
|
00a5b5d477 | ||
|
|
b8eac19177 | ||
|
|
b47b04c846 | ||
|
|
613ad15d02 | ||
|
|
24187530fb |
129
CHANGELOG
129
CHANGELOG
@@ -1,3 +1,74 @@
|
||||
version 2.72
|
||||
Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
|
||||
|
||||
Add support for "ipsets" in *BSD, using pf. Thanks to
|
||||
Sven Falempim for the patch.
|
||||
|
||||
Fix race condition which could lock up dnsmasq when an
|
||||
interface goes down and up rapidly. Thanks to Conrad
|
||||
Kostecki for helping to chase this down.
|
||||
|
||||
Add DBus methods SetFilterWin2KOption and SetBogusPrivOption
|
||||
Thanks to the Smoothwall project for the patch.
|
||||
|
||||
Fix failure to build against Nettle-3.0. Thanks to Steven
|
||||
Barth for spotting this and finding the fix.
|
||||
|
||||
When assigning existing DHCP leases to intefaces by comparing
|
||||
networks, handle the case that two or more interfaces have the
|
||||
same network part, but different prefix lengths (favour the
|
||||
longer prefix length.) Thanks to Lung-Pin Chang for the
|
||||
patch.
|
||||
|
||||
Add a mode which detects and removes DNS forwarding loops, ie
|
||||
a query sent to an upstream server returns as a new query to
|
||||
dnsmasq, and would therefore be forwarded again, resulting in
|
||||
a query which loops many times before being dropped. Upstream
|
||||
servers which loop back are disabled and this event is logged.
|
||||
Thanks to Smoothwall for their sponsorship of this feature.
|
||||
|
||||
Extend --conf-dir to allow filtering of files. So
|
||||
--conf-dir=/etc/dnsmasq.d,\*.conf
|
||||
will load all the files in /etc/dnsmasq.d which end in .conf
|
||||
|
||||
Fix bug when resulted in NXDOMAIN answers instead of NODATA in
|
||||
some circumstances.
|
||||
|
||||
Fix bug which caused dnsmasq to become unresponsive if it
|
||||
failed to send packets due to a network interface disappearing.
|
||||
Thanks to Niels Peen for spotting this.
|
||||
|
||||
Fix problem with --local-service option on big-endian platforms
|
||||
Thanks to Richard Genoud for the patch.
|
||||
|
||||
|
||||
version 2.71
|
||||
Subtle change to error handling to help DNSSEC validation
|
||||
when servers fail to provide NODATA answers for
|
||||
non-existent DS records.
|
||||
|
||||
Tweak code which removes DNSSEC records from answers when
|
||||
not required. Fixes broken answers when additional section
|
||||
has real records in it. Thanks to Marco Davids for the bug
|
||||
report.
|
||||
|
||||
Fix DNSSEC validation of ANY queries. Thanks to Marco Davids
|
||||
for spotting that too.
|
||||
|
||||
Fix total DNS failure and 100% CPU use if cachesize set to zero,
|
||||
regression introduced in 2.69. Thanks to James Hunt and
|
||||
the Ubuntu crowd for assistance in fixing this.
|
||||
|
||||
|
||||
version 2.70
|
||||
Fix crash, introduced in 2.69, on TCP request when dnsmasq
|
||||
compiled with DNSSEC support, but running without DNSSEC
|
||||
enabled. Thanks to Manish Sing for spotting that one.
|
||||
|
||||
Fix regression which broke ipset functionality. Thanks to
|
||||
Wang Jian for the bug report.
|
||||
|
||||
|
||||
version 2.69
|
||||
Implement dynamic interface discovery on *BSD. This allows
|
||||
the contructor: syntax to be used in dhcp-range for DHCPv6
|
||||
@@ -28,9 +99,9 @@ version 2.69
|
||||
|
||||
make dnsmasq COPTS='-DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC'
|
||||
|
||||
which bloats the dnsmasq binary to over a megabyte, but
|
||||
saves the size of the shared libraries which are five
|
||||
times that size.
|
||||
which bloats the dnsmasq binary, but saves the size of
|
||||
the shared libraries which are much bigger.
|
||||
|
||||
To enable, DNSSEC, you will need a set of
|
||||
trust-anchors. Now that the TLDs are signed, this can be
|
||||
the keys for the root zone, and for convenience they are
|
||||
@@ -56,6 +127,36 @@ version 2.69
|
||||
downstream validators. Setting --log-queries will show
|
||||
DNSSEC in action.
|
||||
|
||||
If a domain is returned from an upstream nameserver without
|
||||
DNSSEC signature, dnsmasq by default trusts this. This
|
||||
means that for unsigned zone (still the majority) there
|
||||
is effectively no cost for having DNSSEC enabled. Of course
|
||||
this allows an attacker to replace a signed record with a
|
||||
false unsigned record. This is addressed by the
|
||||
--dnssec-check-unsigned flag, which instructs dnsmasq
|
||||
to prove that an unsigned record is legitimate, by finding
|
||||
a secure proof that the zone containing the record is not
|
||||
signed. Doing this has costs (typically one or two extra
|
||||
upstream queries). It also has a nasty failure mode if
|
||||
dnsmasq's upstream nameservers are not DNSSEC capable.
|
||||
Without --dnssec-check-unsigned using such an upstream
|
||||
server will simply result in not queries being validated;
|
||||
with --dnssec-check-unsigned enabled and a
|
||||
DNSSEC-ignorant upstream server, _all_ queries will fail.
|
||||
|
||||
Note that DNSSEC requires that the local time is valid and
|
||||
accurate, if not then DNSSEC validation will fail. NTP
|
||||
should be running. This presents a problem for routers
|
||||
without a battery-backed clock. To set the time needs NTP
|
||||
to do DNS lookups, but lookups will fail until NTP has run.
|
||||
To address this, there's a flag, --dnssec-no-timecheck
|
||||
which disables the time checks (only) in DNSSEC. When dnsmasq
|
||||
is started and the clock is not synced, this flag should
|
||||
be used. As soon as the clock is synced, SIGHUP dnsmasq.
|
||||
The SIGHUP clears the cache of partially-validated data and
|
||||
resets the no-timecheck flag, so that all DNSSEC checks
|
||||
henceforward will be complete.
|
||||
|
||||
The development of DNSSEC in dnsmasq was started by
|
||||
Giovanni Bajo, to whom huge thanks are owed. It has been
|
||||
supported by Comcast, whose techfund grant has allowed for
|
||||
@@ -67,7 +168,27 @@ version 2.69
|
||||
Add --servers-file. Allows dynamic update of upstream servers
|
||||
full access to configuration.
|
||||
|
||||
|
||||
Add --local-service. Accept DNS queries only from hosts
|
||||
whose address is on a local subnet, ie a subnet for which
|
||||
an interface exists on the server. This option
|
||||
only has effect if there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended
|
||||
to be set as a default on installation, to allow
|
||||
unconfigured installations to be useful but also safe from
|
||||
being used for DNS amplification attacks.
|
||||
|
||||
Fix crashes in cache_get_cname_target() when dangling CNAMEs
|
||||
encountered. Thanks to Andy and the rt-n56u project for
|
||||
find this and helping to chase it down.
|
||||
|
||||
Fix wrong RCODE in authoritative DNS replies to PTR queries. The
|
||||
correct answer was included, but the RCODE was set to NXDOMAIN.
|
||||
Thanks to Craig McQueen for spotting this.
|
||||
|
||||
Make statistics available as DNS queries in the .bind TLD as
|
||||
well as logging them.
|
||||
|
||||
|
||||
version 2.68
|
||||
Use random addresses for DHCPv6 temporary address
|
||||
allocations, instead of algorithmically determined stable
|
||||
|
||||
4
Makefile
4
Makefile
@@ -61,7 +61,7 @@ lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CON
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
|
||||
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
|
||||
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --copy -lgmp`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
@@ -69,7 +69,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.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
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
|
||||
@@ -9,7 +9,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -11,11 +11,19 @@ in=`cat`
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $search >/dev/null 2>&1; then
|
||||
|
||||
# Nasty, nasty, in --copy, arg 2 is another config to search for, use with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
pkg="$*"
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
pkg=""
|
||||
else
|
||||
pkg="$*"
|
||||
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 $*`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
pkg=`$pkg $op $*`
|
||||
fi
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=A lightweight DHCP and caching DNS server
|
||||
Description=dnsmasq - A lightweight DHCP and caching DNS server
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
|
||||
@@ -40,6 +40,14 @@ ClearCache
|
||||
Returns nothing. Clears the domain name cache and re-reads
|
||||
/etc/hosts. The same as sending dnsmasq a HUP signal.
|
||||
|
||||
SetFilterWin2KOption
|
||||
--------------------
|
||||
Takes boolean, sets or resets the --filterwin2k option.
|
||||
|
||||
SetBogusPrivOption
|
||||
------------------
|
||||
Takes boolean, sets or resets the --bogus-priv option.
|
||||
|
||||
SetServers
|
||||
----------
|
||||
Returns nothing. Takes a set of arguments representing the new
|
||||
@@ -152,6 +160,15 @@ for SetServersEx is represented as
|
||||
"/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
|
||||
]
|
||||
|
||||
GetLoopServers
|
||||
--------------
|
||||
|
||||
(Only available if dnsmasq compiled with HAVE_LOOP)
|
||||
|
||||
Return an array of strings, each string is the IP address of an upstream
|
||||
server which has been found to loop queries back to this dnsmasq instance, and
|
||||
it therefore not being used.
|
||||
|
||||
|
||||
|
||||
2. SIGNALS
|
||||
|
||||
51
debian/changelog
vendored
51
debian/changelog
vendored
@@ -1,6 +1,57 @@
|
||||
dnsmasq (2.72-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* If dns-root-data package is installed, use it to set the DNSSEC
|
||||
trust anchor(s). Recommend dns-root-data. (closes: #760460)
|
||||
* Handle AD bit correctly in replies from cache. (closes: #761654)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 20 May 2014 21:01:11 +0000
|
||||
|
||||
dnsmasq (2.71-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Fix 100% CPU-usage bug when dnsmasq started with cachesize
|
||||
set to zero. (LP: #1314697)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 May 2014 20:17:10 +0000
|
||||
|
||||
dnsmasq (2.70-3) unstable; urgency=medium
|
||||
|
||||
* Write a pid-file, even when being started using systemd, since
|
||||
other components may wish to signal dnsmasq.
|
||||
* Enable dnsmasq systemd unit on install. Otherwise dnsmasq does not run on
|
||||
fresh installations (without administrator handholding) and even worse it
|
||||
is disabled on systems switching from sysv to systemd. Modify
|
||||
postinst/postrm exactly as dh_systemd would, add dependency on
|
||||
init-system-helpers. Closes: #724602
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 11 May 2014 17:45:21 +0000
|
||||
|
||||
dnsmasq (2.70-2) unstable; urgency=low
|
||||
|
||||
* Ensure daemon not stared if dnsmasq package has been removed,
|
||||
even if dnsmasq-base is still installed. (closes: #746941)
|
||||
* Tidy cruft in initscript. (closes: #746940)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 04 May 2014 21:34:11 +0000
|
||||
|
||||
dnsmasq (2.70-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 23 Apr 2014 15:14:42 +0000
|
||||
|
||||
dnsmasq (2.69-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Set --local-service. (closes: #732610)
|
||||
This tells dnsmasq to ignore DNS requests that don't come
|
||||
from a local network. It's automatically ignored if
|
||||
--interface --except-interface, --listen-address or
|
||||
--auth-server exist in the configuration, so for most
|
||||
installations, it will have no effect, but for
|
||||
otherwise-unconfigured installations, it stops dnsmasq
|
||||
from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
|
||||
|
||||
|
||||
9
debian/control
vendored
9
debian/control
vendored
@@ -2,13 +2,15 @@ Source: dnsmasq
|
||||
Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev, nettle-dev (>=2.4-3)
|
||||
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3)
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Standards-Version: 3.9.3
|
||||
Standards-Version: 3.9.5
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, dnsmasq-base(>= ${binary:Version})
|
||||
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
|
||||
init-system-helpers (>= 1.18~)
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
@@ -26,6 +28,7 @@ Architecture: any
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~)
|
||||
Recommends: dns-root-data
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
|
||||
2
debian/default
vendored
2
debian/default
vendored
@@ -27,7 +27,7 @@ CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||
# If the resolvconf package is installed, dnsmasq will use its output
|
||||
# rather than the contents of /etc/resolv.conf to find upstream
|
||||
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||
# Not that including a "resolv-file=<filename>" line in
|
||||
# Note that including a "resolv-file=<filename>" line in
|
||||
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||
# installed: the line below must be uncommented.
|
||||
#IGNORE_RESOLVCONF=yes
|
||||
|
||||
37
debian/init
vendored
37
debian/init
vendored
@@ -29,6 +29,12 @@ if [ -r /etc/default/locale ]; then
|
||||
export LANG
|
||||
fi
|
||||
|
||||
# /etc/dnsmasq.d/README is a non-conffile installed by the dnsmasq package.
|
||||
# Should the dnsmasq package be removed, the following test ensures that
|
||||
# the daemon is no longer started, even if the dnsmasq-base package is
|
||||
# still in place.
|
||||
test -e /etc/dnsmasq.d/README || exit 0
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
# Provide skeleton LSB log functions for backports which don't have LSB functions.
|
||||
@@ -90,6 +96,24 @@ if [ ! "$DNSMASQ_USER" ]; then
|
||||
DNSMASQ_USER="dnsmasq"
|
||||
fi
|
||||
|
||||
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
|
||||
# It's automatically ignored if --interface --except-interface, --listen-address
|
||||
# or --auth-server exist in the configuration, so for most installations, it will
|
||||
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
|
||||
# from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
|
||||
|
||||
# If the dns-root-data package is installed, then the trust anchors will be
|
||||
# available in $ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
|
||||
# --trust-anchor options.
|
||||
|
||||
ROOT_DS="/usr/share/dns/root.ds"
|
||||
|
||||
if [ -f $ROOT_DS ]; then
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/". IN DS "/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
|
||||
fi
|
||||
|
||||
start()
|
||||
{
|
||||
# Return
|
||||
@@ -144,9 +168,6 @@ stop()
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
return "$RETVAL"
|
||||
}
|
||||
|
||||
stop_resolvconf()
|
||||
@@ -266,9 +287,15 @@ case "$1" in
|
||||
stop_resolvconf
|
||||
;;
|
||||
systemd-exec)
|
||||
# --pid-file without argument disables writing a PIDfile, we don't need one with sytemd.
|
||||
# /var/run may be volatile, so we need to ensure that
|
||||
# /var/run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
|
||||
fi
|
||||
# Enable DBus by default because we use DBus activation with systemd.
|
||||
exec $DAEMON --keep-in-foreground --pid-file --enable-dbus \
|
||||
exec $DAEMON --keep-in-foreground --enable-dbus \
|
||||
-x /var/run/dnsmasq/$NAME.pid \
|
||||
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||
${MAILTARGET:+ -t $MAILTARGET} \
|
||||
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||
|
||||
16
debian/postinst
vendored
16
debian/postinst
vendored
@@ -1,6 +1,22 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Code copied from dh_systemd_enable ----------------------
|
||||
# This will only remove masks created by d-s-h on package removal.
|
||||
deb-systemd-helper unmask dnsmasq.service >/dev/null || true
|
||||
|
||||
# was-enabled defaults to true, so new installations run enable.
|
||||
if deb-systemd-helper --quiet was-enabled dnsmasq.service; then
|
||||
# Enables the unit on first installation, creates new
|
||||
# symlinks on upgrades if the unit file has changed.
|
||||
deb-systemd-helper enable dnsmasq.service >/dev/null || true
|
||||
else
|
||||
# Update the statefile to add new symlinks (if any), which need to be
|
||||
# cleaned up on purge. Also remove old symlinks.
|
||||
deb-systemd-helper update-state dnsmasq.service >/dev/null || true
|
||||
fi
|
||||
# End code copied from dh_systemd_enable ------------------
|
||||
|
||||
if [ -x /etc/init.d/dnsmasq ]; then
|
||||
update-rc.d dnsmasq defaults 15 85 >/dev/null
|
||||
|
||||
|
||||
16
debian/postrm
vendored
16
debian/postrm
vendored
@@ -4,3 +4,19 @@ set -e
|
||||
if [ purge = "$1" ]; then
|
||||
update-rc.d dnsmasq remove >/dev/null
|
||||
fi
|
||||
|
||||
# Code copied from dh_systemd_enable ----------------------
|
||||
if [ "$1" = "remove" ]; then
|
||||
if [ -x "/usr/bin/deb-systemd-helper" ]; then
|
||||
deb-systemd-helper mask dnsmasq.service >/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" = "purge" ]; then
|
||||
if [ -x "/usr/bin/deb-systemd-helper" ]; then
|
||||
deb-systemd-helper purge dnsmasq.service >/dev/null
|
||||
deb-systemd-helper unmask dnsmasq.service >/dev/null
|
||||
fi
|
||||
fi
|
||||
# End code copied from dh_systemd_enable ------------------
|
||||
|
||||
|
||||
16
debian/rules
vendored
16
debian/rules
vendored
@@ -11,18 +11,16 @@
|
||||
|
||||
package=dnsmasq-base
|
||||
|
||||
CFLAGS = $(shell export DEB_BUILD_OPTIONS=$(DEB_BUILD_OPTIONS); dpkg-buildflags --get CFLAGS)
|
||||
CFLAGS += $(shell dpkg-buildflags --get CPPFLAGS)
|
||||
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all" dpkg-buildflags
|
||||
|
||||
CFLAGS = $(shell $(dpkg_buildflags) --get CFLAGS)
|
||||
CFLAGS += $(shell $(dpkg_buildflags) --get CPPFLAGS)
|
||||
CFLAGS += -Wall -W
|
||||
|
||||
LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
|
||||
LDFLAGS = $(shell $(dpkg_buildflags) --get LDFLAGS)
|
||||
|
||||
DEB_COPTS = $(COPTS)
|
||||
|
||||
# The nettle library in Debian is too old to include
|
||||
# ECC support.
|
||||
DEB_COPTS += -DNO_NETTLE_ECC
|
||||
|
||||
TARGET = install-i18n
|
||||
|
||||
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||
@@ -134,7 +132,9 @@ binary-arch: checkroot
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||
# Need to remove paypal links in Debian Package for policy reasons.
|
||||
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
|
||||
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html
|
||||
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
|
||||
|
||||
7
debian/systemd.service
vendored
7
debian/systemd.service
vendored
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=A lightweight DHCP and caching DNS server
|
||||
Description=dnsmasq - A lightweight DHCP and caching DNS server
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
@@ -13,9 +13,8 @@ ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
# itself, when called with the "systemd-exec" function.
|
||||
#
|
||||
# It also adds the command-line flags
|
||||
# --keep-in-foreground --pid-file --enable-dbus
|
||||
# to disable writing a pid-file (not needed with systemd) and
|
||||
# enable DBus by default because we use DBus activation.
|
||||
# --keep-in-foreground --enable-dbus
|
||||
# to enable DBus by default because we use DBus activation.
|
||||
#
|
||||
ExecStart=/etc/init.d/dnsmasq systemd-exec
|
||||
|
||||
|
||||
@@ -25,6 +25,14 @@
|
||||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||
#dnssec
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
# Note that (amongst other things) this blocks all SRV requests,
|
||||
@@ -632,3 +640,9 @@
|
||||
# Include another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
|
||||
# Include all the files in a directory except those ending in .bak
|
||||
#conf-dir=/etc/dnsmasq.d,.bak
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/*.conf
|
||||
133
doc.html
133
doc.html
@@ -1,8 +1,7 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
|
||||
<link rel="icon"
|
||||
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
<TITLE> Dnsmasq - network services for small networks.</TITLE>
|
||||
<link rel="icon" href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="WHITE">
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
@@ -11,82 +10,48 @@
|
||||
<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
|
||||
<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
|
||||
</table>
|
||||
Dnsmasq provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be
|
||||
lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used
|
||||
for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD, and Mac OS X. Dnsmasq is included in most
|
||||
Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmasq provides full IPv6 support.
|
||||
|
||||
Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
|
||||
server. It is designed to provide DNS and, optionally, DHCP, to a
|
||||
small network. It can serve the names of local machines which are
|
||||
not in the global DNS. The DHCP server integrates with the DNS
|
||||
server and allows machines with DHCP-allocated addresses
|
||||
to appear in the DNS with names configured either in each host or
|
||||
in a central configuration file. Dnsmasq supports static and dynamic
|
||||
DHCP leases and BOOTP/TFTP/PXE for network booting of diskless machines.
|
||||
<P>
|
||||
Dnsmasq is targeted at home networks using NAT and
|
||||
connected to the internet via a modem, cable-modem or ADSL
|
||||
connection but would be a good choice for any smallish network (up to
|
||||
1000 clients is known to work) where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
|
||||
Solaris and Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse, Fedora,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l,
|
||||
CoyoteLinux, Endian Firewall and
|
||||
Clarkconnect. It is also available as FreeBSD, OpenBSD and NetBSD ports and is used in
|
||||
Linksys wireless routers (dd-wrt, openwrt and the stock firmware) and the m0n0wall project.
|
||||
<P>
|
||||
Dnsmasq provides the following features:
|
||||
The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
|
||||
cacheing of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled).
|
||||
<DIR>
|
||||
|
||||
<LI>
|
||||
The DNS configuration of machines behind the firewall is simple and
|
||||
doesn't depend on the details of the ISP's dns servers
|
||||
<LI>
|
||||
Clients which try to do DNS lookups while a modem link to the
|
||||
internet is down will time out immediately.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq will serve names from the /etc/hosts file on the firewall
|
||||
machine: If the names of local machines are there, then they can all
|
||||
be addressed without having to maintain /etc/hosts on each machine.
|
||||
</LI>
|
||||
<LI>
|
||||
The integrated DHCP server supports static and dynamic DHCP leases and
|
||||
multiple networks and IP ranges. It works across BOOTP relays and
|
||||
supports DHCP options including RFC3397 DNS search lists.
|
||||
Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address in the dnsmasq
|
||||
config file.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
||||
mappings (PTR records), reducing the load on upstream servers and
|
||||
improving performance (especially on modem connections).
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to automatically pick up the addresses of
|
||||
its upstream nameservers from ppp or dhcp configuration. It will
|
||||
automatically reload this information if it changes. This facility
|
||||
will be of particular interest to maintainers of Linux firewall
|
||||
distributions since it allows dns configuration to be made automatic.
|
||||
</LI>
|
||||
<LI>
|
||||
On IPv6-enabled boxes, dnsmasq can both talk to upstream servers via IPv6
|
||||
and offer DNS service via IPv6. On dual-stack (IPv4 and IPv6) boxes it talks
|
||||
both protocols and can even act as IPv6-to-IPv4 or IPv4-to-IPv6 forwarder.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to send queries for certain domains to
|
||||
upstream servers handling only those domains. This makes integration
|
||||
with private DNS systems easy.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq supports MX and SRV records and can be configured to return MX records
|
||||
for any or all local machines.
|
||||
</LI>
|
||||
<LI>Local DNS names can be defined by reading /etc/hosts, by importing names from the DHCP subsystem, or by configuration of a wide range of useful record types.</LI>
|
||||
<LI>Upstream servers can be configured in a variety of convenient ways, including dynamic configuration as these change on moving upstream network.
|
||||
<LI>Authoritative DNS mode allows local DNS names may be exported to zone in the global DNS. Dnsmasq acts as authoritative server for this zone, and also provides
|
||||
zone transfer to secondaries for the zone, if required.</LI>
|
||||
<LI>DNSSEC validation may be performed on DNS replies from upstream nameservers, providing security against spoofing and cache poisoning.</LI>
|
||||
<LI>Specified sub-domains can be directed to their own upstream DNS servers, making VPN configuration easy.</LI>
|
||||
<LI>Internationalised domain names are supported.
|
||||
</DIR>
|
||||
<P>
|
||||
The DHCP subsystem supports DHCPv4, DHCPv6, BOOTP and PXE.
|
||||
<DIR>
|
||||
<LI> Both static and dynamic DHCP leases are supported, along with stateless mode in DHCPv6.</LI>
|
||||
<LI> The PXE system is a full PXE server, supporting netboot menus and multiple architecture support. It
|
||||
includes proxy-mode, where the PXE system co-operates with another DHCP server.</LI>
|
||||
<LI> There is a built in read-only TFTP server to support netboot.</LI>
|
||||
<LI> Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address or UID in the dnsmasq
|
||||
configuration file.</LI>
|
||||
</DIR>
|
||||
<P>
|
||||
The Router Advertisement subsystem provides basic autoconfiguration for IPv6 hosts. It can be used stand-alone or in conjunction with DHCPv6.
|
||||
<DIR>
|
||||
<LI> The M and O bits are configurable, to control hosts' use of DHCPv6.</LI>
|
||||
<LI> Router advertisements can include the RDNSS option.</LI>
|
||||
<LI> There is a mode which uses name information from DHCPv4 configuration to provide DNS entries
|
||||
for autoconfigured IPv6 addresses which would otherwise be anonymous.</LI>
|
||||
</DIR>
|
||||
<P>
|
||||
|
||||
For extra compactness, unused features may be omitted at compile time.
|
||||
|
||||
|
||||
<H2>Get code.</H2>
|
||||
|
||||
@@ -102,7 +67,7 @@ the repo, or get a copy using git protocol with the command
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
|
||||
for details.
|
||||
|
||||
<H2>Contact.</H2>
|
||||
@@ -110,7 +75,21 @@ There is a dnsmasq mailing list at <A
|
||||
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
|
||||
first location for queries, bugreports, suggestions etc.
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A
|
||||
You can contact me at <A
|
||||
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||
|
||||
<H2>Donations.</H2>
|
||||
Dnsmasq is mainly written and maintained by Simon Kelley. For most of its life, dnsmasq has been a spare-time project.
|
||||
These days I'm working on it as my main activity.
|
||||
I don't have an employer or anyone who pays me regularly to work on dnsmasq. If you'd like to make
|
||||
a contribution towards my expenses, please use the donation button below.
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="V3X9GVW5GX6DA">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
|
||||
|
||||
</BODY>
|
||||
|
||||
|
||||
@@ -208,6 +208,14 @@ resolve in the global DNS to a 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.
|
||||
.TP
|
||||
.B --local-service
|
||||
Accept DNS queries only from hosts whose address is on a local subnet,
|
||||
ie a subnet for which an interface exists on the server. This option
|
||||
only has effect is there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended to be set as
|
||||
a default on installation, to allow unconfigured installations to be
|
||||
useful but also safe from being used for DNS amplification attacks.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<interface name>
|
||||
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
||||
@@ -326,6 +334,16 @@ it will send queries to just one server. Setting this flag forces
|
||||
dnsmasq to send all queries to all available servers. The reply from
|
||||
the server which answers first will be returned to the original requester.
|
||||
.TP
|
||||
.B --dns-loop-detect
|
||||
Enable code to detect DNS forwarding loops; ie the situation where a query sent to one
|
||||
of the upstream server eventually returns as a new query to the dnsmasq instance. The
|
||||
process works by generating TXT queries of the form <hex>.test and sending them to
|
||||
each upstream server. The hex is a UID which encodes the instance of dnsmasq sending the query
|
||||
and the upstream server to which it was sent. If the query returns to the server which sent it, then
|
||||
the upstream server through which it was sent is disabled and this event is logged. Each time the
|
||||
set of upstream servers changes, the test is re-run on all of them, including ones which
|
||||
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
|
||||
@@ -599,7 +617,15 @@ clients unable to do validation, use of the AD bit set by dnsmasq is useful, pro
|
||||
the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
|
||||
trust anchors provided, see
|
||||
.B --trust-anchor.
|
||||
Because the DNSSEC validation process uses the cache, it is not permitted to reduce the cache size below the default when DNSSEC is enabled.
|
||||
Because the DNSSEC validation process uses the cache, it is not
|
||||
permitted to reduce the cache size below the default when DNSSEC is
|
||||
enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
|
||||
ie capable of returning DNSSEC records with data. If they are not,
|
||||
then dnsmasq will not be able to determine the trusted status of
|
||||
answers. In the default mode, this menas that all replies will be
|
||||
marked as untrusted. If
|
||||
.B --dnssec-check-unsigned
|
||||
is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
|
||||
.TP
|
||||
.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
|
||||
Provide DS records to act a trust anchors for DNSSEC
|
||||
@@ -608,6 +634,27 @@ key(s) of the root zone,
|
||||
but trust anchors for limited domains are also possible. The current
|
||||
root-zone trust anchors may be donwloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
.TP
|
||||
.B --dnssec-check-unsigned
|
||||
As a default, dnsmasq does not check that unsigned DNS replies are
|
||||
legitimate: they are assumed to be valid and passed on (without the
|
||||
"authentic data" bit set, of course). This does not protect against an
|
||||
attacker forging unsigned replies for signed DNS zones, but it is
|
||||
fast. If this flag is set, dnsmasq will check the zones of unsigned
|
||||
replies, to ensure that unsigned replies are allowed in those
|
||||
zones. The cost of this is more upstream queries and slower
|
||||
performance. See also the warning about upstream servers in the
|
||||
section on
|
||||
.B --dnssec
|
||||
.TP
|
||||
.B --dnssec-no-timecheck
|
||||
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
|
||||
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
|
||||
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
|
||||
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
|
||||
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
|
||||
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
|
||||
which have not been throughly checked.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
|
||||
alternative to having dnsmasq validate DNSSEC, but it depends on the security of the network between
|
||||
@@ -638,7 +685,7 @@ Interface-name and address-literal subnet specifications may be used
|
||||
freely in the same --auth-zone declaration.
|
||||
|
||||
The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries. If not
|
||||
ip6.arpa domains which are served for reverse-DNS queries. If not
|
||||
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
|
||||
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
|
||||
unless you are familiar with RFC 2317 and have arranged the
|
||||
@@ -745,7 +792,7 @@ or from /etc/ethers will be served. A static-only subnet with address
|
||||
all zeros may be used as a "catch-all" address to enable replies to all
|
||||
Information-request packets on a subnet which is provided with
|
||||
stateless DHCPv6, ie
|
||||
.B --dhcp=range=::,static
|
||||
.B --dhcp-range=::,static
|
||||
|
||||
For IPv4, the <mode> may be
|
||||
.B proxy
|
||||
@@ -757,7 +804,7 @@ and
|
||||
for details.)
|
||||
|
||||
For IPv6, the mode may be some combination of
|
||||
.B ra-only, slaac, ra-names, ra-stateless.
|
||||
.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter.
|
||||
|
||||
.B ra-only
|
||||
tells dnsmasq to offer Router Advertisement only on this subnet,
|
||||
@@ -792,6 +839,11 @@ can be combined with
|
||||
and
|
||||
.B slaac.
|
||||
|
||||
.B ra-advrouter
|
||||
enables a mode where router address(es) rather than prefix(es) are included in the advertisements.
|
||||
This is described in RFC-3775 section 7.2 and is used in mobile IPv6. In this mode the interval option
|
||||
is also included, as described in RFC-3775 section 7.3.
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
Specify per host parameters for the DHCP server. This allows a machine
|
||||
@@ -1508,6 +1560,7 @@ Treat DHCP request packets arriving at any of the <alias> interfaces
|
||||
as if they had arrived at <interface>. This option is necessary when
|
||||
using "old style" bridging on BSD platforms, since
|
||||
packets arrive at tap interfaces which don't have an IP address.
|
||||
A trailing '*' wildcard can be used in each <alias>.
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
Specifies DNS domains for the DHCP server. Domains may be be given
|
||||
@@ -1672,12 +1725,16 @@ Specify a different configuration file. The conf-file option is also allowed in
|
||||
configuration files, to include multiple configuration files. A
|
||||
filename of "-" causes dnsmasq to read configuration from stdin.
|
||||
.TP
|
||||
.B \-7, --conf-dir=<directory>[,<file-extension>......]
|
||||
.B \-7, --conf-dir=<directory>[,<file-extension>......],
|
||||
Read all the files in the given directory as configuration
|
||||
files. If extension(s) are given, any files which end in those
|
||||
extensions are skipped. Any files whose names end in ~ or start with . or start and end
|
||||
with # are always skipped. This flag may be given on the command
|
||||
line or in a configuration file.
|
||||
with # are always skipped. If the extension starts with * then only files
|
||||
which have that extension are loaded. So
|
||||
.B --conf-dir=/path/to/dir,*.conf
|
||||
loads all files with the suffix .conf in /path/to/dir. This flag may be given on the command
|
||||
line or in a configuration file. If giving it on the command line, be sure to
|
||||
escape * characters.
|
||||
.TP
|
||||
.B --servers-file=<file>
|
||||
A special case of
|
||||
@@ -1725,12 +1782,22 @@ When it receives a SIGUSR1,
|
||||
writes statistics to the system log. It writes the cache size,
|
||||
the number of names which have had to removed from the cache before
|
||||
they expired in order to make room for new names and the total number
|
||||
of names that have been inserted into the cache. For each upstream
|
||||
of names that have been inserted into the cache. The number of cache hits and
|
||||
misses and the number of authoritative queries answered are also given. For each upstream
|
||||
server it gives the number of queries sent, and the number which
|
||||
resulted in an error. In
|
||||
.B --no-daemon
|
||||
mode or when full logging is enabled (-q), a complete dump of the
|
||||
contents of the cache is made.
|
||||
contents of the cache is made.
|
||||
|
||||
The cache statistics are also available in the DNS as answers to
|
||||
queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind,
|
||||
misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the
|
||||
.B dig
|
||||
utility would be
|
||||
|
||||
dig +short chaos txt cachesize.bind
|
||||
|
||||
.PP
|
||||
When it receives SIGUSR2 and it is logging direct to a file (see
|
||||
.B --log-facility
|
||||
@@ -1834,7 +1901,7 @@ which has tags will be used in preference to an untagged
|
||||
.B dhcp-option,
|
||||
provided that _all_ the tags match somewhere in the
|
||||
set collected as described above. The prefix '!' on a tag means 'not'
|
||||
so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
tag purple is not in the set of valid tags. (If using this in a
|
||||
command line rather than a configuration file, be sure to escape !,
|
||||
which is a shell metacharacter)
|
||||
@@ -1986,7 +2053,7 @@ to particular hosts then
|
||||
will do so.
|
||||
|
||||
Dnsmasq acts as an authoritative server for in-addr.arpa and
|
||||
ipv6.arpa domains associated with the subnets given in auth-zone
|
||||
ip6.arpa domains associated with the subnets given in auth-zone
|
||||
declarations, so reverse (address to name) lookups can be simply
|
||||
configured with a suitable NS record, for instance in this example,
|
||||
where we allow 1.2.3.0/24 addresses.
|
||||
|
||||
@@ -706,7 +706,7 @@ l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage D
|
||||
(ce comportement peut-être désactivé par
|
||||
.B constructor-noauth:
|
||||
). Le ou les sous-réseaux sont également utilisé(s) pour définir les domaines
|
||||
in-addr.arpa et ipv6.arpa servant à l'interrogation DNS inverse. Si la longueur
|
||||
in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur
|
||||
de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour
|
||||
IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait-être de 8, 16
|
||||
ou 24, sauf si en cas de mise en place d'une délégation de la zone in-addr.arpa
|
||||
@@ -1659,7 +1659,7 @@ Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias
|
||||
comme si elles arrivaient de l'interface <interface>. Cette option est
|
||||
nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
|
||||
BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
|
||||
pas d'adresse IP.
|
||||
pas d'adresse IP. Chaque <alias> peut finir avec un simple '*' joker.
|
||||
.TP
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
|
||||
Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
|
||||
@@ -2186,7 +2186,7 @@ spécifiques, vous pouvez le faire via :
|
||||
.fi
|
||||
|
||||
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
|
||||
et ipv6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
|
||||
le nom) peuvent-simplement être configurées avec un enregistrement NS
|
||||
adéquat. Par exemple, comme nous définissons plus haut les adresses
|
||||
|
||||
1051
po/pt_BR.po
1051
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all
|
||||
if (!(flag & F_IPV4))
|
||||
continue;
|
||||
|
||||
netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
|
||||
|
||||
if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
|
||||
return subnet;
|
||||
@@ -231,8 +231,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
|
||||
|
||||
if (!found)
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ static void blockdata_expand(int n)
|
||||
{
|
||||
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
||||
|
||||
if (new)
|
||||
if (n > 0 && new)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -46,14 +46,19 @@ void blockdata_init(void)
|
||||
blockdata_alloced = 0;
|
||||
blockdata_count = 0;
|
||||
blockdata_hwm = 0;
|
||||
|
||||
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
|
||||
|
||||
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
|
||||
blockdata_count * sizeof(struct blockdata), blockdata_hwm * sizeof(struct blockdata), blockdata_alloced * sizeof(struct blockdata));
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
|
||||
blockdata_count * sizeof(struct blockdata),
|
||||
blockdata_hwm * sizeof(struct blockdata),
|
||||
blockdata_alloced * sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
|
||||
@@ -376,7 +376,7 @@ void route_init(void)
|
||||
die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
void route_sock(time_t now)
|
||||
void route_sock(void)
|
||||
{
|
||||
struct if_msghdr *msg;
|
||||
int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
|
||||
@@ -401,7 +401,7 @@ void route_sock(time_t now)
|
||||
else if (msg->ifm_type == RTM_NEWADDR)
|
||||
{
|
||||
del_family = 0;
|
||||
newaddress(now);
|
||||
queue_event(EVENT_NEWADDR);
|
||||
}
|
||||
else if (msg->ifm_type == RTM_DELADDR)
|
||||
{
|
||||
@@ -439,7 +439,7 @@ void route_sock(time_t now)
|
||||
of += sizeof(long) - (diff & (sizeof(long) - 1));
|
||||
}
|
||||
|
||||
newaddress(now);
|
||||
queue_event(EVENT_NEWADDR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
190
src/cache.c
190
src/cache.c
@@ -24,7 +24,6 @@ static struct crec *new_chain = NULL;
|
||||
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 1;
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -73,6 +72,19 @@ static void cache_link(struct crec *crecp);
|
||||
static void rehash(int size);
|
||||
static void cache_hash(struct crec *crecp);
|
||||
|
||||
static unsigned int next_uid(void)
|
||||
{
|
||||
static unsigned int uid = 0;
|
||||
|
||||
uid++;
|
||||
|
||||
/* uid == 0 used to indicate CNAME to interface name. */
|
||||
if (uid == SRC_INTERFACE)
|
||||
uid++;
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
void cache_init(void)
|
||||
{
|
||||
struct crec *crecp;
|
||||
@@ -88,7 +100,7 @@ void cache_init(void)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = uid++;
|
||||
crecp->uid = next_uid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +195,7 @@ static void cache_blockdata_free(struct crec *crecp)
|
||||
else
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
}
|
||||
else if (crecp->flags & F_DS)
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.ds.keydata);
|
||||
}
|
||||
#endif
|
||||
@@ -192,10 +204,7 @@ static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (uid == -1)
|
||||
uid++;
|
||||
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
@@ -256,7 +265,7 @@ char *cache_get_name(struct crec *crecp)
|
||||
|
||||
char *cache_get_cname_target(struct crec *crecp)
|
||||
{
|
||||
if (crecp->addr.cname.uid != -1)
|
||||
if (crecp->addr.cname.uid != SRC_INTERFACE)
|
||||
return cache_get_name(crecp->addr.cname.target.cache);
|
||||
|
||||
return crecp->addr.cname.target.int_name->name;
|
||||
@@ -289,7 +298,7 @@ struct crec *cache_enumerate(int init)
|
||||
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1)
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
return 0;
|
||||
|
||||
/* NB. record may be reused as DS or DNSKEY, where uid is
|
||||
@@ -564,7 +573,14 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
*cache_get_name(new) = 0;
|
||||
|
||||
if (addr)
|
||||
new->addr.addr = *addr;
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & (F_DS | F_DNSKEY))
|
||||
new->uid = addr->addr.dnssec.class;
|
||||
else
|
||||
#endif
|
||||
new->addr.addr = *addr;
|
||||
}
|
||||
|
||||
new->ttd = now + (time_t)ttl;
|
||||
new->next = new_chain;
|
||||
@@ -620,7 +636,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
{
|
||||
if ((crecp->flags & F_FORWARD) &&
|
||||
#ifdef HAVE_DNSSEC
|
||||
((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
|
||||
(((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
|
||||
#endif
|
||||
(crecp->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
@@ -680,7 +696,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
if (ans &&
|
||||
(ans->flags & F_FORWARD) &&
|
||||
#ifdef HAVE_DNSSEC
|
||||
((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
|
||||
(((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
|
||||
#endif
|
||||
(ans->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(ans), name))
|
||||
@@ -767,13 +783,14 @@ static void add_hosts_cname(struct crec *target)
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.target.cache = target;
|
||||
crec->addr.cname.uid = target->uid;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
add_hosts_cname(crec); /* handle chains */
|
||||
}
|
||||
}
|
||||
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||
int index, struct crec **rhash, int hashsz)
|
||||
unsigned int index, struct crec **rhash, int hashsz)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||
int i, nameexists = 0;
|
||||
@@ -877,7 +894,7 @@ static int gettok(FILE *f, char *token)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
@@ -1027,7 +1044,8 @@ void cache_reload(void)
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = -1;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
cache->uid = next_uid();
|
||||
cache_hash(cache);
|
||||
add_hosts_cname(cache); /* handle chains */
|
||||
}
|
||||
@@ -1063,7 +1081,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
|
||||
@@ -1071,7 +1089,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1084,7 +1102,7 @@ void cache_reload(void)
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -1148,6 +1166,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
aliasc->name.namep = a->alias;
|
||||
aliasc->addr.cname.target.cache = target;
|
||||
aliasc->addr.cname.uid = target->uid;
|
||||
aliasc->uid = next_uid();
|
||||
cache_hash(aliasc);
|
||||
add_dhcp_cname(aliasc, ttd);
|
||||
}
|
||||
@@ -1235,7 +1254,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->uid = uid++;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
|
||||
add_dhcp_cname(crec, ttd);
|
||||
@@ -1243,6 +1262,101 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
}
|
||||
#endif
|
||||
|
||||
int cache_make_stat(struct txt_record *t)
|
||||
{
|
||||
static char *buff = NULL;
|
||||
static int bufflen = 60;
|
||||
int len;
|
||||
struct server *serv, *serv1;
|
||||
char *p;
|
||||
|
||||
if (!buff && !(buff = whine_malloc(60)))
|
||||
return 0;
|
||||
|
||||
p = buff;
|
||||
|
||||
switch (t->stat)
|
||||
{
|
||||
case TXT_STAT_CACHESIZE:
|
||||
sprintf(buff+1, "%d", daemon->cachesize);
|
||||
break;
|
||||
|
||||
case TXT_STAT_INSERTS:
|
||||
sprintf(buff+1, "%d", cache_inserted);
|
||||
break;
|
||||
|
||||
case TXT_STAT_EVICTIONS:
|
||||
sprintf(buff+1, "%d", cache_live_freed);
|
||||
break;
|
||||
|
||||
case TXT_STAT_MISSES:
|
||||
sprintf(buff+1, "%u", daemon->queries_forwarded);
|
||||
break;
|
||||
|
||||
case TXT_STAT_HITS:
|
||||
sprintf(buff+1, "%u", daemon->local_answer);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
case TXT_STAT_AUTH:
|
||||
sprintf(buff+1, "%u", daemon->auth_answer);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TXT_STAT_SERVERS:
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
char *new, *lenp;
|
||||
int port, newlen, bytes_avail, bytes_needed;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
lenp = p++; /* length */
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
if (bytes_needed >= bytes_avail)
|
||||
{
|
||||
/* expand buffer if necessary */
|
||||
newlen = bytes_needed + 1 + bufflen - bytes_avail;
|
||||
if (!(new = whine_malloc(newlen)))
|
||||
return 0;
|
||||
memcpy(new, buff, bufflen);
|
||||
free(buff);
|
||||
p = new + (p - buff);
|
||||
lenp = p - 1;
|
||||
buff = new;
|
||||
bufflen = newlen;
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
*lenp = bytes_needed;
|
||||
p += bytes_needed;
|
||||
}
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = p - buff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = strlen(buff+1);
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = len + 1;
|
||||
*buff = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
@@ -1304,25 +1418,16 @@ void dump_cache(time_t now)
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
if (cache->flags & F_DNSKEY)
|
||||
{
|
||||
/* RRSIG */
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
|
||||
}
|
||||
else
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
/* RRSIG */
|
||||
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
|
||||
else if (!(cache->flags & F_NEG))
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||
cache->addr.key.algo, cache->addr.key.flags);
|
||||
}
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||
cache->addr.key.algo, cache->addr.key.flags);
|
||||
#endif
|
||||
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
|
||||
{
|
||||
@@ -1370,11 +1475,13 @@ void dump_cache(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
char *record_source(int index)
|
||||
char *record_source(unsigned int index)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
if (index == 0)
|
||||
if (index == SRC_CONFIG)
|
||||
return "config";
|
||||
else if (index == SRC_HOSTS)
|
||||
return HOSTSFILE;
|
||||
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -1502,6 +1609,13 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
source = arg;
|
||||
verb = "to";
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = "ipset add";
|
||||
dest = name;
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
}
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
|
||||
32
src/config.h
32
src/config.h
@@ -18,7 +18,7 @@
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define KEYBLOCK_LEN 35 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
@@ -31,7 +31,8 @@
|
||||
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
|
||||
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
|
||||
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
|
||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||
#define SMALLDNAME 50 /* most domain names are smaller than this */
|
||||
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
@@ -46,6 +47,8 @@
|
||||
#define SOA_REFRESH 1200 /* SOA refresh default */
|
||||
#define SOA_RETRY 180 /* SOA retry default */
|
||||
#define SOA_EXPIRY 1209600 /* SOA expiry default */
|
||||
#define LOOP_TEST_DOMAIN "test" /* domain for loop testing, "test" is reserved by RFC 2606 and won't therefore clash */
|
||||
#define LOOP_TEST_TYPE T_TXT
|
||||
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
@@ -104,6 +107,12 @@ HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
HAVE_LOOP
|
||||
include functionality to probe for and remove DNS forwarding loops.
|
||||
|
||||
|
||||
NO_IPV6
|
||||
NO_TFTP
|
||||
@@ -117,6 +126,11 @@ NO_AUTH
|
||||
which are enabled by default in the distributed source tree. Building dnsmasq
|
||||
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||
|
||||
NO_NETTLE_ECC
|
||||
Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
|
||||
NO_GMP
|
||||
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
|
||||
|
||||
LEASEFILE
|
||||
CONFFILE
|
||||
RESOLVFILE
|
||||
@@ -140,6 +154,7 @@ RESOLVFILE
|
||||
#define HAVE_SCRIPT
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
#define HAVE_LOOP
|
||||
|
||||
/* Build options which require external libraries.
|
||||
|
||||
@@ -260,6 +275,7 @@ HAVE_SOCKADDR_SA_LEN
|
||||
/* Select the RFC_3542 version of the IPv6 socket API.
|
||||
Define before netinet6/in6.h is included. */
|
||||
#define __APPLE_USE_RFC_3542
|
||||
#define NO_IPSET
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#define HAVE_BSD_NETWORK
|
||||
@@ -329,10 +345,14 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
|
||||
#if defined(NO_IPSET)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
|
||||
#ifdef NO_LOOP
|
||||
#undef HAVE_LOOP
|
||||
#endif
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
|
||||
@@ -402,7 +422,11 @@ static char *compile_opts =
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
"DNSSEC";
|
||||
"DNSSEC "
|
||||
#ifndef HAVE_LOOP
|
||||
"no-"
|
||||
#endif
|
||||
"loop-detect";
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
81
src/dbus.c
81
src/dbus.c
@@ -35,6 +35,11 @@ const char* introspection_xml_template =
|
||||
" <method name=\"GetVersion\">\n"
|
||||
" <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
|
||||
" </method>\n"
|
||||
#ifdef HAVE_LOOP
|
||||
" <method name=\"GetLoopServers\">\n"
|
||||
" <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
|
||||
" </method>\n"
|
||||
#endif
|
||||
" <method name=\"SetServers\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
|
||||
" </method>\n"
|
||||
@@ -44,6 +49,12 @@ const char* introspection_xml_template =
|
||||
" <method name=\"SetServersEx\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetFilterWin2KOption\">\n"
|
||||
" <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetBogusPrivOption\">\n"
|
||||
" <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <signal name=\"DhcpLeaseAdded\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
@@ -150,13 +161,16 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
dbus_message_iter_get_basic(&iter, &p[i]);
|
||||
dbus_message_iter_next (&iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
|
||||
break;
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
my_syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
|
||||
#else
|
||||
if (i == sizeof(struct in6_addr)-1)
|
||||
if (i == sizeof(struct in6_addr))
|
||||
{
|
||||
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -196,6 +210,29 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
cleanup_servers();
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter args, args_iter;
|
||||
struct server *serv;
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
|
||||
dbus_message_iter_init_append (reply, &args);
|
||||
dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_LOOP)
|
||||
{
|
||||
prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container (&args, &args_iter);
|
||||
|
||||
return reply;
|
||||
}
|
||||
#endif
|
||||
|
||||
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
DBusMessageIter iter, array_iter, string_iter;
|
||||
@@ -372,6 +409,30 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
return error;
|
||||
}
|
||||
|
||||
static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
dbus_bool_t enabled;
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &enabled);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
my_syslog(LOG_INFO, "Enabling --%s option from D-Bus", name);
|
||||
set_option_bool(flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_INFO, "Disabling --$s option from D-Bus", name);
|
||||
reset_option_bool(flag);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
void *user_data)
|
||||
@@ -400,6 +461,12 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
|
||||
}
|
||||
#ifdef HAVE_LOOP
|
||||
else if (strcmp(method, "GetLoopServers") == 0)
|
||||
{
|
||||
reply = dbus_reply_server_loop(message);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
dbus_read_servers(message);
|
||||
@@ -415,6 +482,14 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
reply = dbus_read_servers_ex(message, 1);
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetFilterWin2KOption") == 0)
|
||||
{
|
||||
reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
|
||||
}
|
||||
else if (strcmp(method, "SetBogusPrivOption") == 0)
|
||||
{
|
||||
reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache = 1;
|
||||
else
|
||||
@@ -558,7 +633,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
{
|
||||
print_mac(mac, lease->clid, lease->clid_len);
|
||||
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
@@ -232,7 +232,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
|
||||
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
|
||||
{
|
||||
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||
{
|
||||
@@ -404,7 +404,8 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
/* interface name already copied in */
|
||||
arp_req.arp_flags = ATF_COM;
|
||||
ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
|
||||
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
|
||||
}
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
|
||||
|
||||
@@ -727,8 +727,7 @@ void dhcp_construct_contexts(time_t now)
|
||||
|
||||
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
|
||||
{
|
||||
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
|
||||
option_bool(OPT_RA))
|
||||
if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
|
||||
{
|
||||
/* previously constructed context has gone. advertise it's demise */
|
||||
context->flags |= CONTEXT_OLD;
|
||||
|
||||
@@ -30,6 +30,7 @@ static void sig_handler(int sig);
|
||||
static void async_event(int pipe, time_t now);
|
||||
static void fatal_event(struct event_desc *ev, char *msg);
|
||||
static int read_event(int fd, struct event_desc *evp, char **msg);
|
||||
static void poll_resolv(int force, int do_reload, time_t now);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
@@ -79,7 +80,9 @@ 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);
|
||||
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
@@ -185,7 +188,10 @@ int main (int argc, char **argv)
|
||||
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
rand_init();
|
||||
#ifndef HAVE_LOOP
|
||||
if (option_bool(OPT_LOOP_DETECT))
|
||||
die(_("Loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
@@ -397,7 +403,7 @@ int main (int argc, char **argv)
|
||||
piperead = pipefd[0];
|
||||
pipewrite = pipefd[1];
|
||||
/* prime the pipe to load stuff first time. */
|
||||
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||
send_event(pipewrite, EVENT_INIT, 0, NULL);
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
@@ -661,10 +667,17 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
{
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
if (option_bool(OPT_DNSSEC_TIME))
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (log_err != 0)
|
||||
@@ -910,10 +923,10 @@ int main (int argc, char **argv)
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast(now);
|
||||
netlink_multicast();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
if (FD_ISSET(daemon->routefd, &rset))
|
||||
route_sock(now);
|
||||
route_sock();
|
||||
#endif
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
@@ -1030,6 +1043,11 @@ void send_alarm(time_t event, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
void queue_event(int event)
|
||||
{
|
||||
send_event(pipewrite, event, 0, NULL);
|
||||
}
|
||||
|
||||
void send_event(int fd, int event, int data, char *msg)
|
||||
{
|
||||
struct event_desc ev;
|
||||
@@ -1127,8 +1145,18 @@ static void async_event(int pipe, time_t now)
|
||||
switch (ev.event)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
reset_option_bool(OPT_DNSSEC_TIME);
|
||||
}
|
||||
#endif
|
||||
/* fall through */
|
||||
|
||||
case EVENT_INIT:
|
||||
clear_cache_and_reload(now);
|
||||
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
if (daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
@@ -1213,7 +1241,17 @@ static void async_event(int pipe, time_t now)
|
||||
if (daemon->log_file != NULL)
|
||||
log_reopen(daemon->log_file);
|
||||
break;
|
||||
|
||||
|
||||
case EVENT_NEWADDR:
|
||||
newaddress(now);
|
||||
break;
|
||||
|
||||
case EVENT_NEWROUTE:
|
||||
resend_query();
|
||||
/* Force re-reading resolv file right now, for luck. */
|
||||
poll_resolv(0, 1, now);
|
||||
break;
|
||||
|
||||
case EVENT_TERM:
|
||||
/* Knock all our children on the head. */
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
@@ -1246,7 +1284,7 @@ static void async_event(int pipe, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
void poll_resolv(int force, int do_reload, time_t now)
|
||||
static void poll_resolv(int force, int do_reload, time_t now)
|
||||
{
|
||||
struct resolvc *res, *latest;
|
||||
struct stat statbuf;
|
||||
|
||||
@@ -164,6 +164,9 @@ struct event_desc {
|
||||
#define EVENT_FORK_ERR 18
|
||||
#define EVENT_LUA_ERR 19
|
||||
#define EVENT_TFTP_ERR 20
|
||||
#define EVENT_INIT 21
|
||||
#define EVENT_NEWADDR 22
|
||||
#define EVENT_NEWROUTE 23
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -230,9 +233,12 @@ struct event_desc {
|
||||
#define OPT_QUIET_DHCP6 43
|
||||
#define OPT_QUIET_RA 44
|
||||
#define OPT_DNSSEC_VALID 45
|
||||
#define OPT_DNSSEC_PERMISS 46
|
||||
#define OPT_DNSSEC_TIME 46
|
||||
#define OPT_DNSSEC_DEBUG 47
|
||||
#define OPT_LAST 48
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LOOP_DETECT 50
|
||||
#define OPT_LAST 51
|
||||
|
||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||
@@ -278,10 +284,19 @@ struct naptr {
|
||||
struct naptr *next;
|
||||
};
|
||||
|
||||
#define TXT_STAT_CACHESIZE 1
|
||||
#define TXT_STAT_INSERTS 2
|
||||
#define TXT_STAT_EVICTIONS 3
|
||||
#define TXT_STAT_MISSES 4
|
||||
#define TXT_STAT_HITS 5
|
||||
#define TXT_STAT_AUTH 6
|
||||
#define TXT_STAT_SERVERS 7
|
||||
|
||||
struct txt_record {
|
||||
char *name;
|
||||
unsigned char *txt;
|
||||
unsigned short class, len;
|
||||
int stat;
|
||||
struct txt_record *next;
|
||||
};
|
||||
|
||||
@@ -365,7 +380,7 @@ struct crec {
|
||||
struct crec *cache;
|
||||
struct interface_name *int_name;
|
||||
} target;
|
||||
int uid; /* -1 if union is interface-name */
|
||||
unsigned int uid; /* 0 if union is interface-name */
|
||||
} cname;
|
||||
struct {
|
||||
struct blockdata *keydata;
|
||||
@@ -386,7 +401,7 @@ struct crec {
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
|
||||
int uid;
|
||||
unsigned int uid;
|
||||
unsigned short flags;
|
||||
union {
|
||||
char sname[SMALLDNAME];
|
||||
@@ -424,6 +439,14 @@ struct crec {
|
||||
#define F_KEYTAG (1u<<23)
|
||||
#define F_SECSTAT (1u<<24)
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
#define F_NSIGMATCH (1u<<27)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
#define SRC_CONFIG 1
|
||||
#define SRC_HOSTS 2
|
||||
#define SRC_AH 3
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
@@ -457,6 +480,7 @@ union mysockaddr {
|
||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -477,6 +501,9 @@ struct server {
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags, tcpfd;
|
||||
unsigned int queries, failed_queries;
|
||||
#ifdef HAVE_LOOP
|
||||
u32 uid;
|
||||
#endif
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
@@ -523,7 +550,7 @@ struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
int flags;
|
||||
char *fname;
|
||||
int index; /* matches to cache entries for logging */
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
|
||||
@@ -535,6 +562,10 @@ struct hostsfile {
|
||||
#define STAT_NEED_KEY 5
|
||||
#define STAT_TRUNCATED 6
|
||||
#define STAT_SECURE_WILDCARD 7
|
||||
#define STAT_NO_SIG 8
|
||||
#define STAT_NO_DS 9
|
||||
#define STAT_NEED_DS_NEG 10
|
||||
#define STAT_CHASE_CNAME 11
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
@@ -542,6 +573,9 @@ struct hostsfile {
|
||||
#define FREC_DNSKEY_QUERY 8
|
||||
#define FREC_DS_QUERY 16
|
||||
#define FREC_AD_QUESTION 32
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_CHECK_NOSIGN 256
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
@@ -613,6 +647,8 @@ struct dhcp_lease {
|
||||
unsigned char *extradata;
|
||||
unsigned int extradata_len, extradata_size;
|
||||
int last_interface;
|
||||
int new_interface; /* save possible originated interface */
|
||||
int new_prefixlen; /* and its prefix length */
|
||||
#ifdef HAVE_DHCP6
|
||||
struct in6_addr addr6;
|
||||
int iaid;
|
||||
@@ -797,7 +833,7 @@ struct dhcp_context {
|
||||
#define CONTEXT_NETMASK (1u<<1)
|
||||
#define CONTEXT_BRDCAST (1u<<2)
|
||||
#define CONTEXT_PROXY (1u<<3)
|
||||
#define CONTEXT_RA_ONLY (1u<<4)
|
||||
#define CONTEXT_RA_ROUTER (1u<<4)
|
||||
#define CONTEXT_RA_DONE (1u<<5)
|
||||
#define CONTEXT_RA_NAME (1u<<6)
|
||||
#define CONTEXT_RA_STATELESS (1u<<7)
|
||||
@@ -812,7 +848,6 @@ struct dhcp_context {
|
||||
#define CONTEXT_OLD (1u<<16)
|
||||
#define CONTEXT_V6 (1u<<17)
|
||||
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
time_t time;
|
||||
@@ -958,6 +993,7 @@ extern struct daemon {
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, helperfd, pxefd;
|
||||
@@ -995,7 +1031,7 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
@@ -1011,6 +1047,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
int cache_make_stat(struct txt_record *t);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *cache_get_cname_target(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
@@ -1048,7 +1085,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
int no_cache, int secure, int *doctored);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int *ad_reqd);
|
||||
time_t now, int *ad_reqd, int *do_bit);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
@@ -1083,13 +1120,16 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer);
|
||||
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
unsigned short rand16(void);
|
||||
u32 rand32(void);
|
||||
u64 rand64(void);
|
||||
int legal_hostname(char *c);
|
||||
char *canonicalise(char *s, int *nomem);
|
||||
@@ -1101,6 +1141,7 @@ int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||
int hostname_isequal(const char *a, const char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
int netmask_length(struct in_addr mask);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
#ifdef HAVE_IPV6
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||
@@ -1120,6 +1161,7 @@ void bump_maxfd(int fd, int *max);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
@@ -1152,6 +1194,9 @@ struct frec *get_new_frec(time_t now, int *wait, int force);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface);
|
||||
void resend_query();
|
||||
struct randfd *allocate_rfd(int family);
|
||||
void free_rfd(struct randfd *rfd);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
@@ -1259,15 +1304,15 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||
int make_icmp_sock(void);
|
||||
int icmp_ping(struct in_addr addr);
|
||||
#endif
|
||||
void queue_event(int event);
|
||||
void send_alarm(time_t event, time_t now);
|
||||
void send_event(int fd, int event, int data, char *msg);
|
||||
void clear_cache_and_reload(time_t now);
|
||||
void poll_resolv(int force, int do_reload, time_t now);
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
void netlink_multicast(time_t now);
|
||||
void netlink_multicast(void);
|
||||
#endif
|
||||
|
||||
/* bpf.c */
|
||||
@@ -1276,7 +1321,7 @@ void init_bpf(void);
|
||||
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
struct in_addr iface_addr, struct ifreq *ifr);
|
||||
void route_init(void);
|
||||
void route_sock(time_t now);
|
||||
void route_sock(void);
|
||||
#endif
|
||||
|
||||
/* bpf.c or netlink.c */
|
||||
@@ -1417,3 +1462,10 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
|
||||
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
|
||||
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
|
||||
#endif
|
||||
|
||||
/* loop.c */
|
||||
#ifdef HAVE_LOOP
|
||||
void loop_send_probes();
|
||||
int detect_loop(char *query, int type);
|
||||
#endif
|
||||
|
||||
|
||||
838
src/dnssec.c
838
src/dnssec.c
File diff suppressed because it is too large
Load Diff
561
src/forward.c
561
src/forward.c
@@ -22,7 +22,14 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
void *hash);
|
||||
static unsigned short get_id(void);
|
||||
static void free_frec(struct frec *f);
|
||||
static struct randfd *allocate_rfd(int family);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
||||
int class, char *name, char *keyname, struct server *server, int *keycount);
|
||||
static int do_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
static int send_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
|
||||
#endif
|
||||
|
||||
|
||||
/* Send a UDP packet with its source address set as "source"
|
||||
unless nowild is true, when we just send it with the kernel default */
|
||||
@@ -235,7 +242,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
struct dns_header *header, size_t plen, time_t now,
|
||||
struct frec *forward, int ad_reqd)
|
||||
struct frec *forward, int ad_reqd, int do_bit)
|
||||
{
|
||||
char *domain = NULL;
|
||||
int type = 0, norebind = 0;
|
||||
@@ -250,6 +257,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
#endif
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
|
||||
(void)do_bit;
|
||||
|
||||
/* may be no servers available. */
|
||||
if (!daemon->servers)
|
||||
forward = NULL;
|
||||
@@ -268,7 +277,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
if (forward->sentto->addr.sa.sa_family)
|
||||
if (forward->sentto->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
@@ -289,7 +298,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
while (sendto(fd, (char *)header, plen, 0,
|
||||
&forward->sentto->addr.sa,
|
||||
sa_len(&forward->sentto->addr)) == -1 && retry_send());
|
||||
sa_len(&forward->sentto->addr)) == -1 && retry_send());
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -336,8 +345,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->flags |= FREC_AD_QUESTION;
|
||||
#ifdef HAVE_DNSSEC
|
||||
forward->work_counter = DNSSEC_WORK;
|
||||
if (do_bit)
|
||||
forward->flags |= FREC_DO_QUESTION;
|
||||
#endif
|
||||
|
||||
|
||||
header->id = htons(forward->new_id);
|
||||
|
||||
/* In strict_order mode, always try servers in the order
|
||||
@@ -393,11 +404,17 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
|
||||
size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
|
||||
if (new_plen != plen)
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
plen = new_plen;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -409,7 +426,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
if (type == (start->flags & SERV_TYPE) &&
|
||||
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
||||
!(start->flags & SERV_LITERAL_ADDRESS))
|
||||
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||
{
|
||||
int fd;
|
||||
|
||||
@@ -506,7 +523,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
|
||||
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
|
||||
int no_cache, int cache_secure, int ad_reqd, int check_subnet, union mysockaddr *query_source)
|
||||
int no_cache, int cache_secure, int ad_reqd, int do_bit, int added_pheader, int check_subnet, union mysockaddr *query_source)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
@@ -514,22 +531,26 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
size_t plen;
|
||||
|
||||
(void)ad_reqd;
|
||||
(void) do_bit;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos;
|
||||
unsigned int namelen = strlen(daemon->namebuff);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
{
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
char *matchstart = daemon->namebuff + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen)
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos;
|
||||
unsigned int namelen = strlen(daemon->namebuff);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
{
|
||||
matchlen = domainlen;
|
||||
sets = ipset_pos->sets;
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
char *matchstart = daemon->namebuff + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen)
|
||||
{
|
||||
matchlen = domainlen;
|
||||
sets = ipset_pos->sets;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -553,6 +574,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (added_pheader)
|
||||
{
|
||||
pheader = 0;
|
||||
header->arcount = htons(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* RFC 4035 sect 4.6 para 3 */
|
||||
@@ -560,7 +587,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
|
||||
return n;
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
|
||||
/* Complain loudly if the upstream server is non-recursive. */
|
||||
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
|
||||
@@ -624,6 +651,10 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
|
||||
if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
|
||||
header->hb4 |= HB4_AD;
|
||||
|
||||
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||
if (!do_bit)
|
||||
n = filter_rrsigs(header, n);
|
||||
#endif
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
@@ -669,14 +700,20 @@ void reply_query(int fd, int family, time_t now)
|
||||
serveraddr.in6.sin6_flowinfo = 0;
|
||||
#endif
|
||||
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
|
||||
if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
|
||||
return;
|
||||
|
||||
/* spoof check: answer must come from known server, */
|
||||
for (server = daemon->servers; server; server = server->next)
|
||||
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
|
||||
sockaddr_isequal(&server->addr, &serveraddr))
|
||||
break;
|
||||
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
hash = hash_questions(header, n, daemon->namebuff);
|
||||
#else
|
||||
@@ -684,11 +721,9 @@ void reply_query(int fd, int family, time_t now)
|
||||
crc = questions_crc(header, n, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
if (!server ||
|
||||
n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
|
||||
!(forward = lookup_frec(ntohs(header->id), hash)))
|
||||
if (!(forward = lookup_frec(ntohs(header->id), hash)))
|
||||
return;
|
||||
|
||||
|
||||
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
@@ -708,7 +743,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
header->hb3 &= ~(HB3_QR | HB3_TC);
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0);
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -718,7 +753,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
{
|
||||
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
|
||||
if (RCODE(header) == REFUSED)
|
||||
server = NULL;
|
||||
else
|
||||
{
|
||||
@@ -741,8 +776,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
we get a good reply from another server. Kill it when we've
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
everything is broken */
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
|
||||
{
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0;
|
||||
|
||||
@@ -755,7 +789,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
|
||||
if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -775,13 +809,27 @@ void reply_query(int fd, int family, time_t now)
|
||||
else if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else if (forward->flags & FREC_DS_QUERY)
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
{
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
if (status == STAT_NO_DS)
|
||||
status = STAT_INSECURE;
|
||||
}
|
||||
else if (forward->flags & FREC_CHECK_NOSIGN)
|
||||
status = do_check_sign(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
||||
|
||||
{
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL);
|
||||
if (status == STAT_NO_SIG)
|
||||
{
|
||||
if (option_bool(OPT_DNSSEC_NO_SIGN))
|
||||
status = send_check_sign(now, header, n, daemon->namebuff, daemon->keyname);
|
||||
else
|
||||
status = STAT_INSECURE;
|
||||
}
|
||||
}
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
answer aside, whilst we get that. */
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG || status == STAT_NEED_KEY)
|
||||
{
|
||||
struct frec *new, *orig;
|
||||
|
||||
@@ -807,11 +855,12 @@ void reply_query(int fd, int family, time_t now)
|
||||
*new = *forward; /* copy everything, then overwrite */
|
||||
new->next = next;
|
||||
new->blocking_query = NULL;
|
||||
new->sentto = server;
|
||||
new->rfd4 = NULL;
|
||||
#ifdef HAVE_IPV6
|
||||
new->rfd6 = NULL;
|
||||
#endif
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_CHECK_NOSIGN);
|
||||
|
||||
new->dependent = forward; /* to find query awaiting new one. */
|
||||
forward->blocking_query = new; /* for garbage cleaning */
|
||||
@@ -824,7 +873,10 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
else
|
||||
{
|
||||
new->flags |= FREC_DS_QUERY;
|
||||
if (status == STAT_NEED_DS_NEG)
|
||||
new->flags |= FREC_CHECK_NOSIGN;
|
||||
else
|
||||
new->flags |= FREC_DS_QUERY;
|
||||
nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
|
||||
daemon->keyname, forward->class, T_DS, &server->addr);
|
||||
}
|
||||
@@ -888,11 +940,26 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else if (forward->flags & FREC_DS_QUERY)
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
{
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
if (status == STAT_NO_DS)
|
||||
status = STAT_INSECURE;
|
||||
}
|
||||
else if (forward->flags & FREC_CHECK_NOSIGN)
|
||||
status = do_check_sign(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class);
|
||||
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
{
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL);
|
||||
if (status == STAT_NO_SIG)
|
||||
{
|
||||
if (option_bool(OPT_DNSSEC_NO_SIGN))
|
||||
status = send_check_sign(now, header, n, daemon->namebuff, daemon->keyname);
|
||||
else
|
||||
status = STAT_INSECURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG || status == STAT_NEED_KEY)
|
||||
goto anotherkey;
|
||||
}
|
||||
}
|
||||
@@ -927,7 +994,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->hb4 &= ~HB4_CD;
|
||||
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
@@ -1014,11 +1082,60 @@ void receive_query(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
|
||||
if (listen->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 */
|
||||
if (source_addr.in.sin_port == 0)
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
else
|
||||
{
|
||||
/* Source-port == 0 is an error, we can't send back to that. */
|
||||
if (source_addr.in6.sin6_port == 0)
|
||||
return;
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
if ((addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
|
||||
break;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct in_addr netmask;
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
{
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
|
||||
if (!(addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!addr)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
|
||||
warned = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_dst)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
@@ -1153,6 +1270,12 @@ void receive_query(struct listener *listen, time_t now)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
/* Check for forwarding loop */
|
||||
if (detect_loop(daemon->namebuff, type))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
@@ -1169,9 +1292,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int ad_reqd;
|
||||
int ad_reqd, do_bit;
|
||||
m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n,
|
||||
dst_addr_4, netmask, now, &ad_reqd);
|
||||
dst_addr_4, netmask, now, &ad_reqd, &do_bit);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
@@ -1180,7 +1303,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
daemon->local_answer++;
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL, ad_reqd))
|
||||
header, (size_t)n, now, NULL, ad_reqd, do_bit))
|
||||
daemon->queries_forwarded++;
|
||||
else
|
||||
daemon->local_answer++;
|
||||
@@ -1188,6 +1311,192 @@ void receive_query(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
/* UDP: we've got an unsigned answer, return STAT_INSECURE if we can prove there's no DS
|
||||
and therefore the answer shouldn't be signed, or STAT_BOGUS if it should be, or
|
||||
STAT_NEED_DS_NEG and keyname if we need to do the query. */
|
||||
static int send_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
|
||||
{
|
||||
struct crec *crecp;
|
||||
char *name_start = name;
|
||||
int status = dnssec_chase_cname(now, header, plen, name, keyname);
|
||||
|
||||
if (status != STAT_INSECURE)
|
||||
return status;
|
||||
|
||||
while (1)
|
||||
{
|
||||
crecp = cache_find_by_name(NULL, name_start, now, F_DS);
|
||||
|
||||
if (crecp && (crecp->flags & F_DNSSECOK))
|
||||
return (crecp->flags & F_NEG) ? STAT_INSECURE : STAT_BOGUS;
|
||||
|
||||
if (crecp && (crecp->flags & F_NEG) && (name_start = strchr(name_start, '.')))
|
||||
{
|
||||
name_start++; /* chop a label off and try again */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reached the root */
|
||||
if (!name_start)
|
||||
return STAT_BOGUS;
|
||||
|
||||
strcpy(keyname, name_start);
|
||||
return STAT_NEED_DS_NEG;
|
||||
}
|
||||
}
|
||||
|
||||
/* Got answer to DS query from send_check_sign, check for proven non-existence, or make the next DS query to try. */
|
||||
static int do_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
||||
|
||||
{
|
||||
char *name_start;
|
||||
unsigned char *p;
|
||||
int status;
|
||||
|
||||
/* In this case only, a SERVFAIL reply allows us to continue up the tree, looking for a
|
||||
suitable NSEC reply to DS queries. */
|
||||
if (RCODE(header) != SERVFAIL)
|
||||
{
|
||||
status = dnssec_validate_ds(now, header, plen, name, keyname, class);
|
||||
|
||||
if (status != STAT_INSECURE)
|
||||
{
|
||||
if (status == STAT_NO_DS)
|
||||
status = STAT_INSECURE;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
if (extract_name(header, plen, &p, name, 1, 4) &&
|
||||
(name_start = strchr(name, '.')))
|
||||
{
|
||||
name_start++; /* chop a label off and try again */
|
||||
strcpy(keyname, name_start);
|
||||
return STAT_NEED_DS_NEG;
|
||||
}
|
||||
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
/* Move toward the root, until we find a signed non-existance of a DS, in which case
|
||||
an unsigned answer is OK, or we find a signed DS, in which case there should be
|
||||
a signature, and the answer is BOGUS */
|
||||
static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, size_t plen, int class, char *name,
|
||||
char *keyname, struct server *server, int *keycount)
|
||||
{
|
||||
size_t m;
|
||||
unsigned char *packet, *payload;
|
||||
u16 *length;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int status;
|
||||
char *name_start = name;
|
||||
|
||||
/* Get first insecure entry in CNAME chain */
|
||||
status = tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, class, name, keyname, server, keycount);
|
||||
if (status == STAT_BOGUS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (!(packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16))))
|
||||
return STAT_BOGUS;
|
||||
|
||||
payload = &packet[2];
|
||||
header = (struct dns_header *)payload;
|
||||
length = (u16 *)packet;
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned char *newhash, hash[HASH_SIZE];
|
||||
unsigned char c1, c2;
|
||||
struct crec *crecp = cache_find_by_name(NULL, name_start, now, F_DS);
|
||||
|
||||
if (--(*keycount) == 0)
|
||||
{
|
||||
free(packet);
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (crecp && (crecp->flags & F_DNSSECOK))
|
||||
{
|
||||
free(packet);
|
||||
return (crecp->flags & F_NEG) ? STAT_INSECURE : STAT_BOGUS;
|
||||
}
|
||||
|
||||
/* If we have cached insecurely that a DS doesn't exist,
|
||||
ise that is a hit for where to start looking for the secure one */
|
||||
if (crecp && (crecp->flags & F_NEG) && (name_start = strchr(name_start, '.')))
|
||||
{
|
||||
name_start++; /* chop a label off and try again */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reached the root */
|
||||
if (!name_start)
|
||||
{
|
||||
free(packet);
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr);
|
||||
|
||||
/* We rely on the question section coming back unchanged, ensure it is with the hash. */
|
||||
if ((newhash = hash_questions(header, (unsigned int)m, name)))
|
||||
{
|
||||
memcpy(hash, newhash, HASH_SIZE);
|
||||
|
||||
*length = htons(m);
|
||||
|
||||
if (read_write(server->tcpfd, packet, m + sizeof(u16), 0) &&
|
||||
read_write(server->tcpfd, &c1, 1, 1) &&
|
||||
read_write(server->tcpfd, &c2, 1, 1) &&
|
||||
read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
|
||||
{
|
||||
m = (c1 << 8) | c2;
|
||||
|
||||
newhash = hash_questions(header, (unsigned int)m, name);
|
||||
if (newhash && memcmp(hash, newhash, HASH_SIZE) == 0)
|
||||
{
|
||||
/* In this case only, a SERVFAIL reply allows us to continue up the tree, looking for a
|
||||
suitable NSEC reply to DS queries. */
|
||||
if (RCODE(header) == SERVFAIL)
|
||||
status = STAT_INSECURE;
|
||||
else
|
||||
/* Note this trashes all three name workspaces */
|
||||
status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name, keyname, server, keycount);
|
||||
|
||||
/* We've found a DS which proves the bit of the DNS where the
|
||||
original query is, is unsigned, so the answer is OK,
|
||||
if unvalidated. */
|
||||
if (status == STAT_NO_DS)
|
||||
{
|
||||
free(packet);
|
||||
return STAT_INSECURE;
|
||||
}
|
||||
|
||||
/* No DS, not got to DNSSEC-land yet, go up. */
|
||||
if (status == STAT_INSECURE)
|
||||
{
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
if (extract_name(header, plen, &p, name, 1, 4) &&
|
||||
(name_start = strchr(name, '.')))
|
||||
{
|
||||
name_start++; /* chop a label off and try again */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(packet);
|
||||
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
}
|
||||
|
||||
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
|
||||
int class, char *name, char *keyname, struct server *server, int *keycount)
|
||||
{
|
||||
@@ -1200,11 +1509,27 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
|
||||
if (status == STAT_NEED_KEY)
|
||||
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
|
||||
else if (status == STAT_NEED_DS)
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class);
|
||||
|
||||
else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
|
||||
{
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
if (status == STAT_NEED_DS && new_status == STAT_NO_DS)
|
||||
new_status = STAT_INSECURE;
|
||||
}
|
||||
else if (status == STAT_CHASE_CNAME)
|
||||
new_status = dnssec_chase_cname(now, header, n, name, keyname);
|
||||
else
|
||||
{
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL);
|
||||
|
||||
if (new_status == STAT_NO_SIG)
|
||||
{
|
||||
if (option_bool(OPT_DNSSEC_NO_SIGN))
|
||||
new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
|
||||
else
|
||||
new_status = STAT_INSECURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
||||
Make query for same, and recurse to validate */
|
||||
if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY)
|
||||
@@ -1234,7 +1559,9 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
{
|
||||
m = (c1 << 8) | c2;
|
||||
|
||||
if (tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount) == STAT_SECURE)
|
||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
|
||||
|
||||
if (new_status == STAT_SECURE)
|
||||
{
|
||||
/* Reached a validated record, now try again at this level.
|
||||
Note that we may get ANOTHER NEED_* if an answer needs more than one key.
|
||||
@@ -1242,11 +1569,27 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
|
||||
if (status == STAT_NEED_KEY)
|
||||
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
|
||||
else if (status == STAT_NEED_DS)
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class);
|
||||
|
||||
else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
|
||||
{
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
if (status == STAT_NEED_DS && new_status == STAT_NO_DS)
|
||||
new_status = STAT_INSECURE; /* Validated no DS */
|
||||
}
|
||||
else if (status == STAT_CHASE_CNAME)
|
||||
new_status = dnssec_chase_cname(now, header, n, name, keyname);
|
||||
else
|
||||
{
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL);
|
||||
|
||||
if (new_status == STAT_NO_SIG)
|
||||
{
|
||||
if (option_bool(OPT_DNSSEC_NO_SIGN))
|
||||
new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
|
||||
else
|
||||
new_status = STAT_INSECURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY)
|
||||
goto another_tcp_key;
|
||||
}
|
||||
@@ -1254,7 +1597,6 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
|
||||
free(packet);
|
||||
}
|
||||
|
||||
return new_status;
|
||||
}
|
||||
#endif
|
||||
@@ -1272,7 +1614,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_AUTH
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
int checking_disabled, ad_question, check_subnet, no_cache_dnssec = 0, cache_secure = 0;
|
||||
int checking_disabled, ad_question, do_bit, added_pheader = 0;
|
||||
int check_subnet, no_cache_dnssec = 0, cache_secure = 0;
|
||||
size_t m;
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
@@ -1290,6 +1633,37 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
|
||||
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (peer_addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
if ((addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
|
||||
break;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct in_addr netmask;
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
{
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
|
||||
if (!(addr->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!addr)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -1350,7 +1724,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
{
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
dst_addr_4, netmask, now, &ad_question);
|
||||
dst_addr_4, netmask, now, &ad_question, &do_bit);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(NULL);
|
||||
@@ -1388,8 +1762,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
struct server *firstsendto = NULL;
|
||||
#ifdef HAVE_DNSSEC
|
||||
unsigned char *newhash, hash[HASH_SIZE];
|
||||
if ((newhash = hash_questions(header, (unsigned int)size, daemon->keyname)))
|
||||
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
|
||||
@@ -1411,7 +1787,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
/* server for wrong domain */
|
||||
if (type != (last_server->flags & SERV_TYPE) ||
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
|
||||
(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||
continue;
|
||||
|
||||
if (last_server->tcpfd == -1)
|
||||
@@ -1430,11 +1807,17 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
size = add_do_bit(header, size, ((char *) header) + 65536);
|
||||
size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
|
||||
if (size != new_size)
|
||||
added_pheader = 1;
|
||||
|
||||
size = new_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1458,6 +1841,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
}
|
||||
|
||||
*length = htons(size);
|
||||
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
strcpy(daemon->namebuff, "query");
|
||||
|
||||
if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
|
||||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
|
||||
@@ -1471,8 +1858,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
m = (c1 << 8) | c2;
|
||||
|
||||
if (!gotname)
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (last_server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
|
||||
@@ -1533,7 +1918,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec,
|
||||
cache_secure, ad_question, check_subnet, &peer_addr);
|
||||
cache_secure, ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1579,7 +1964,7 @@ static struct frec *allocate_frec(time_t now)
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct randfd *allocate_rfd(int family)
|
||||
struct randfd *allocate_rfd(int family)
|
||||
{
|
||||
static int finger = 0;
|
||||
int i;
|
||||
@@ -1614,19 +1999,22 @@ static struct randfd *allocate_rfd(int family)
|
||||
|
||||
return NULL; /* doom */
|
||||
}
|
||||
|
||||
void free_rfd(struct randfd *rfd)
|
||||
{
|
||||
if (rfd && --(rfd->refcount) == 0)
|
||||
close(rfd->fd);
|
||||
}
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
if (f->rfd4 && --(f->rfd4->refcount) == 0)
|
||||
close(f->rfd4->fd);
|
||||
|
||||
free_rfd(f->rfd4);
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
f->flags = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (f->rfd6 && --(f->rfd6->refcount) == 0)
|
||||
close(f->rfd6->fd);
|
||||
|
||||
free_rfd(f->rfd6);
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
|
||||
@@ -1751,6 +2139,25 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Send query packet again, if we can. */
|
||||
void resend_query()
|
||||
{
|
||||
if (daemon->srv_save)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (daemon->srv_save->sfd)
|
||||
fd = daemon->srv_save->sfd->fd;
|
||||
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
|
||||
fd = daemon->rfd_save->fd;
|
||||
else
|
||||
return;
|
||||
|
||||
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
|
||||
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
||||
}
|
||||
}
|
||||
|
||||
/* A server record is going away, remove references to it */
|
||||
void server_gone(struct server *server)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
#if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK)
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
38
src/lease.c
38
src/lease.c
@@ -352,16 +352,21 @@ static int find_interface_v4(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
int prefix = netmask_length(netmask);
|
||||
|
||||
(void) label;
|
||||
(void) broadcast;
|
||||
(void) vparam;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
if (is_same_net(local, lease->addr, netmask))
|
||||
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
|
||||
is_same_net(local, lease->addr, netmask) &&
|
||||
prefix > lease->new_prefixlen)
|
||||
{
|
||||
lease->new_interface = if_index;
|
||||
lease->new_prefixlen = prefix;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -371,17 +376,23 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
|
||||
(void)scope;
|
||||
(void)flags;
|
||||
(void)preferred;
|
||||
(void)valid;
|
||||
(void)vparam;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
if (is_same_net6(local, &lease->addr6, prefix))
|
||||
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||
|
||||
if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
|
||||
/* save prefix length for comparison, as we might get shorter matching
|
||||
* prefix in upcoming netlink GETADDR responses
|
||||
* */
|
||||
lease->new_interface = if_index;
|
||||
lease->new_prefixlen = prefix;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -414,10 +425,19 @@ void lease_update_slaac(time_t now)
|
||||
start-time. */
|
||||
void lease_find_interfaces(time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
lease->new_prefixlen = lease->new_interface = 0;
|
||||
|
||||
iface_enumerate(AF_INET, &now, find_interface_v4);
|
||||
#ifdef HAVE_DHCP6
|
||||
iface_enumerate(AF_INET6, &now, find_interface_v6);
|
||||
#endif
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->new_interface != 0)
|
||||
lease_set_interface(lease, lease->new_interface, now);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
116
src/loop.c
Normal file
116
src/loop.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 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/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
static ssize_t loop_make_probe(u32 uid);
|
||||
|
||||
void loop_send_probes()
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
if (!option_bool(OPT_LOOP_DETECT))
|
||||
return;
|
||||
|
||||
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
|
||||
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
|
||||
{
|
||||
ssize_t len = loop_make_probe(serv->uid);
|
||||
int fd;
|
||||
struct randfd *rfd = NULL;
|
||||
|
||||
if (serv->sfd)
|
||||
fd = serv->sfd->fd;
|
||||
else
|
||||
{
|
||||
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
|
||||
continue;
|
||||
fd = rfd->fd;
|
||||
}
|
||||
|
||||
while (sendto(fd, daemon->packet, len, 0, &serv->addr.sa, sa_len(&serv->addr)) == -1 && retry_send());
|
||||
|
||||
free_rfd(rfd);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t loop_make_probe(u32 uid)
|
||||
{
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
header->id = rand16();
|
||||
header->ancount = header->nscount = header->arcount = htons(0);
|
||||
header->qdcount = htons(1);
|
||||
header->hb3 = HB3_RD;
|
||||
header->hb4 = 0;
|
||||
SET_OPCODE(header, QUERY);
|
||||
|
||||
*p++ = 8;
|
||||
sprintf((char *)p, "%.8x", uid);
|
||||
p += 8;
|
||||
*p++ = strlen(LOOP_TEST_DOMAIN);
|
||||
strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
|
||||
p += strlen(LOOP_TEST_DOMAIN) + 1;
|
||||
|
||||
PUTSHORT(LOOP_TEST_TYPE, p);
|
||||
PUTSHORT(C_IN, p);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
|
||||
int detect_loop(char *query, int type)
|
||||
{
|
||||
int i;
|
||||
u32 uid;
|
||||
struct server *serv;
|
||||
|
||||
if (!option_bool(OPT_LOOP_DETECT))
|
||||
return 0;
|
||||
|
||||
if (type != LOOP_TEST_TYPE ||
|
||||
strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
|
||||
strstr(query, LOOP_TEST_DOMAIN) != query + 9)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (!isxdigit(query[i]))
|
||||
return 0;
|
||||
|
||||
uid = strtol(query, NULL, 16);
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
|
||||
uid == serv->uid)
|
||||
{
|
||||
serv->flags |= SERV_LOOP;
|
||||
check_servers(); /* log new state */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -38,7 +38,7 @@
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
static int nl_async(struct nlmsghdr *h);
|
||||
static void nl_async(struct nlmsghdr *h);
|
||||
|
||||
void netlink_init(void)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
struct nlmsghdr *h;
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int callback_ok = 1, newaddr = 0;
|
||||
int callback_ok = 1;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -191,21 +191,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
if (nl_async(h))
|
||||
{
|
||||
newaddr = 1;
|
||||
enumerate_interfaces(1); /* reset */
|
||||
}
|
||||
nl_async(h);
|
||||
}
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
/* handle async new interface address arrivals, these have to be done
|
||||
after we complete as we're not re-entrant */
|
||||
if (newaddr)
|
||||
newaddress(dnsmasq_time());
|
||||
|
||||
return callback_ok;
|
||||
}
|
||||
return callback_ok;
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
@@ -219,7 +208,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
char *label = NULL;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
|
||||
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
@@ -330,11 +320,11 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
}
|
||||
|
||||
void netlink_multicast(time_t now)
|
||||
void netlink_multicast(void)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
int flags, newaddr = 0;
|
||||
int flags;
|
||||
|
||||
/* don't risk blocking reading netlink messages here. */
|
||||
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
|
||||
@@ -343,24 +333,19 @@ void netlink_multicast(time_t now)
|
||||
|
||||
if ((len = netlink_recv()) != -1)
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (nl_async(h))
|
||||
newaddr = 1;
|
||||
nl_async(h);
|
||||
|
||||
/* restore non-blocking status */
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||
|
||||
if (newaddr)
|
||||
newaddress(now);
|
||||
}
|
||||
|
||||
static int nl_async(struct nlmsghdr *h)
|
||||
static void nl_async(struct nlmsghdr *h)
|
||||
{
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
struct nlmsgerr *err = NLMSG_DATA(h);
|
||||
if (err->error != 0)
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
return 0;
|
||||
}
|
||||
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
||||
{
|
||||
@@ -372,31 +357,10 @@ static int nl_async(struct nlmsghdr *h)
|
||||
struct rtmsg *rtm = NLMSG_DATA(h);
|
||||
|
||||
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
|
||||
{
|
||||
/* Force re-reading resolv file right now, for luck. */
|
||||
daemon->last_resolv = 0;
|
||||
|
||||
if (daemon->srv_save)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (daemon->srv_save->sfd)
|
||||
fd = daemon->srv_save->sfd->fd;
|
||||
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
|
||||
fd = daemon->rfd_save->fd;
|
||||
else
|
||||
return 0;
|
||||
|
||||
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
|
||||
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
queue_event(EVENT_NEWROUTE);
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
return 1; /* clever bind mode - rescan */
|
||||
|
||||
return 0;
|
||||
queue_event(EVENT_NEWADDR);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -268,7 +268,40 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
|
||||
if (!label)
|
||||
label = ifr.ifr_name;
|
||||
|
||||
/* maintain a list of all addresses on all interfaces for --local-service option */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *al;
|
||||
|
||||
if (param->spare)
|
||||
{
|
||||
al = param->spare;
|
||||
param->spare = al->next;
|
||||
}
|
||||
else
|
||||
al = whine_malloc(sizeof(struct addrlist));
|
||||
|
||||
if (al)
|
||||
{
|
||||
al->next = daemon->interface_addrs;
|
||||
daemon->interface_addrs = al;
|
||||
al->prefixlen = prefixlen;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
al->addr.addr.addr4 = addr->in.sin_addr;
|
||||
al->flags = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
al->addr.addr.addr6 = addr->in6.sin6_addr;
|
||||
al->flags = ADDRLIST_IPV6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
||||
@@ -518,7 +551,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
|
||||
int enumerate_interfaces(int reset)
|
||||
{
|
||||
static struct addrlist *spare = NULL;
|
||||
static int done = 0, active = 0;
|
||||
static int done = 0;
|
||||
struct iface_param param;
|
||||
int errsave, ret = 1;
|
||||
struct addrlist *addr, *tmp;
|
||||
@@ -537,14 +570,11 @@ int enumerate_interfaces(int reset)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (done || active)
|
||||
if (done)
|
||||
return 1;
|
||||
|
||||
done = 1;
|
||||
|
||||
/* protect against recusive calls from iface_enumerate(); */
|
||||
active = 1;
|
||||
|
||||
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
@@ -565,6 +595,15 @@ int enumerate_interfaces(int reset)
|
||||
intname->addr = NULL;
|
||||
}
|
||||
|
||||
/* Remove list of addresses of local interfaces */
|
||||
for (addr = daemon->interface_addrs; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
daemon->interface_addrs = NULL;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* remove addresses stored against auth_zone subnets, but not
|
||||
ones configured as address literals */
|
||||
@@ -635,10 +674,8 @@ int enumerate_interfaces(int reset)
|
||||
}
|
||||
|
||||
errno = errsave;
|
||||
|
||||
spare = param.spare;
|
||||
active = 0;
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1260,8 +1297,14 @@ void mark_servers(int flag)
|
||||
|
||||
/* mark everything with argument flag */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
{
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
#ifdef HAVE_LOOP
|
||||
/* Give looped servers another chance */
|
||||
serv->flags &= ~SERV_LOOP;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup_servers(void)
|
||||
@@ -1283,6 +1326,11 @@ void cleanup_servers(void)
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
/* Now we have a new set of servers, test for loops. */
|
||||
loop_send_probes();
|
||||
#endif
|
||||
}
|
||||
|
||||
void add_update_server(int flags,
|
||||
@@ -1348,7 +1396,10 @@ void add_update_server(int flags,
|
||||
serv->domain = domain_str;
|
||||
serv->next = next;
|
||||
serv->queries = serv->failed_queries = 0;
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
if (domain)
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
|
||||
@@ -1427,6 +1478,10 @@ void check_servers(void)
|
||||
else if (!(serv->flags & SERV_LITERAL_ADDRESS))
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
|
||||
}
|
||||
#ifdef HAVE_LOOP
|
||||
else if (serv->flags & SERV_LOOP)
|
||||
my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port);
|
||||
#endif
|
||||
else if (serv->interface[0] != 0)
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
|
||||
else
|
||||
@@ -1522,13 +1577,13 @@ int reload_servers(char *fname)
|
||||
return gotone;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
|
||||
/* Called when addresses are added or deleted from an interface */
|
||||
void newaddress(time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
|
||||
daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
@@ -1546,7 +1601,6 @@ void newaddress(time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
257
src/option.c
257
src/option.c
@@ -64,85 +64,89 @@ struct myoption {
|
||||
#define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
|
||||
|
||||
/* options which don't have a one-char version */
|
||||
#define LOPT_RELOAD 256
|
||||
#define LOPT_NO_NAMES 257
|
||||
#define LOPT_TFTP 258
|
||||
#define LOPT_SECURE 259
|
||||
#define LOPT_PREFIX 260
|
||||
#define LOPT_PTR 261
|
||||
#define LOPT_BRIDGE 262
|
||||
#define LOPT_TFTP_MAX 263
|
||||
#define LOPT_FORCE 264
|
||||
#define LOPT_NOBLOCK 265
|
||||
#define LOPT_LOG_OPTS 266
|
||||
#define LOPT_MAX_LOGS 267
|
||||
#define LOPT_CIRCUIT 268
|
||||
#define LOPT_REMOTE 269
|
||||
#define LOPT_SUBSCR 270
|
||||
#define LOPT_INTNAME 271
|
||||
#define LOPT_BANK 272
|
||||
#define LOPT_DHCP_HOST 273
|
||||
#define LOPT_APREF 274
|
||||
#define LOPT_OVERRIDE 275
|
||||
#define LOPT_TFTPPORTS 276
|
||||
#define LOPT_REBIND 277
|
||||
#define LOPT_NOLAST 278
|
||||
#define LOPT_OPTS 279
|
||||
#define LOPT_DHCP_OPTS 280
|
||||
#define LOPT_MATCH 281
|
||||
#define LOPT_BROADCAST 282
|
||||
#define LOPT_NEGTTL 283
|
||||
#define LOPT_ALTPORT 284
|
||||
#define LOPT_SCRIPTUSR 285
|
||||
#define LOPT_LOCAL 286
|
||||
#define LOPT_NAPTR 287
|
||||
#define LOPT_MINPORT 288
|
||||
#define LOPT_DHCP_FQDN 289
|
||||
#define LOPT_CNAME 290
|
||||
#define LOPT_PXE_PROMT 291
|
||||
#define LOPT_PXE_SERV 292
|
||||
#define LOPT_TEST 293
|
||||
#define LOPT_TAG_IF 294
|
||||
#define LOPT_PROXY 295
|
||||
#define LOPT_GEN_NAMES 296
|
||||
#define LOPT_MAXTTL 297
|
||||
#define LOPT_NO_REBIND 298
|
||||
#define LOPT_LOC_REBND 299
|
||||
#define LOPT_ADD_MAC 300
|
||||
#define LOPT_DNSSEC 301
|
||||
#define LOPT_INCR_ADDR 302
|
||||
#define LOPT_CONNTRACK 303
|
||||
#define LOPT_FQDN 304
|
||||
#define LOPT_LUASCRIPT 305
|
||||
#define LOPT_RA 306
|
||||
#define LOPT_DUID 307
|
||||
#define LOPT_HOST_REC 308
|
||||
#define LOPT_TFTP_LC 309
|
||||
#define LOPT_RR 310
|
||||
#define LOPT_CLVERBIND 311
|
||||
#define LOPT_MAXCTTL 312
|
||||
#define LOPT_AUTHZONE 313
|
||||
#define LOPT_AUTHSERV 314
|
||||
#define LOPT_AUTHTTL 315
|
||||
#define LOPT_AUTHSOA 316
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#define LOPT_SYNTH 320
|
||||
#define LOPT_RELOAD 256
|
||||
#define LOPT_NO_NAMES 257
|
||||
#define LOPT_TFTP 258
|
||||
#define LOPT_SECURE 259
|
||||
#define LOPT_PREFIX 260
|
||||
#define LOPT_PTR 261
|
||||
#define LOPT_BRIDGE 262
|
||||
#define LOPT_TFTP_MAX 263
|
||||
#define LOPT_FORCE 264
|
||||
#define LOPT_NOBLOCK 265
|
||||
#define LOPT_LOG_OPTS 266
|
||||
#define LOPT_MAX_LOGS 267
|
||||
#define LOPT_CIRCUIT 268
|
||||
#define LOPT_REMOTE 269
|
||||
#define LOPT_SUBSCR 270
|
||||
#define LOPT_INTNAME 271
|
||||
#define LOPT_BANK 272
|
||||
#define LOPT_DHCP_HOST 273
|
||||
#define LOPT_APREF 274
|
||||
#define LOPT_OVERRIDE 275
|
||||
#define LOPT_TFTPPORTS 276
|
||||
#define LOPT_REBIND 277
|
||||
#define LOPT_NOLAST 278
|
||||
#define LOPT_OPTS 279
|
||||
#define LOPT_DHCP_OPTS 280
|
||||
#define LOPT_MATCH 281
|
||||
#define LOPT_BROADCAST 282
|
||||
#define LOPT_NEGTTL 283
|
||||
#define LOPT_ALTPORT 284
|
||||
#define LOPT_SCRIPTUSR 285
|
||||
#define LOPT_LOCAL 286
|
||||
#define LOPT_NAPTR 287
|
||||
#define LOPT_MINPORT 288
|
||||
#define LOPT_DHCP_FQDN 289
|
||||
#define LOPT_CNAME 290
|
||||
#define LOPT_PXE_PROMT 291
|
||||
#define LOPT_PXE_SERV 292
|
||||
#define LOPT_TEST 293
|
||||
#define LOPT_TAG_IF 294
|
||||
#define LOPT_PROXY 295
|
||||
#define LOPT_GEN_NAMES 296
|
||||
#define LOPT_MAXTTL 297
|
||||
#define LOPT_NO_REBIND 298
|
||||
#define LOPT_LOC_REBND 299
|
||||
#define LOPT_ADD_MAC 300
|
||||
#define LOPT_DNSSEC 301
|
||||
#define LOPT_INCR_ADDR 302
|
||||
#define LOPT_CONNTRACK 303
|
||||
#define LOPT_FQDN 304
|
||||
#define LOPT_LUASCRIPT 305
|
||||
#define LOPT_RA 306
|
||||
#define LOPT_DUID 307
|
||||
#define LOPT_HOST_REC 308
|
||||
#define LOPT_TFTP_LC 309
|
||||
#define LOPT_RR 310
|
||||
#define LOPT_CLVERBIND 311
|
||||
#define LOPT_MAXCTTL 312
|
||||
#define LOPT_AUTHZONE 313
|
||||
#define LOPT_AUTHSERV 314
|
||||
#define LOPT_AUTHTTL 315
|
||||
#define LOPT_AUTHSOA 316
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#define LOPT_SYNTH 320
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#endif
|
||||
#define LOPT_RELAY 323
|
||||
#define LOPT_RA_PARAM 324
|
||||
#define LOPT_ADD_SBNET 325
|
||||
#define LOPT_QUIET_DHCP 326
|
||||
#define LOPT_QUIET_DHCP6 327
|
||||
#define LOPT_QUIET_RA 328
|
||||
#define LOPT_SEC_VALID 329
|
||||
#define LOPT_TRUST_ANCHOR 330
|
||||
#define LOPT_DNSSEC_DEBUG 331
|
||||
#define LOPT_REV_SERV 332
|
||||
#define LOPT_SERVERS_FILE 333
|
||||
#define LOPT_RELAY 323
|
||||
#define LOPT_RA_PARAM 324
|
||||
#define LOPT_ADD_SBNET 325
|
||||
#define LOPT_QUIET_DHCP 326
|
||||
#define LOPT_QUIET_DHCP6 327
|
||||
#define LOPT_QUIET_RA 328
|
||||
#define LOPT_SEC_VALID 329
|
||||
#define LOPT_TRUST_ANCHOR 330
|
||||
#define LOPT_DNSSEC_DEBUG 331
|
||||
#define LOPT_REV_SERV 332
|
||||
#define LOPT_SERVERS_FILE 333
|
||||
#define LOPT_DNSSEC_CHECK 334
|
||||
#define LOPT_LOCAL_SERVICE 335
|
||||
#define LOPT_DNSSEC_TIME 336
|
||||
#define LOPT_LOOP_DETECT 337
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -174,6 +178,7 @@ static const struct myoption opts[] =
|
||||
{ "domain-suffix", 1, 0, 's' },
|
||||
{ "interface", 1, 0, 'i' },
|
||||
{ "listen-address", 1, 0, 'a' },
|
||||
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
|
||||
{ "bogus-priv", 0, 0, 'b' },
|
||||
{ "bogus-nxdomain", 1, 0, 'B' },
|
||||
{ "selfmx", 0, 0, 'e' },
|
||||
@@ -283,6 +288,8 @@ static const struct myoption opts[] =
|
||||
{ "dnssec", 0, 0, LOPT_SEC_VALID },
|
||||
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
|
||||
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
|
||||
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
@@ -291,6 +298,7 @@ static const struct myoption opts[] =
|
||||
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
|
||||
{ "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
|
||||
{ "quiet-ra", 0, 0, LOPT_QUIET_RA },
|
||||
{ "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -438,6 +446,8 @@ static struct {
|
||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
|
||||
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
|
||||
{ LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
#endif
|
||||
@@ -445,6 +455,8 @@ static struct {
|
||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
||||
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
|
||||
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
|
||||
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
|
||||
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops"), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -609,19 +621,24 @@ static int atoi_check8(char *a, int *res)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void add_txt(char *name, char *txt)
|
||||
static void add_txt(char *name, char *txt, int stat)
|
||||
{
|
||||
size_t len = strlen(txt);
|
||||
struct txt_record *r = opt_malloc(sizeof(struct txt_record));
|
||||
|
||||
if (txt)
|
||||
{
|
||||
size_t len = strlen(txt);
|
||||
r->txt = opt_malloc(len+1);
|
||||
r->len = len+1;
|
||||
*(r->txt) = len;
|
||||
memcpy((r->txt)+1, txt, len);
|
||||
}
|
||||
|
||||
r->stat = stat;
|
||||
r->name = opt_string_alloc(name);
|
||||
r->next = daemon->txt;
|
||||
daemon->txt = r;
|
||||
r->class = C_CHAOS;
|
||||
r->txt = opt_malloc(len+1);
|
||||
r->len = len+1;
|
||||
*(r->txt) = len;
|
||||
memcpy((r->txt)+1, txt, len);
|
||||
}
|
||||
|
||||
static void do_usage(void)
|
||||
@@ -1448,7 +1465,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
struct list {
|
||||
char *suffix;
|
||||
struct list *next;
|
||||
} *ignore_suffix = NULL, *li;
|
||||
} *ignore_suffix = NULL, *match_suffix = NULL, *li;
|
||||
|
||||
comma = split(arg);
|
||||
if (!(directory = opt_string_alloc(arg)))
|
||||
@@ -1458,10 +1475,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
comma = split(arg);
|
||||
li = opt_malloc(sizeof(struct list));
|
||||
li->next = ignore_suffix;
|
||||
ignore_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg);
|
||||
if (*arg == '*')
|
||||
{
|
||||
li->next = match_suffix;
|
||||
match_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
li->next = ignore_suffix;
|
||||
ignore_suffix = li;
|
||||
/* Have to copy: buffer is overwritten */
|
||||
li->suffix = opt_string_alloc(arg);
|
||||
}
|
||||
};
|
||||
|
||||
if (!(dir_stream = opendir(directory)))
|
||||
@@ -1479,6 +1506,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (match_suffix)
|
||||
{
|
||||
for (li = match_suffix; li; li = li->next)
|
||||
{
|
||||
/* check for required suffices */
|
||||
size_t ls = strlen(li->suffix);
|
||||
if (len > ls &&
|
||||
strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
|
||||
break;
|
||||
}
|
||||
if (!li)
|
||||
continue;
|
||||
}
|
||||
|
||||
for (li = ignore_suffix; li; li = li->next)
|
||||
{
|
||||
/* check for proscribed suffices */
|
||||
@@ -1658,7 +1699,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'H': /* --addn-hosts */
|
||||
{
|
||||
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
|
||||
static int hosts_index = 1;
|
||||
static unsigned int hosts_index = SRC_AH;
|
||||
new->fname = opt_string_alloc(arg);
|
||||
new->index = hosts_index++;
|
||||
new->flags = 0;
|
||||
@@ -2157,6 +2198,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
newlist = opt_malloc(sizeof(struct server));
|
||||
memset(newlist, 0, sizeof(struct server));
|
||||
#ifdef HAVE_LOOP
|
||||
newlist->uid = rand32();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (servers_only && option == 'S')
|
||||
@@ -2569,9 +2613,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (strcmp(a[leasepos], "static") == 0)
|
||||
new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
|
||||
else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
|
||||
new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
|
||||
new->flags |= CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "ra-names") == 0)
|
||||
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "ra-advrouter") == 0)
|
||||
new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
|
||||
else if (strcmp(a[leasepos], "ra-stateless") == 0)
|
||||
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
|
||||
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
|
||||
@@ -2601,7 +2647,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (new->prefix != 64)
|
||||
{
|
||||
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
if (new->flags & CONTEXT_RA)
|
||||
ret_err(_("prefix length must be exactly 64 for RA subnets"));
|
||||
else if (new->flags & CONTEXT_TEMPLATE)
|
||||
ret_err(_("prefix length must be exactly 64 for subnet constructors"));
|
||||
@@ -3603,7 +3649,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->txt;
|
||||
daemon->txt = new;
|
||||
new->class = C_IN;
|
||||
|
||||
new->stat = 0;
|
||||
|
||||
if (!(new->name = canonicalise_opt(arg)))
|
||||
ret_err(_("bad TXT record"));
|
||||
|
||||
@@ -4014,10 +4061,11 @@ static int one_file(char *file, int hard_opt)
|
||||
/* expand any name which is a directory */
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (i = 0, ah = list; ah; ah = ah->next)
|
||||
/* find largest used index */
|
||||
for (i = SRC_AH, ah = list; ah; ah = ah->next)
|
||||
{
|
||||
if (i <= ah->index)
|
||||
i = ah->index + 1;
|
||||
@@ -4251,9 +4299,19 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_refresh = SOA_REFRESH;
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
add_txt("version.bind", "dnsmasq-" VERSION );
|
||||
add_txt("authors.bind", "Simon Kelley");
|
||||
add_txt("copyright.bind", COPYRIGHT);
|
||||
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
add_txt("authors.bind", "Simon Kelley", 0);
|
||||
add_txt("copyright.bind", COPYRIGHT, 0);
|
||||
add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
|
||||
add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
|
||||
add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
|
||||
add_txt("misses.bind", NULL, TXT_STAT_MISSES);
|
||||
add_txt("hits.bind", NULL, TXT_STAT_HITS);
|
||||
#ifdef HAVE_AUTH
|
||||
add_txt("auth.bind", NULL, TXT_STAT_AUTH);
|
||||
#endif
|
||||
add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -4454,6 +4512,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
else if (option_bool(OPT_DHCP_FQDN))
|
||||
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
|
||||
|
||||
/* If there's access-control config, then ignore --local-service, it's intended
|
||||
as a system default to keep otherwise unconfigured installations safe. */
|
||||
if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
|
||||
reset_option_bool(OPT_LOCAL_SERVICE);
|
||||
|
||||
if (testmode)
|
||||
{
|
||||
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
|
||||
|
||||
@@ -49,6 +49,8 @@ struct prefix_opt {
|
||||
#define ICMP6_OPT_SOURCE_MAC 1
|
||||
#define ICMP6_OPT_PREFIX 3
|
||||
#define ICMP6_OPT_MTU 5
|
||||
#define ICMP6_OPT_ADV_INTERVAL 7
|
||||
#define ICMP6_OPT_RT_INFO 24
|
||||
#define ICMP6_OPT_RDNSS 25
|
||||
#define ICMP6_OPT_DNSSL 31
|
||||
|
||||
|
||||
71
src/radv.c
71
src/radv.c
@@ -28,11 +28,11 @@
|
||||
|
||||
struct ra_param {
|
||||
time_t now;
|
||||
int ind, managed, other, found_context, first;
|
||||
int ind, managed, other, found_context, first, adv_router;
|
||||
char *if_name;
|
||||
struct dhcp_netid *tags;
|
||||
struct in6_addr link_local, link_global, ula;
|
||||
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval;
|
||||
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
|
||||
};
|
||||
|
||||
struct search_param {
|
||||
@@ -210,28 +210,30 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
FILE *f;
|
||||
#endif
|
||||
|
||||
|
||||
parm.ind = iface;
|
||||
parm.managed = 0;
|
||||
parm.other = 0;
|
||||
parm.found_context = 0;
|
||||
parm.adv_router = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
parm.now = now;
|
||||
parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
|
||||
parm.adv_interval = calc_interval(ra_param);
|
||||
parm.prio = calc_prio(ra_param);
|
||||
|
||||
save_counter(0);
|
||||
ra = expand(sizeof(struct ra_packet));
|
||||
|
||||
ra->type = ND_ROUTER_ADVERT;
|
||||
ra->code = 0;
|
||||
ra->hop_limit = hop_limit;
|
||||
ra->flags = calc_prio(ra_param);
|
||||
ra->flags = parm.prio;
|
||||
ra->lifetime = htons(calc_lifetime(ra_param));
|
||||
ra->reachable_time = 0;
|
||||
ra->retrans_time = 0;
|
||||
|
||||
parm.ind = iface;
|
||||
parm.managed = 0;
|
||||
parm.other = 0;
|
||||
parm.found_context = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
parm.now = now;
|
||||
parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
|
||||
parm.adv_interval = calc_interval(ra_param);
|
||||
|
||||
/* set tag with name == interface */
|
||||
iface_id.net = iface_name;
|
||||
iface_id.next = NULL;
|
||||
@@ -286,8 +288,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
|
||||
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
if (context->flags & CONTEXT_RA)
|
||||
{
|
||||
do_slaac = 1;
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
@@ -339,6 +340,17 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
if (!old_prefix && !parm.found_context)
|
||||
return;
|
||||
|
||||
/* If we're sending router address instead of prefix in at least on prefix,
|
||||
include the advertisement interval option. */
|
||||
if (parm.adv_router)
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
|
||||
put_opt6_char(1);
|
||||
put_opt6_short(0);
|
||||
/* interval value is in milliseconds */
|
||||
put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
@@ -500,6 +512,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int do_slaac = 0;
|
||||
int deprecate = 0;
|
||||
int constructed = 0;
|
||||
int adv_router = 0;
|
||||
unsigned int time = 0xffffffff;
|
||||
struct dhcp_context *context;
|
||||
|
||||
@@ -511,8 +524,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
{
|
||||
context->saved_valid = valid;
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
if (context->flags & CONTEXT_RA)
|
||||
{
|
||||
do_slaac = 1;
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
@@ -530,7 +542,17 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->managed = 1;
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Configured to advertise router address, not prefix. See RFC 3775 7.2
|
||||
In this case we do all addresses associated with a context,
|
||||
hence the real_prefix setting here. */
|
||||
if (context->flags & CONTEXT_RA_ROUTER)
|
||||
{
|
||||
adv_router = 1;
|
||||
param->adv_router = 1;
|
||||
real_prefix = context->prefix;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
{
|
||||
@@ -556,7 +578,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
/* subsequent prefixes on the same interface
|
||||
and subsequent instances of this prefix don't need timers.
|
||||
Be careful not to find the same prefix twice with different
|
||||
addresses. */
|
||||
addresses unless we're advertising the actual addresses. */
|
||||
if (!(context->flags & CONTEXT_RA_DONE))
|
||||
{
|
||||
if (!param->first)
|
||||
@@ -607,13 +629,18 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
/* zero net part of address */
|
||||
setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
|
||||
if (!adv_router)
|
||||
setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
|
||||
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = real_prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
opt->flags = 0x80;
|
||||
if (do_slaac)
|
||||
opt->flags |= 0x40;
|
||||
if (adv_router)
|
||||
opt->flags |= 0x20;
|
||||
opt->valid_lifetime = htonl(valid);
|
||||
opt->preferred_lifetime = htonl(preferred);
|
||||
opt->reserved = 0;
|
||||
|
||||
@@ -601,11 +601,11 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
|
||||
|
||||
if (family == parm->l3->sa.sa_family)
|
||||
{
|
||||
if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
match = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
match = 1;
|
||||
#endif
|
||||
}
|
||||
@@ -917,8 +917,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name, doctored);
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (*doctored)
|
||||
secure = 0;
|
||||
if (*doctored && secure)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -927,7 +927,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
int found = 0, cname_count = 5;
|
||||
int found = 0, cname_count = CNAME_CHAIN;
|
||||
struct crec *cpp = NULL;
|
||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
int secflag = secure ? F_DNSSECOK : 0;
|
||||
@@ -988,9 +988,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count--)
|
||||
return 0; /* looped CNAMES */
|
||||
secflag = 0; /* no longer DNSSEC */
|
||||
if (!cname_count-- || secure)
|
||||
return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
|
||||
goto cname_loop;
|
||||
}
|
||||
|
||||
@@ -1066,6 +1065,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (newc)
|
||||
{
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
/* anything other than zero, to avoid being mistaken for CNAME to interface-name */
|
||||
newc->addr.cname.uid = 1;
|
||||
if (cpp)
|
||||
{
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
@@ -1101,7 +1102,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
ipsets_cur = ipsets;
|
||||
while (*ipsets_cur)
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
{
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1242,7 +1246,12 @@ int check_for_local_domain(char *name, time_t now)
|
||||
struct ptr_record *ptr;
|
||||
struct naptr *naptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
|
||||
/* Note: the call to cache_find_by_name is intended to find any record which matches
|
||||
ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
|
||||
cache_find_by name ordinarily only returns records with an exact match on those bits (ie
|
||||
for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
return 1;
|
||||
|
||||
@@ -1453,11 +1462,11 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int *ad_reqd)
|
||||
time_t now, int *ad_reqd, int *do_bit)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
int qtype, qclass;
|
||||
unsigned int qtype, qclass;
|
||||
struct all_addr addr;
|
||||
int nameoffset;
|
||||
unsigned short flag;
|
||||
@@ -1475,7 +1484,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
/* RFC 6840 5.7 */
|
||||
*ad_reqd = header->hb4 & HB4_AD;
|
||||
|
||||
*do_bit = 0;
|
||||
|
||||
/* If there is an RFC2671 pseudoheader then it will be overwritten by
|
||||
partial replies, so we have to do a dry run to see if we can answer
|
||||
the query. We check to see if the do bit is set, if so we always
|
||||
@@ -1493,7 +1503,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
pheader += 2; /* ext_rcode */
|
||||
GETSHORT(flags, pheader);
|
||||
|
||||
sec_reqd = flags & 0x8000; /* do bit */
|
||||
if ((sec_reqd = flags & 0x8000))
|
||||
*do_bit = 1;/* do bit */
|
||||
*ad_reqd = 1;
|
||||
|
||||
/* If our client is advertising a larger UDP packet size
|
||||
@@ -1544,10 +1555,20 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl = daemon->local_ttl;
|
||||
int ok = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
/* Dynamically generate stat record */
|
||||
if (t->stat != 0)
|
||||
{
|
||||
ttl = 0;
|
||||
if (!cache_make_stat(t))
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
@@ -1578,19 +1599,29 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
|
||||
if (crecp->uid == qclass)
|
||||
{
|
||||
gotone = 1;
|
||||
if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
|
||||
{
|
||||
struct all_addr a;
|
||||
a.addr.keytag = crecp->addr.ds.keytag;
|
||||
log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_DS, qclass, "sbbt",
|
||||
crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
gotone = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
log_query(F_UPSTREAM, name, NULL, "secure no DS");
|
||||
}
|
||||
else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
|
||||
{
|
||||
struct all_addr a;
|
||||
a.addr.keytag = crecp->addr.ds.keytag;
|
||||
log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_DS, qclass, "sbbt",
|
||||
crecp->addr.ds.keytag, crecp->addr.ds.algo,
|
||||
crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* DNSKEY */
|
||||
@@ -2005,7 +2036,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
strcpy(name, cname_target);
|
||||
/* check if target interface_name */
|
||||
if (crecp->addr.cname.uid == -1)
|
||||
if (crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
goto intname_restart;
|
||||
else
|
||||
goto cname_restart;
|
||||
|
||||
@@ -962,6 +962,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
case DHCPDISCOVER:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
{
|
||||
if (option_bool(OPT_QUIET_DHCP))
|
||||
return 0;
|
||||
message = _("ignored");
|
||||
opt = NULL;
|
||||
}
|
||||
|
||||
@@ -313,8 +313,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
else if (msg_type != DHCP6IREQ)
|
||||
return 0;
|
||||
|
||||
/* server-id must match except for SOLICIT and CONFIRM messages */
|
||||
if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ &&
|
||||
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
|
||||
if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
|
||||
(!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
|
||||
opt6_len(opt) != daemon->duid_len ||
|
||||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
|
||||
@@ -328,6 +328,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
|
||||
|
||||
{
|
||||
*outmsgtypep = DHCP6REPLY;
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6USEMULTI);
|
||||
put_opt6_string("Use multicast");
|
||||
@@ -1039,6 +1040,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
case DHCP6CONFIRM:
|
||||
{
|
||||
int good_addr = 0;
|
||||
|
||||
/* set reply message type */
|
||||
*outmsgtypep = DHCP6REPLY;
|
||||
|
||||
@@ -1063,9 +1066,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
return 1;
|
||||
}
|
||||
|
||||
good_addr = 1;
|
||||
log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
|
||||
}
|
||||
}
|
||||
|
||||
/* No addresses, no reply: RFC 3315 18.2.2 */
|
||||
if (!good_addr)
|
||||
return 0;
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6SUCCESS );
|
||||
@@ -1232,6 +1240,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We must anwser with 'success' in global section anyway */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6SUCCESS);
|
||||
put_opt6_string(_("success"));
|
||||
end_opt6(o1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
169
src/tables.c
Normal file
169
src/tables.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/* tables.c is Copyright (c) 2014 Sven Falempin All Rights Reserved.
|
||||
|
||||
Author's email: sfalempin@citypassenger.com
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
static char *pf_device = "/dev/pf";
|
||||
static int dev = -1;
|
||||
|
||||
static char *pfr_strerror(int errnum)
|
||||
{
|
||||
switch (errnum)
|
||||
{
|
||||
case ESRCH:
|
||||
return "Table does not exist";
|
||||
case ENOENT:
|
||||
return "Anchor or Ruleset does not exist";
|
||||
default:
|
||||
return strerror(errnum);
|
||||
}
|
||||
}
|
||||
|
||||
static int pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size < 0 || (size && tbl == NULL))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRADDTABLES, &io))
|
||||
return (-1);
|
||||
if (nadd != NULL)
|
||||
*nadd = io.pfrio_nadd;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fill_addr(const struct all_addr *ipaddr, int flags, struct pfr_addr* addr) {
|
||||
if ( !addr || !ipaddr)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("error: fill_addr missused"));
|
||||
return -1;
|
||||
}
|
||||
bzero(addr, sizeof(*addr));
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
addr->pfra_af = AF_INET6;
|
||||
addr->pfra_net = 0x80;
|
||||
memcpy(&(addr->pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
addr->pfra_af = AF_INET;
|
||||
addr->pfra_net = 0x20;
|
||||
addr->pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void ipset_init(void)
|
||||
{
|
||||
dev = open( pf_device, O_RDWR);
|
||||
if (dev == -1)
|
||||
{
|
||||
err(1, "%s", pf_device);
|
||||
die (_("failed to access pf devices: %s"), NULL, EC_MISC);
|
||||
}
|
||||
}
|
||||
|
||||
int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
int flags, int remove)
|
||||
{
|
||||
struct pfr_addr addr;
|
||||
struct pfioc_table io;
|
||||
struct pfr_table table;
|
||||
int n = 0, rc = 0;
|
||||
|
||||
if ( dev == -1 )
|
||||
{
|
||||
my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bzero(&table, sizeof(struct pfr_table));
|
||||
table.pfrt_flags |= PFR_TFLAG_PERSIST;
|
||||
if ( strlen(setname) >= PF_TABLE_NAME_SIZE )
|
||||
{
|
||||
my_syslog(LOG_ERR, _("error: cannot use table name %s"), setname);
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( strlcpy(table.pfrt_name, setname,
|
||||
sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("error: cannot strlcpy table name %s"), setname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc = pfr_add_tables(&table, 1, &n, 0))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"),
|
||||
pfr_strerror(errno),rc);
|
||||
return -1;
|
||||
}
|
||||
table.pfrt_flags &= ~PFR_TFLAG_PERSIST;
|
||||
if (n)
|
||||
my_syslog(LOG_INFO, _("info: table created"));
|
||||
|
||||
fill_addr(ipaddr,flags,&addr);
|
||||
bzero(&io, sizeof(io));
|
||||
io.pfrio_flags = 0;
|
||||
io.pfrio_table = table;
|
||||
io.pfrio_buffer = &addr;
|
||||
io.pfrio_esize = sizeof(addr);
|
||||
io.pfrio_size = 1;
|
||||
if (ioctl(dev, ( remove ? DIOCRDELADDRS : DIOCRADDADDRS ), &io))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("warning: DIOCR%sADDRS: %s"), ( remove ? "DEL" : "ADD" ), pfr_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("%d addresses %s"),
|
||||
io.pfrio_nadd, ( remove ? "removed" : "added" ));
|
||||
|
||||
return io.pfrio_nadd;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
60
src/util.c
60
src/util.c
@@ -81,6 +81,18 @@ unsigned short rand16(void)
|
||||
return (unsigned short) out[--outleft];
|
||||
}
|
||||
|
||||
u32 rand32(void)
|
||||
{
|
||||
if (!outleft)
|
||||
{
|
||||
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
|
||||
surf();
|
||||
outleft = 8;
|
||||
}
|
||||
|
||||
return out[--outleft];
|
||||
}
|
||||
|
||||
u64 rand64(void)
|
||||
{
|
||||
static int outleft = 0;
|
||||
@@ -319,6 +331,19 @@ time_t dnsmasq_time(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int netmask_length(struct in_addr mask)
|
||||
{
|
||||
int zero_count = 0;
|
||||
|
||||
while (0x0 == (mask.s_addr & 0x1) && zero_count < 32)
|
||||
{
|
||||
mask.s_addr >>= 1;
|
||||
zero_count++;
|
||||
}
|
||||
|
||||
return 32 - zero_count;
|
||||
}
|
||||
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
{
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
@@ -545,18 +570,28 @@ void bump_maxfd(int fd, int *max)
|
||||
|
||||
int retry_send(void)
|
||||
{
|
||||
struct timespec waiter;
|
||||
/* Linux kernels can return EAGAIN in perpetuity when calling
|
||||
sendmsg() and the relevant interface has gone. Here we loop
|
||||
retrying in EAGAIN for 1 second max, to avoid this hanging
|
||||
dnsmasq. */
|
||||
|
||||
static int retries = 0;
|
||||
struct timespec waiter;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
{
|
||||
waiter.tv_sec = 0;
|
||||
waiter.tv_nsec = 10000;
|
||||
nanosleep(&waiter, NULL);
|
||||
return 1;
|
||||
if (retries++ < 1000)
|
||||
return 1;
|
||||
}
|
||||
|
||||
retries = 0;
|
||||
|
||||
if (errno == EINTR)
|
||||
return 1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -602,3 +637,22 @@ int wildcard_match(const char* wildcard, const char* match)
|
||||
|
||||
return *wildcard == *match;
|
||||
}
|
||||
|
||||
/* The same but comparing a maximum of NUM characters, like strncmp. */
|
||||
int wildcard_matchn(const char* wildcard, const char* match, int num)
|
||||
{
|
||||
while (*wildcard && *match && num)
|
||||
{
|
||||
if (*wildcard == '*')
|
||||
return 1;
|
||||
|
||||
if (*wildcard != *match)
|
||||
return 0;
|
||||
|
||||
++wildcard;
|
||||
++match;
|
||||
--num;
|
||||
}
|
||||
|
||||
return (!num) || (*wildcard == *match);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user