Compare commits

...

39 Commits

Author SHA1 Message Date
Simon Kelley
efff74c1ae Tweak logging introduced in 3a8b0f6fcc 2017-04-28 23:01:23 +01:00
Simon Kelley
a9df0e30b0 Revert "Implement RFC-6842 (Client-ids in DHCP replies.)"
This reverts commit 88a77a78ad.

A least one client has been found which breaks with this change. Since
the use-case is not clear, I'm reverting the change, at least for now.
2017-04-28 22:44:24 +01:00
Simon Kelley
5ce3e76fbf DHCPv4: do ICMP-ping check in all cases other that current lease. 2017-04-28 22:14:20 +01:00
Vladislav Grishenko
6ec5f5c427 Extend --ra-param mtu: field to allow an interface name. 2017-04-24 22:34:45 +01:00
Vladislav Grishenko
5a7212c70e Make --rev-server work in the presence of --bogus-priv. 2017-04-24 22:21:04 +01:00
Petr Menšík
3a8b0f6fcc Improve error handling with shcp-script "init" mode. 2017-04-23 14:12:37 +01:00
Simon Kelley
a24c31e023 Debian: enable PIE and BINDNOW hardening in build. 2017-04-16 22:45:53 +01:00
Simon Kelley
f5a3679f1d Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2017-04-16 22:27:51 +01:00
Simon Kelley
5ac813cb86 Bump Lua version to 5.2. 2017-04-16 20:47:11 +01:00
Simon Kelley
a93b02e321 Compile option string: show script-support independent of DHCP. 2017-04-16 20:38:22 +01:00
Petr Menšík
c77fb9d8f0 Capture and log STDOUT and STDERR output from dhcp-script. 2017-04-16 20:20:08 +01:00
Simon Kelley
facc18f2a8 Bump Debian standards version. 2017-04-11 18:52:36 +01:00
Simon Kelley
bc515b71ec Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2017-04-11 18:49:59 +01:00
Simon Kelley
7bfa26399b FreeBSD compilation tweak. 2017-04-11 18:49:27 +01:00
Simon Kelley
461b7b43b4 Debian: readme typos. 2017-04-11 18:06:13 +01:00
Simon Kelley
b1cefa57f1 Debian: strip dhcp_release6 binary. 2017-04-11 15:55:26 +01:00
Simon Kelley
ce9a9704c6 Debian: add lsb-base dep. 2017-04-11 15:34:25 +01:00
Simon Kelley
93a9a55055 Debian changelog format fixup. 2017-04-11 15:21:30 +01:00
Simon Kelley
44eb875a5a Handle change in format of Debian /usr/share/dns/root.ds. 2017-04-11 15:13:09 +01:00
Floris Bos
bc87e609c2 Debian initscript tweak.
Dnsmasq's startup script seems to assume users always want to use
dnsmasq as local DNS resolver, and tells resolvconf to put
"nameserver 127.0.0.1" in /etc/resolv.conf
The problem with this is that if users just want to use dnsmasq
as DHCP server, and put port=0 in /etc/dnsmasq.conf to disable
the DNS functionality, they end up with broken name resolving.

Put a basic check in the startup script that skips resolvconf
configuration if a line starting with port=0 is in /etc/dnsmasq.conf
This doesn't cover all cases (e.g. configuration could also be in
different file in /etc/dnsmasq.d), but is better than current
situation.
2017-04-11 14:19:57 +01:00
David Flamand
005c46d6f5 Add mtu facility to --ra-param. 2017-04-11 11:49:54 +01:00
Floris Bos
503c609149 --dhcp-reply-delay option to workaround PXE client bugs.
Adds option to delay replying to DHCP packets by one or more seconds.
This provides a workaround for a PXE boot firmware implementation
that has a bug causing it to fail if it receives a (proxy) DHCP
reply instantly.

On Linux it looks up the exact receive time of the UDP packet with
the SIOCGSTAMP ioctl to prevent multiple delays if multiple packets
come in around the same time.
2017-04-09 23:07:13 +01:00
Floris Bos
60704f5e2e Add support for unique TFTP root per MAC.
It is currently only possible to let the TFTP server serve a different
folder depending on the client's IP address.
However it isn't always possible to predict what the client's
IP address will be, especially in situations in which we are not
responsible for handing them out (e.g. proxy dhcp setups).

Extend the current --tftp-unique-root parameter to support having a
separate folder per MAC address instead.
2017-04-09 22:22:49 +01:00
Kristian Evensen
4e7694d710 Allow binding to both source address and interface in server specs.
The current --server syntax allows for binding to interface or
address. However, in some (admittedly special) cases it is useful to
be able to specify both. This commit introduces the following syntax
to support binding to both interface and address:

--server X.X.X.X@IP@interface#port

Based on my tests, the syntax is backwards compatible with the current
@IP/interface#port. The code will fail if two interface names are given.

v1->v2:
* Add man page description of the extended server syntax (thanks Simon Kelley)

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
2017-03-22 21:32:50 +00:00
James Bottomley
e33b48700e When forwarding a query to a non-DNSSEC nameserver, don't verify the lack of DNSSEC.
The man page says that we don't do DNSSEC on forwarded domains, but if
you turn on dnssec_check_signatures this turns out to be untrue,
because we try to build up a DS chain to them.  Since forwarded domains
are usually used for split DNS to hidden domains, they're unlikely to
verify to the DNS root anyway, so the way to do DNSSEC for them (as the
manual says) is to provide a trust anchor for each forwarder.

The problem I've run into is a split DNS setup where I want DNSSEC to
work mostly, but one of the forwarding domains doesn't have an internal
DNSSEC capable resolver. Without this patch the entire domain goes
unresolvable because the DS record query to the internal resolver
returns a failure which is interpreted as the domain being BOGUS.

The fix is not to do the DS record chase for forwarded domains.
2017-03-17 21:44:10 +00:00
Petr Menšík
ad59f278c6 Fix man page re interface labels and add warning when used badly. 2017-03-17 17:22:19 +00:00
Bert Gijsbers
16f03e7139 Check for failure of "git describe" in get-version. 2017-03-06 23:07:32 +00:00
Olivier Gayot
dc99058d83 Improve error checking for --rev-server.
The rev-server directive only handles the following CIDR prefixes
properly: /8, /16, /24, /32.

Any other value was silently converted to /16 which could result in
unexpected behaviour.

This patch rejects any other value instead of making a silent
conversion.
2017-03-06 22:17:21 +00:00
Olivier Gayot
916959c188 Fix rev-server with /32 prefix.
[ excerpt from the man page ]
The rev-server directive provides a syntactic sugar to make specifying
address-to-name queries easier. For example
--rev-server=1.2.3.0/24,192.168.0.1 is exactly equivalent to
--server=/3.2.1.in-addr.arpa/192.168.0.1

It is not mentioned in the man page but the only prefixes that the
directive properly handles when dealing with IPv4 are /8, /16 and /24.
Specifying anything else as the same effect as specifying /16.

It is not a big deal for subnets on non-octet boundaries since they
cannot be represented using a single in-addr.arpa address. However, it
is unconvenient for /32 prefix while the analogous server directive
behaves as expected. E.g. the following server directive work
as expected:

    server=/42.10.168.192.in-addr.arpa/1.2.3.4

but the following does not:

    rev-server=192.168.10.42/32,1.2.3.4

and, in practice, the later behaves the same as:

    server=/168.192.in-addr.arpa/1.2.3.4

This strange behaviour is fixed by accepting /32 CIDR prefixes as a
valid value. Any other value will still be considered the same as /16.
2017-03-06 22:14:50 +00:00
Simon Kelley
864913c0f3 Man page typo. 2017-02-28 18:07:18 +00:00
Simon Kelley
13dee6f49e Compilation warning fixes. 2017-02-28 16:51:58 +00:00
Simon Kelley
62f9c0d470 Fix CNAME wildcard in auth-mode.
A domain can only have a CNAME if it has not other records.

Don't return a CNAME when there are records of other types on the name.
2017-02-19 23:07:01 +00:00
Simon Kelley
54bb3639d4 Update FAQ to fix a couple of dead links.
Thanks to Federico Bianchi for reporting this.
2017-02-19 22:13:36 +00:00
Simon Kelley
fca008d8d4 Make --bogus-priv apply to IPv6. 2017-02-19 18:50:41 +00:00
klemens
43517fcaf5 Spelling fixes. 2017-02-19 15:53:37 +00:00
Simon Kelley
88a77a78ad Implement RFC-6842 (Client-ids in DHCP replies.) 2017-02-11 17:02:02 +00:00
Hannu Nyman
3e2496fb16 Decrease the number of individual sites listed in log.
By default 30 first servers are listed individually to system log, and
then a count of the remaining items. With e.g. a NXDOMAIN based adblock
service, dnsmasq lists 30 unnecessary ad sites every time when dnsmasq
evaluates the list. But the actual nameservers in use are evaluated last
and are not displayed as they get included in the "remaining items" total.

Handle the "local addresses only" separately and list only a few of them.
Remove the "local addresses only" from the general count.
2017-02-11 13:44:08 +00:00
Simon Kelley
05da782f8f Add forthcoming 2017 root zone trust anchor to trust-anchors.conf. 2017-02-10 21:32:45 +00:00
Simon Kelley
361dfe5158 Improve connection handling when talking to TCP upsteam servers.
Specifically, be prepared to open a new connection when we
want to make multiple queries but the upstream server accepts
fewer queries per connection.
2017-02-10 21:12:30 +00:00
32 changed files with 998 additions and 455 deletions

View File

@@ -51,7 +51,7 @@ version 2.77
Add DNSMASQ_REQUESTED_OPTIONS environment variable to the
lease-change script. Thanks to ZHAO Yu for the patch.
Fix foobar in rrfilter code, that could cause misformed
Fix foobar in rrfilter code, that could cause malformed
replies, especially when DNSSEC validation on, and
the upstream server returns answer with the RRs in a
particular order. The only DNS server known to tickle
@@ -65,14 +65,59 @@ version 2.77
Thanks to Kevin Darbyshire-Bryant and Eric Luehrsen
for pushing this.
Improve connection handling when talking to TCP upstream
servers. Specifically, be prepared to open a new TCP
connection when we want to make multiple queries
but the upstream server accepts fewer queries per connection.
Improve logging of upstream servers when there are a lot
of "local addresses only" entries. Thanks to Hannu Nyman for
the patch.
Make --bogus-priv apply to IPv6, for the prefixes specified
in RFC6303. Thanks to Kevin Darbyshire-Bryant for work on this.
Allow use of MAC addresses with --tftp-unique-root. Thanks
to Floris Bos for the patch.
Add --dhcp-reply-delay option. Thanks to Floris Bos
for the patch.
Add mtu setting facility to --ra-param. Thanks to David
Flamand for the patch.
Capture STDOUT and STDERR output from dhcp-script and log
it as part of the dnsmasq log stream. Makes life easier
for diagnosing unexpected problems in scripts.
Thanks to Petr Mensik for the patch.
Generate fatal errors when failing to parse the output
of the dhcp-script in "init" mode. Avoids strange errors
when the script accidentally emits error messages.
Thanks to Petr Mensik for the patch.
Make --rev-server for an RFC1918 subnet work even in the
presence of the --bogus-priv flag. Thanks to
Vladislav Grishenko for the patch.
Extend --ra-param mtu: field to allow an interface name.
This allows the MTU of a WAN interface to be advertised on
the internal interfaces of a router. Thanks to
Vladislav Grishenko for the patch.
Do ICMP-ping check for address-in-use for DHCPv4 when
the client specifies an address in DHCPDISCOVER, and when
an address in configured locally. Thanks to Alin Năstac
for spotting the problem.
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
translates to hosts on the local network, or, at
least, 0.0.0.0 accesses the local host, so could
be targets for DNS rebinding. See RFC 5735 section 3
for details. Thanks to Stephen Röttger for the bug report.
Enhance --add-subnet to allow arbitrary subnet addresses.
Thanks to Ed Barsley for the patch.
@@ -456,7 +501,7 @@ version 2.69
conf-file=/path/to/trust-anchors.conf
dnssec
to your config is all thats needed to get things
to your config is all that's needed to get things
working. The upstream nameservers have to be DNSSEC-capable
too, of course. Many ISP nameservers aren't, but the
Google public nameservers (8.8.8.8 and 8.8.4.4) are.
@@ -644,7 +689,7 @@ version 2.67
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
report.
Increase timeout/number of retries in TFTP to accomodate
Increase timeout/number of retries in TFTP to accommodate
AudioCodes Voice Gateways doing streaming writes to flash.
Thanks to Damian Kaczkowski for spotting the problem.
@@ -912,7 +957,7 @@ version 2.63
still-born attempt to allow automatic isolated
configuration by libvirt, but have never (to my knowledge)
been used, had very strange semantics, and have been
superceded by other mechanisms.
superseded by other mechanisms.
Fixed bug logging filenames when duplicate dhcp-host
addresses are found. Thanks to John Hanks for the patch.
@@ -945,7 +990,7 @@ version 2.63
version 2.62
Update German translation. Thanks to Conrad Kostecki.
Cope with router-solict packets wich don't have a valid
Cope with router-solict packets which don't have a valid
source address. Thanks to Vladislav Grishenko for the patch.
Fixed bug which caused missing periodic router
@@ -1199,7 +1244,7 @@ version 2.58
Relax the need to supply a netmask in --dhcp-range for
networks which use a DHCP relay. Whilst this is still
desireable, in the absence of a netmask dnsmasq will use
desirable, in the absence of a netmask dnsmasq will use
a default based on the class (A, B, or C) of the address.
This should at least remove a cause of mysterious failure
for people using RFC1918 addresses and relays.
@@ -1313,7 +1358,7 @@ version 2.56
Add --add-mac option. This is to support currently
experimental DNS filtering facilities. Thanks to Benjamin
Petrin for the orignal patch.
Petrin for the original patch.
Fix bug which meant that tags were ignored in dhcp-range
configuration specifying PXE-proxy service. Thanks to

View File

@@ -78,7 +78,7 @@ release 0.98 Some enhancements and bug-fixes.
ids, to thwart DNS spoofers.
(7) Dnsmasq no longer forwards queries when the
"recursion desired" bit is not set in the header.
(8) Fixed getopt code to work on compliers with unsigned char.
(8) Fixed getopt code to work on compilers with unsigned char.
release 0.991 Added -b flag: when set causes dnsmasq to always answer
reverse queries on the RFC 1918 private IP space itself and
@@ -319,7 +319,7 @@ release 1.9 Fixes to rpm .spec files.
uClinux. Thanks to Matthew Natalier for uClinux stuff.
release 1.10 Log warnings if resolv.conf or dhcp.leases are not
accessable for any reason, as suggested by Hinrich Eilts.
accessible for any reason, as suggested by Hinrich Eilts.
Fixed wrong address printing in error message about
no interface with address.
@@ -975,7 +975,7 @@ release 2.8
configuration. Specifically: (1) options are matched on
the netids from dhcp-range, dhcp-host, vendor class and
user class(es). Multiple net-ids are allowed and options
are searched on them all. (2) matches agains vendor class
are searched on them all. (2) matches against vendor class
and user class are now on a substring, if the given
string is a substring of the vendor/user class, then a
match occurs. Thanks again to Richard Musil for prompting
@@ -1019,7 +1019,7 @@ release 2.9
broken. The new algorithm is to pick as before for the
first try, but if a query is retried, to send to all
available servers in parallel. The first one to reply
then becomes prefered for the next query. This should
then becomes preferred for the next query. This should
improve reliability without generating significant extra
upstream load.
@@ -1229,7 +1229,7 @@ version 2.16
Set NONBLOCK on all listening sockets to workaround non-POSIX
compliance in Linux 2.4 and 2.6. This fixes rare hangs which
occured when corrupted packets were received. Thanks to
occurred when corrupted packets were received. Thanks to
Joris van Rantwijk for chasing that down.
Updated config.h for NetBSD. Thanks to Martin Lambers.
@@ -1297,7 +1297,7 @@ version 2.18
interfaces with more than one IPv6 address. Thanks to
Martin Pels for help with that.
Fix problems which occured when more than one dhcp-range
Fix problems which occurred when more than one dhcp-range
was specified in the same subnet: sometimes parameters
(lease time, network-id tag) from the wrong one would be
used. Thanks to Rory Campbell-Lange for the bug report.
@@ -1740,7 +1740,7 @@ version 2.28
Fixed regression in netlink code under 2.2.x kernels which
occurred in 2.27. Erik Jan Tromp is the vintage kernel fan
who found this. P.S. It looks like this "netlink bind:
permission denied" problem occured in kernels at least as
permission denied" problem occurred in kernels at least as
late a 2.4.18. Good information from Alain Richoux.
Added a warning when it's impossible to give a host its

62
FAQ
View File

@@ -156,7 +156,7 @@ A: [note: this was written in September 2003, things may well change.]
If you get "jlsdajkdalld.com" does not exist, then all is fine, if
host returns an IP address, then the DNS is broken. (Try a few
different unlikely domains, just in case you picked a wierd one
different unlikely domains, just in case you picked a weird one
which really _is_ registered.)
Assuming that your DNS is broken, and you want to fix it, simply
@@ -320,8 +320,18 @@ A: Yes, new releases of dnsmasq are always announced through
Q: What does the dhcp-authoritative option do?
A: See http://www.isc.org/files/auth.html - that's
for the ISC daemon, but the same applies to dnsmasq.
A: The DHCP spec says that when a DHCP server recieves a renewal request
from a client it has no knowledge of, it should just ignore it.
This is because it's supported to have more than one DHCP server
on a network, and another DHCP server may be dealing with the client.
This has the unfortunate effect that when _no_ DHCP replies to
the client, it takes some time for the client to time-out and start
to get a new lease. Setting this option makes dnsmasq violate the
standard to the extent that it will send a NAK reply to the client,
causing it to immediately start to get a new lease. This improves
behaviour when machines move networks, and in the case that the DHCP
lease database is lost. As long as there are not more tha one DHCP
server on the network, it's safe to enable the option.
Q: Why does my Gentoo box pause for a minute before getting a new
lease?
@@ -349,6 +359,7 @@ A: By default, the identity of a machine is determined by using the
method for setting the client-id varies with DHCP client software,
dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
Addendum:
From version 2.46, dnsmasq has a solution to this which doesn't
involve setting client-IDs. It's possible to put more than one MAC
@@ -361,6 +372,51 @@ Addendum:
constraint: if you configure multiple MAC addresses and violate
this rule, bad things will happen.
Addendum-II: The link above is dead, the former contents of the link are:
------------------------------------------------------------------------------
How can I keep the same DHCP client reservation, if the MAC address changes?
When you reserve an IP address for a DHCP client, you provide the
MAC address of the client's NIC.
It is possible to use a custom identifier, which is sent as
option 61 in the client's DHCP Discover and Request packet.
The DhcpClientIdentifier is a REG_DWORD value that is located at:
Windows NT 4.0 SP2+
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Adapter Name>'X'\Parameters\Tcpip
where <Adapter Name> is the NIC driver name and 'X' is the number of the NIC.
Windows 2000
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TcpIp\Parameters\Interfaces\<NIC GUID>
where <NIC GUID> is the GUID of the NIC.
The valid range of data is 0x0 - 0xFFFFFFFF. The custom identifier is send as 4 bytes,
8 hexadecimal character, in groups of 2 hexadecimal characters, with the groups being
sent in reverse order. If the custom identifier is less than 8 hexadeciaml characters,
it is zero padded at the end. Examples:
Custom Client Client Reservation
Identifier on DHCP Server
12345678 78563412
123456 56341200
1234 34120000
1234567 67452301
12345 45230100
123 23010000
A18F42 428FA100
CF432 32F40C00
C32D1BE BED1320C
-------------------------------------------------------------------------------------------------------
Q: Can dnsmasq do DHCP on IP-alias interfaces?
A: Yes, from version-2.21. The support is only available running under

View File

@@ -57,8 +57,8 @@ idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) -
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`

View File

@@ -11,11 +11,18 @@
# If there is more than one v[0-9].* tag, sort them and use the
# first. This favours, eg v2.63 over 2.63rc6.
# Change directory to the toplevel source directory.
if test -z "$1" || ! test -d "$1" || ! cd "$1"; then
echo "$0: First argument $1 must be toplevel dir." >&2
exit 1
fi
if which git >/dev/null 2>&1 && \
([ -d $1/.git ] || grep '^gitdir:' $1/.git >/dev/null 2>&1); then
cd $1; git describe | sed 's/^v//'
([ -d .git ] || grep '^gitdir:' .git >/dev/null 2>&1) && \
git describe >/dev/null 2>&1; then
git describe | sed 's/^v//'
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`

View File

@@ -20,7 +20,7 @@
The iaid argument is numeric string and mandatory. Normally
it can be found in leases file both on client and server.
IP is an IPv6 adress to release
IP is an IPv6 address to release
If --dry-run is specified, dhcp_release6 just prints hexadecimal representation of
packet to send to stdout and exits.

7
debian/changelog vendored
View File

@@ -1,8 +1,13 @@
dnsmasq (2.77-1) unstable; urgency=low
* New upstream.
* Don't register as a resolvconf source when config file
includes port=0 to disable DNS.
* Handle gratuitous format change in /usr/share/dns/root.ds
(closes: #858506) (closes: #860064)
* Add lsb-base dependancy.
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 14 Dec 2016 18:01:40 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
dnsmasq (2.76-5) unstable; urgency=medium

4
debian/control vendored
View File

@@ -5,12 +5,12 @@ Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.5
Standards-Version: 3.9.8
Package: dnsmasq
Architecture: all
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
init-system-helpers (>= 1.18~)
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
Suggests: resolvconf
Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server

7
debian/init vendored
View File

@@ -111,7 +111,7 @@ DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
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' ' '`"
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/"^.*DS[\t ]"/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
fi
start()
@@ -154,6 +154,11 @@ start_resolvconf()
[ $interface = lo ] && return
done
# Also skip this if DNS functionality is disabled in /etc/dnsmasq.conf
if grep -qs '^port=0' /etc/dnsmasq.conf; then
return
fi
if [ -x /sbin/resolvconf ] ; then
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
fi

4
debian/readme vendored
View File

@@ -31,7 +31,7 @@ Notes on configuring dnsmasq as packaged for Debian.
as the first nameserver address in /etc/resolv.conf.
(6) In the absence of resolvconf, dns-nameservers lines in
/etc/network/interfaces are ignored. If you do do not use
/etc/network/interfaces are ignored. If you do not use
resolvconf, list 127.0.0.1 as the first nameserver address
in /etc/resolv.conf and configure your nameservers using
"server=<IP-address>" lines in /etc/dnsmasq.conf.
@@ -66,7 +66,7 @@ Notes on configuring dnsmasq as packaged for Debian.
combined with noi18n to be effective.
gitversion : set the version of the produced packages from the
git-derived versioning information on the source,
rather the the debian changelog.
rather than the debian changelog.
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. Dnsmasq-base provides the dnsmasq executable and

3
debian/rules vendored
View File

@@ -11,7 +11,7 @@
package=dnsmasq-base
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all" dpkg-buildflags
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all,+pie,+bindnow" dpkg-buildflags
CFLAGS = $(shell $(dpkg_buildflags) --get CFLAGS)
CFLAGS += $(shell $(dpkg_buildflags) --get CPPFLAGS)
@@ -214,6 +214,7 @@ ifeq ($(DEB_HOST_ARCH_OS),linux)
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release6
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums

View File

@@ -203,12 +203,17 @@ or
options are given dnsmasq listens on all available interfaces except any
given in
.B \--except-interface
options. IP alias interfaces (eg "eth1:0") cannot be used with
.B --interface
options. On Linux, when
.B \--bind-interfaces
or
.B --except-interface
options, use --listen-address instead. A simple wildcard, consisting
of a trailing '*', can be used in
.B \--bind-dynamic
are in effect, IP alias interface labels (eg "eth1:0") are checked, rather than
interface names. In the degenerate case when an interface has one address, this amounts to the same thing but when an interface has multiple addresses it
allows control over which of those addresses are accepted.
The same effect is achievable in default mode by using
.B \--listen-address.
A simple wildcard, consisting of a trailing '*',
can be used in
.B \--interface
and
.B \--except-interface
@@ -222,7 +227,9 @@ and
.B --except-interface
options does not matter and that
.B --except-interface
options always override the others.
options always override the others. The comments about interface labels for
.B --listen-address
apply here.
.TP
.B --auth-server=<domain>,<interface>|<ip-address>
Enable DNS authoritative mode for queries arriving at an interface or address. Note that the interface or address
@@ -301,7 +308,8 @@ attached to. Currently this facility is limited to IPv4.
.B \-b, --bogus-priv
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
which are not found in /etc/hosts or the DHCP leases file are answered
with "no such domain" rather than being forwarded upstream.
with "no such domain" rather than being forwarded upstream. The
set of prefixes affected is the list given in RFC6303, for IPv4 and IPv6.
.TP
.B \-V, --alias=[<old-ip>]|[<start-ip>-<end-ip>],<new-ip>[,<mask>]
Modify IPv4 addresses returned from upstream nameservers; old-ip is
@@ -459,14 +467,14 @@ to make configuration files clearer in this case.
IPv6 addresses may include a %interface scope-id, eg
fe80::202:a412:4512:7bbf%eth0.
The optional string after the @ character tells
dnsmasq how to set the source of the queries to this
nameserver. It should be an ip-address, which should belong to the machine on which
dnsmasq is running otherwise this server line will be logged and then
ignored, or an interface name. If an interface name is given, then
queries to the server will be forced via that interface; if an
ip-address is given then the source address of the queries will be set
to that address.
The optional string after the @ character tells dnsmasq how to set the source of
the queries to this nameserver. It can either be an ip-address, an interface
name or both. The ip-address should belong to the machine on which dnsmasq is
running, otherwise this server line will be logged and then ignored. If an
interface name is given, then queries to the server will be forced via that
interface; if an ip-address is given then the source address of the queries will
be set to that address; and if both are given then a combination of ip-address
and interface name will be used to steer requests to the server.
The query-port flag is ignored for any servers which have a
source address specified but the port may be specified directly as
part of the source address. Forcing queries to an interface is not
@@ -961,7 +969,7 @@ subnets which don't need a pool of dynamically allocated addresses,
use the "static" keyword in the dhcp-range declaration.
It is allowed to use client identifiers (called client
DUID in IPv6-land rather than
DUID in IPv6-land) rather than
hardware addresses to identify hosts by prefixing with 'id:'. Thus:
.B --dhcp-host=id:01:02:03:04,.....
refers to the host with client identifier 01:02:03:04. It is also
@@ -1476,7 +1484,7 @@ DUID automatically when it is first needed. When given, this option
provides dnsmasq the data required to create a DUID-EN type DUID. Note
that once set, the DUID is stored in the lease database, so to change between DUID-EN and
automatically created DUIDs or vice-versa, the lease database must be
re-intialised. The enterprise-id is assigned by IANA, and the uid is a
re-initialised. The enterprise-id is assigned by IANA, and the uid is a
string of hex octets unique to a particular device.
.TP
.B \-6 --dhcp-script=<path>
@@ -1569,8 +1577,8 @@ database.
All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode).
closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq.
(In debug mode, stdio, stdout and stderr file are left as those inherited from the invoker of dnsmasq).
The script is not invoked concurrently: at most one instance
of the script is ever running (dnsmasq waits for an instance of script to exit
@@ -1606,7 +1614,7 @@ the arrival of a new entry in the ARP or neighbour table, and "arp-del" indicate
.B --dhcp-luascript=<path>
Specify a script written in Lua, to be run when leases are created,
destroyed or changed. To use this option, dnsmasq must be compiled
with the correct support. The Lua interpreter is intialised once, when
with the correct support. The Lua interpreter is initialised once, when
dnsmasq starts, so that global variables persist between lease
events. The Lua code must define a
.B lease
@@ -1768,7 +1776,7 @@ the relevant link-local address of the machine running dnsmasq is sent
as recursive DNS server. If provided, the DHCPv6 options dns-server and
domain-search are used for the DNS server (RDNSS) and the domain search list (DNSSL).
.TP
.B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
.B --ra-param=<interface>,[mtu:<integer>|<interface>|off,][high,|low,]<ra-interval>[,<router lifetime>]
Set non-default values for router advertisements sent via an
interface. The priority field for the router may be altered from the
default of medium with eg
@@ -1778,9 +1786,19 @@ The interval between router advertisements may be set (in seconds) with
The lifetime of the route may be changed or set to zero, which allows
a router to advertise prefixes but not a route via itself.
.B --ra-parm=eth0,0,0
(A value of zero for the interval means the default value.) All three parameters may be set at once.
.B --ra-param=low,60,1200
(A value of zero for the interval means the default value.) All four parameters may be set at once.
.B --ra-param=eth0,mtu:1280,low,60,1200
The interface field may include a wildcard.
The mtu: parameter may be an arbitrary interface name, in which case the MTU value for that interface is used. This is useful
for (eg) advertising the MTU of a WAN interface on the other interfaces of a router.
.TP
.B --dhcp-reply-delay=[tag:<tag>,]<integer>
Delays sending DHCPOFFER and proxydhcp replies for at least the specified number of seconds.
This can be used as workaround for bugs in PXE boot firmware that does not function properly when
receiving an instant reply.
This option takes into account the time already spent waiting (e.g. performing ping check) if any.
.TP
.B --enable-tftp[=<interface>[,<interface>]]
Enable the TFTP server function. This is deliberately limited to that
@@ -1800,12 +1818,16 @@ directory is only used for TFTP requests via that interface.
.B --tftp-no-fail
Do not abort startup if specified tftp root directories are inaccessible.
.TP
.B --tftp-unique-root
Add the IP address of the TFTP client as a path component on the end
of the TFTP-root (in standard dotted-quad format). Only valid if a
tftp-root is set and the directory exists. For instance, if tftp-root is "/tftp" and client
1.2.3.4 requests file "myfile" then the effective path will be
"/tftp/1.2.3.4/myfile" if /tftp/1.2.3.4 exists or /tftp/myfile otherwise.
.B --tftp-unique-root[=ip|mac]
Add the IP or hardware address of the TFTP client as a path component on the end
of the TFTP-root. Only valid if a tftp-root is set and the directory exists.
Defaults to adding IP address (in standard dotted-quad format).
For instance, if tftp-root is "/tftp" and client 1.2.3.4 requests file "myfile"
then the effective path will be "/tftp/1.2.3.4/myfile" if /tftp/1.2.3.4 exists or /tftp/myfile otherwise.
When "=mac" is specified it will append the MAC address instead, using lowercase zero padded digits
separated by dashes, e.g.: 01-02-03-04-aa-bb
Note that resolving MAC addresses is only possible if the client is in the local network or obtained
a DHCP lease from us.
.TP
.B --tftp-secure
Enable TFTP secure mode: without this, any file which is readable by

View File

@@ -1756,20 +1756,20 @@ dnsmasq est spécifiée comme DNS récursif. Si elles sont fournies, les
options dns-server et domain-search sont utilisées respectivement pour RDNSS et
DNSSL.
.TP
.B --ra-param=<interface>,[high|low],[[<intervalle d'annonce routeur>],<durée de vie route>]
.B --ra-param=<interface>,[mtu:<valeur>|<interface>|off,][high,|low,]<intervalle d'annonce routeur>[,<durée de vie route>]
Configure pour une interface donnée des valeurs pour les annonces routeurs
différentes des valeurs par défaut. La valeur par défaut du champ priorité
pour le routeur peut-être changée de "medium" (moyen) à "high" (haute) ou
"low" (basse). Par exemple :
.B --ra-param=eth0,high.
.B --ra-param=eth0,high,0.
Un intervalle (en secondes) entre les annonces routeur peut-être fourni par :
.B --ra-param=eth0,60.
La durée de vie de la route peut-être changée ou mise à zéro, auquel cas
le routeur peut annoncer les préfixes mais pas de route :
.B --ra-parm=eth0,0,0
(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
Ces trois paramètres peuvent-être configurés en une fois :
.B --ra-param=low,60,1200
Ces quatre paramètres peuvent-être configurés en une fois :
.B --ra-param=eth0,mtu:1280,low,60,1200
La valeur pour l'interface peut inclure un caractère joker.
.TP
.B --enable-tftp[=<interface>[,<interface>]]

View File

@@ -518,7 +518,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
if (!found)
/* Only supply CNAME if no record for any type is known. */
if (nxdomain)
{
/* Check for possible wildcard match against *.domain
return length of match, to get longest.

View File

@@ -27,6 +27,7 @@
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 20 /* or 20 seconds */
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
@@ -131,7 +132,7 @@ NO_SCRIPT
NO_LARGEFILE
NO_AUTH
NO_INOTIFY
these are avilable to explicitly disable compile time options which would
these are available to explicitly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
@@ -408,14 +409,14 @@ static char *compile_opts =
"no-"
# endif
"DHCPv6 "
# if !defined(HAVE_SCRIPT)
#endif
#if !defined(HAVE_SCRIPT)
"no-scripts "
# else
# if !defined(HAVE_LUASCRIPT)
"no-"
# endif
"Lua "
#else
# if !defined(HAVE_LUASCRIPT)
"no-"
# endif
"Lua "
#endif
#ifndef HAVE_TFTP
"no-"

View File

@@ -549,17 +549,16 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s'", ipaddr);
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL,
&hw_type);
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
clid_len, now, 0);
lease_set_expires(lease, expires, now);
if (hostname_len != 0)
lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
lease_update_file(now);
lease_update_dns(0);

View File

@@ -149,8 +149,10 @@ void dhcp_packet(time_t now, int pxe_fd)
int rcvd_iface_index;
struct in_addr iface_addr;
struct iface_param parm;
time_t recvtime = now;
#ifdef HAVE_LINUX_NETWORK
struct arpreq arp_req;
struct timeval tv;
#endif
union {
@@ -177,6 +179,9 @@ void dhcp_packet(time_t now, int pxe_fd)
return;
#if defined (HAVE_LINUX_NETWORK)
if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
recvtime = tv.tv_sec;
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
@@ -335,14 +340,14 @@ void dhcp_packet(time_t now, int pxe_fd)
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
now, unicast_dest, &is_inform, pxe_fd, iface_addr, recvtime);
lease_update_file(now);
lease_update_dns(0);
if (iov.iov_len == 0)
return;
}
msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest);
msg.msg_control = NULL;
@@ -496,7 +501,7 @@ static int check_listen_addrs(struct in_addr local, int if_index, char *label,
3) Fills in local (this host) and router (this host or relay) addresses.
4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
@@ -638,6 +643,66 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
return NULL;
}
/* Check if and address is in use by sending ICMP ping.
This wrapper handles a cache and load-limiting.
Return is NULL is address in use, or a pointer to a cache entry
recording that it isn't. */
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash)
{
static struct ping_result dummy;
struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
((float)PING_WAIT)));
/* check if we failed to ping addr sometime in the last
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
This avoids problems when a stupid client bangs
on us repeatedly. As a final check, if we did more
than 60% of the possible ping checks in the last
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
for (count = 0, r = daemon->ping_results; r; r = r->next)
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
victim = r; /* old record */
else
{
count++;
if (r->addr.s_addr == addr.s_addr)
return r;
}
/* didn't find cached entry */
if ((count >= max) || option_bool(OPT_NO_PING))
{
/* overloaded, or configured not to check, return "not in use" */
dummy.hash = 0;
return &dummy;
}
else if (icmp_ping(addr))
return NULL; /* address in use. */
else
{
/* at this point victim may hold an expired record */
if (!victim)
{
if ((victim = whine_malloc(sizeof(struct ping_result))))
{
victim->next = daemon->ping_results;
daemon->ping_results = victim;
}
}
/* record that this address is OK for 30s
without more ping checks */
if (victim)
{
victim->addr = addr;
victim->time = now;
victim->hash = hash;
}
return victim;
}
}
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now)
@@ -655,6 +720,10 @@ int address_allocate(struct dhcp_context *context,
dispersal even with similarly-valued "strings". */
for (j = 0, i = 0; i < hw_len; i++)
j = hwaddr[i] + (j << 6) + (j << 16) - j;
/* j == 0 is marker */
if (j == 0)
j = 1;
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
@@ -692,69 +761,27 @@ int address_allocate(struct dhcp_context *context,
(!IN_CLASSC(ntohl(addr.s_addr)) ||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
{
struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
((float)PING_WAIT)));
struct ping_result *r;
*addrp = addr;
/* check if we failed to ping addr sometime in the last
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
This avoids problems when a stupid client bangs
on us repeatedly. As a final check, if we did more
than 60% of the possible ping checks in the last
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
for (count = 0, r = daemon->ping_results; r; r = r->next)
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
victim = r; /* old record */
else
{
count++;
if (r->addr.s_addr == addr.s_addr)
{
/* consec-ip mode: we offered this address for another client
(different hash) recently, don't offer it to this one. */
if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
break;
return 1;
}
}
if (!r)
{
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
if ((r = do_icmp_ping(now, addr, j)))
{
/* consec-ip mode: we offered this address for another client
(different hash) recently, don't offer it to this one. */
if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
{
/* address in use: perturb address selection so that we are
less likely to try this address again. */
if (!option_bool(OPT_CONSEC_ADDR))
c->addr_epoch++;
}
else
{
/* at this point victim may hold an expired record */
if (!victim)
{
if ((victim = whine_malloc(sizeof(struct ping_result))))
{
victim->next = daemon->ping_results;
daemon->ping_results = victim;
}
}
/* record that this address is OK for 30s
without more ping checks */
if (victim)
{
victim->addr = addr;
victim->time = now;
victim->hash = j;
}
*addrp = addr;
return 1;
}
}
else
{
/* address in use: perturb address selection so that we are
less likely to try this address again. */
if (!option_bool(OPT_CONSEC_ADDR))
c->addr_epoch++;
}
}
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))

View File

@@ -771,6 +771,8 @@ int main (int argc, char **argv)
if (option_bool(OPT_NOWILD))
warn_bound_listeners();
else if (!option_bool(OPT_CLEVERBIND))
warn_wild_labels();
warn_int_names();
@@ -1300,6 +1302,7 @@ static void async_event(int pipe, time_t now)
daemon->tcp_pids[i] = 0;
break;
#if defined(HAVE_SCRIPT)
case EVENT_KILLED:
my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
break;
@@ -1313,12 +1316,19 @@ static void async_event(int pipe, time_t now)
daemon->lease_change_command, strerror(ev.data));
break;
case EVENT_SCRIPT_LOG:
my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
free(msg);
msg = NULL;
break;
/* necessary for fatal errors in helper */
case EVENT_USER_ERR:
case EVENT_DIE:
case EVENT_LUA_ERR:
fatal_event(&ev, msg);
break;
#endif
case EVENT_REOPEN:
/* Note: this may leave TCP-handling processes with the old file still open.
@@ -1745,29 +1755,15 @@ int icmp_ping(struct in_addr addr)
{
/* Try and get an ICMP echo from a machine. */
/* Note that whilst in the three second wait, we check for
(and service) events on the DNS and TFTP sockets, (so doing that
better not use any resources our caller has in use...)
but we remain deaf to signals or further DHCP packets. */
/* There can be a problem using dnsmasq_time() to end the loop, since
it's not monotonic, and can go backwards if the system clock is
tweaked, leading to the code getting stuck in this loop and
ignoring DHCP requests. To fix this, we check to see if select returned
as a result of a timeout rather than a socket becoming available. We
only allow this to happen as many times as it takes to get to the wait time
in quarter-second chunks. This provides a fallback way to end loop. */
int fd, rc;
int fd;
struct sockaddr_in saddr;
struct {
struct ip ip;
struct icmp icmp;
} packet;
unsigned short id = rand16();
unsigned int i, j, timeout_count;
unsigned int i, j;
int gotreply = 0;
time_t start, now;
#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
if ((fd = make_icmp_sock()) == -1)
@@ -1797,14 +1793,46 @@ int icmp_ping(struct in_addr addr)
while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
(struct sockaddr *)&saddr, sizeof(saddr))));
for (now = start = dnsmasq_time(), timeout_count = 0;
(difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);)
gotreply = delay_dhcp(dnsmasq_time(), PING_WAIT, fd, addr.s_addr, id);
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
while (retry_send(close(fd)));
#else
opt = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
#endif
return gotreply;
}
int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
{
/* Delay processing DHCP packets for "sec" seconds counting from "start".
If "fd" is not -1 it will stop waiting if an ICMP echo reply is received
from "addr" with ICMP ID "id" and return 1 */
/* Note that whilst waiting, we check for
(and service) events on the DNS and TFTP sockets, (so doing that
better not use any resources our caller has in use...)
but we remain deaf to signals or further DHCP packets. */
/* There can be a problem using dnsmasq_time() to end the loop, since
it's not monotonic, and can go backwards if the system clock is
tweaked, leading to the code getting stuck in this loop and
ignoring DHCP requests. To fix this, we check to see if select returned
as a result of a timeout rather than a socket becoming available. We
only allow this to happen as many times as it takes to get to the wait time
in quarter-second chunks. This provides a fallback way to end loop. */
int rc, timeout_count;
time_t now;
for (now = dnsmasq_time(), timeout_count = 0;
(difftime(now, start) <= (float)sec) && (timeout_count < sec * 4);)
{
struct sockaddr_in faddr;
socklen_t len = sizeof(faddr);
poll_reset();
poll_listen(fd, POLLIN);
if (fd != -1)
poll_listen(fd, POLLIN);
set_dns_listeners(now);
set_log_writer();
@@ -1821,10 +1849,10 @@ int icmp_ping(struct in_addr addr)
timeout_count++;
now = dnsmasq_time();
check_log_writer(0);
check_dns_listeners(now);
#ifdef HAVE_DHCP6
if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
icmp6_packet(now);
@@ -1834,27 +1862,26 @@ int icmp_ping(struct in_addr addr)
check_tftp_listeners(now);
#endif
if (poll_check(fd, POLLIN) &&
recvfrom(fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
packet.icmp.icmp_seq == 0 &&
packet.icmp.icmp_id == id)
{
gotreply = 1;
break;
if (fd != -1)
{
struct {
struct ip ip;
struct icmp icmp;
} packet;
struct sockaddr_in faddr;
socklen_t len = sizeof(faddr);
if (poll_check(fd, POLLIN) &&
recvfrom(fd, &packet, sizeof(packet), 0, (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
addr == faddr.sin_addr.s_addr &&
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
packet.icmp.icmp_seq == 0 &&
packet.icmp.icmp_id == id)
return 1;
}
}
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
while (retry_send(close(fd)));
#else
opt = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
#endif
return gotreply;
return 0;
}
#endif

View File

@@ -145,30 +145,31 @@ struct event_desc {
int event, data, msg_sz;
};
#define EVENT_RELOAD 1
#define EVENT_DUMP 2
#define EVENT_ALARM 3
#define EVENT_TERM 4
#define EVENT_CHILD 5
#define EVENT_REOPEN 6
#define EVENT_EXITED 7
#define EVENT_KILLED 8
#define EVENT_EXEC_ERR 9
#define EVENT_PIPE_ERR 10
#define EVENT_USER_ERR 11
#define EVENT_CAP_ERR 12
#define EVENT_PIDFILE 13
#define EVENT_HUSER_ERR 14
#define EVENT_GROUP_ERR 15
#define EVENT_DIE 16
#define EVENT_LOG_ERR 17
#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
#define EVENT_TIME_ERR 24
#define EVENT_RELOAD 1
#define EVENT_DUMP 2
#define EVENT_ALARM 3
#define EVENT_TERM 4
#define EVENT_CHILD 5
#define EVENT_REOPEN 6
#define EVENT_EXITED 7
#define EVENT_KILLED 8
#define EVENT_EXEC_ERR 9
#define EVENT_PIPE_ERR 10
#define EVENT_USER_ERR 11
#define EVENT_CAP_ERR 12
#define EVENT_PIDFILE 13
#define EVENT_HUSER_ERR 14
#define EVENT_GROUP_ERR 15
#define EVENT_DIE 16
#define EVENT_LOG_ERR 17
#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
#define EVENT_TIME_ERR 24
#define EVENT_SCRIPT_LOG 25
/* Exit codes. */
#define EC_GOOD 0
@@ -211,7 +212,7 @@ struct event_desc {
#define OPT_TFTP_SECURE 26
#define OPT_TFTP_NOBLOCK 27
#define OPT_LOG_OPTS 28
#define OPT_TFTP_APREF 29
#define OPT_TFTP_APREF_IP 29
#define OPT_NO_OVERRIDE 30
#define OPT_NO_REBIND 31
#define OPT_ADD_MAC 32
@@ -238,12 +239,14 @@ struct event_desc {
#define OPT_SCRIPT_ARP 53
#define OPT_MAC_B64 54
#define OPT_MAC_HEX 55
#define OPT_LAST 56
#define OPT_TFTP_APREF_MAC 56
#define OPT_LAST 57
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
#define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON
#define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON
#define MS_SCRIPT LOG_MAIL
struct all_addr {
union {
@@ -485,6 +488,7 @@ union mysockaddr {
#define SERV_FROM_FILE 4096 /* read from --servers-file */
#define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
struct serverfd {
int fd;
@@ -521,7 +525,7 @@ struct ipsets {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found;
int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found, label;
char *name;
struct irec *next;
};
@@ -703,6 +707,12 @@ struct tag_if {
struct tag_if *next;
};
struct delay_config {
int delay;
struct dhcp_netid *netid;
struct delay_config *next;
};
struct hwaddr_config {
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
@@ -831,7 +841,8 @@ struct prefix_class {
struct ra_interface {
char *name;
int interval, lifetime, prio;
char *mtu_name;
int interval, lifetime, prio, mtu;
struct ra_interface *next;
};
@@ -973,6 +984,7 @@ extern struct daemon {
struct tag_if *tag_if;
struct addr_list *override_relays;
struct dhcp_relay *relay4, *relay6;
struct delay_config *delay_conf;
int override;
int enable_pxe;
int doing_ra, doing_dhcp6;
@@ -1251,6 +1263,7 @@ int enumerate_interfaces(int reset);
void create_wildcard_listeners(void);
void create_bound_listeners(int die);
void warn_bound_listeners(void);
void warn_wild_labels(void);
void warn_int_names(void);
int is_dad_listeners(void);
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
@@ -1279,6 +1292,8 @@ struct dhcp_context *address_available(struct dhcp_context *context,
struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr,
struct dhcp_netid *netids);
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr,
unsigned int hash);
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now);
@@ -1330,7 +1345,7 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
/* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback);
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback, time_t recvtime);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
@@ -1339,6 +1354,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
#ifdef HAVE_DHCP
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id);
#endif
void queue_event(int event);
void send_alarm(time_t event, time_t now);

View File

@@ -897,7 +897,7 @@ void reply_query(int fd, int family, time_t now)
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
else
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags && SERV_DO_DNSSEC), NULL, NULL);
}
/* Can't validate, as we're missing key data. Put this
@@ -1328,7 +1328,7 @@ void receive_query(struct listener *listen, time_t now)
struct irec *iface;
/* get the netmask of the interface which has the address we were sent to.
This is no neccessarily the interface we arrived on. */
This is no necessarily the interface we arrived on. */
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->addr.sa.sa_family == AF_INET &&
@@ -1459,14 +1459,15 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
unsigned char *payload = NULL;
struct dns_header *new_header = NULL;
u16 *length = NULL;
while (1)
{
int type = SERV_DO_DNSSEC;
char *domain;
size_t m;
unsigned char c1, c2;
struct server *firstsendto = NULL;
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
if (--(*keycount) == 0)
new_status = STAT_ABANDONED;
@@ -1475,7 +1476,8 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
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, option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags && SERV_DO_DNSSEC), NULL, NULL);
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
break;
@@ -1504,81 +1506,86 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) == 0)
{
struct server *start = server, *new_server = NULL;
type &= ~SERV_DO_DNSSEC;
while (1)
{
if (type == (start->flags & SERV_TYPE) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{
new_server = start;
if (server == start)
{
new_server = NULL;
break;
}
}
if (!(start = start->next))
start = daemon->servers;
if (start == server)
break;
}
if (new_server)
{
server = new_server;
/* may need to make new connection. */
if (server->tcpfd == -1)
{
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
{
new_status = STAT_ABANDONED;
break;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{
close(server->tcpfd);
server->tcpfd = -1;
new_status = STAT_ABANDONED;
break;
}
}
}
}
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))
if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) != 0)
{
new_status = STAT_ABANDONED;
break;
}
m = (c1 << 8) | c2;
type &= ~SERV_DO_DNSSEC;
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
while (1)
{
if (!firstsendto)
firstsendto = server;
else
{
if (!(server = server->next))
server = daemon->servers;
if (server == firstsendto)
{
/* can't find server to accept our query. */
new_status = STAT_ABANDONED;
break;
}
}
if (type != (server->flags & SERV_TYPE) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
continue;
retry:
/* may need to make new connection. */
if (server->tcpfd == -1)
{
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{
close(server->tcpfd);
server->tcpfd = -1;
continue; /* No good, next server */
}
server->flags &= ~SERV_GOT_TCP;
}
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))
{
close(server->tcpfd);
server->tcpfd = -1;
/* We get data then EOF, reopen connection to same server,
else try next. This avoids DoS from a server which accepts
connections and then closes them. */
if (server->flags & SERV_GOT_TCP)
goto retry;
else
continue;
}
server->flags |= SERV_GOT_TCP;
m = (c1 << 8) | c2;
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
break;
}
if (new_status != STAT_OK)
break;
}
if (packet)
free(packet);
@@ -1820,7 +1827,8 @@ unsigned char *tcp_request(int confd, time_t now,
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
continue;
retry:
if (last_server->tcpfd == -1)
{
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
@@ -1840,25 +1848,27 @@ unsigned char *tcp_request(int confd, time_t now,
continue;
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
{
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
if (size != new_size)
{
added_pheader = 1;
size = new_size;
}
/* 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;
}
#endif
last_server->flags &= ~SERV_GOT_TCP;
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
{
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
if (size != new_size)
{
added_pheader = 1;
size = new_size;
}
/* 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;
}
#endif
*length = htons(size);
/* get query name again for logging - may have been overwritten */
@@ -1872,9 +1882,17 @@ unsigned char *tcp_request(int confd, time_t now,
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
/* We get data then EOF, reopen connection to same server,
else try next. This avoids DoS from a server which accepts
connections and then closes them. */
if (last_server->flags & SERV_GOT_TCP)
goto retry;
else
continue;
}
last_server->flags |= SERV_GOT_TCP;
m = (c1 << 8) | c2;
if (last_server->addr.sa.sa_family == AF_INET)

View File

@@ -14,6 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "dnsmasq.h"
#ifdef HAVE_SCRIPT
@@ -135,7 +136,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
max_fd != event_fd && max_fd != err_fd)
close(max_fd);
#ifdef HAVE_LUASCRIPT
if (daemon->luascript)
{
@@ -189,6 +190,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *extradata, *alloc_buff = NULL;
int is6, err = 0;
int pipeout[2];
free(alloc_buff);
@@ -472,16 +474,54 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (!daemon->lease_change_command)
continue;
/* Pipe to capture stdout and stderr from script */
if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1)
continue;
/* possible fork errors are all temporary resource problems */
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
sleep(2);
if (pid == -1)
continue;
{
if (!option_bool(OPT_DEBUG))
{
close(pipeout[0]);
close(pipeout[1]);
}
continue;
}
/* wait for child to complete */
if (pid != 0)
{
if (!option_bool(OPT_DEBUG))
{
FILE *fp;
close(pipeout[1]);
/* Read lines sent to stdout/err by the script and pass them back to be logged */
if (!(fp = fdopen(pipeout[0], "r")))
close(pipeout[0]);
else
{
while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
{
/* do not include new lines, log will append them */
size_t len = strlen(daemon->packet);
if (len > 0)
{
--len;
if (daemon->packet[len] == '\n')
daemon->packet[len] = 0;
}
send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
}
fclose(fp);
}
}
/* reap our children's children, if necessary */
while (1)
{
@@ -504,6 +544,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
}
if (!option_bool(OPT_DEBUG))
{
/* map stdout/stderr of script to pipeout */
close(pipeout[0]);
dup2(pipeout[1], STDOUT_FILENO);
dup2(pipeout[1], STDERR_FILENO);
close(pipeout[1]);
}
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
{
@@ -580,7 +629,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
hostname = NULL;
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
}
}
/* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);

View File

@@ -104,7 +104,7 @@ void inotify_dnsmasq_init()
strcpy(path, res->name);
/* Follow symlinks until we reach a non-symlink, or a non-existant file. */
/* Follow symlinks until we reach a non-symlink, or a non-existent file. */
while ((new_path = my_readlink(path)))
{
if (links-- == 0)

View File

@@ -21,21 +21,127 @@
static struct dhcp_lease *leases = NULL, *old_leases = NULL;
static int dns_dirty, file_dirty, leases_left;
void lease_init(time_t now)
static int read_leases(time_t now, FILE *leasestream)
{
unsigned long ei;
struct all_addr addr;
struct dhcp_lease *lease;
int clid_len, hw_len, hw_type;
int items;
char *domain = NULL;
*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
/* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes
Check various buffers are big enough for the code below */
#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764)
# error Buffer size breakage in leasefile parsing.
#endif
while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
{
*daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
hw_len = hw_type = clid_len = 0;
#ifdef HAVE_DHCP6
if (strcmp(daemon->dhcp_buff3, "duid") == 0)
{
daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
if (daemon->duid_len < 0)
return 0;
daemon->duid = safe_malloc(daemon->duid_len);
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
continue;
}
#endif
if (fscanf(leasestream, " %64s %255s %764s",
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
return 0;
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4))
{
if ((lease = lease4_allocate(addr.addr.addr4)))
domain = get_domain(lease->addr);
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explicit MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
{
char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA;
if (s[0] == 'T')
{
lease_type = LEASE_TA;
s++;
}
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{
lease_set_iaid(lease, strtoul(s, NULL, 10));
domain = get_domain6((struct in6_addr *)lease->hwaddr);
}
}
#endif
else
return 0;
if (!lease)
die (_("too many stored leases"), NULL, EC_MISC);
if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
hw_len, hw_type, clid_len, now, 0);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
ei = atol(daemon->dhcp_buff3);
#ifdef HAVE_BROKEN_RTC
if (ei != 0)
lease->expires = (time_t)ei + now;
else
lease->expires = (time_t)0;
lease->length = ei;
#else
/* strictly time_t is opaque, but this hack should work on all sane systems,
even when sizeof(time_t) == 8 */
lease->expires = (time_t)ei;
#endif
/* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
}
return (items == 0 || items == EOF);
}
void lease_init(time_t now)
{
FILE *leasestream;
int readok = 0;
leases_left = daemon->dhcp_max;
if (option_bool(OPT_LEASE_RO))
{
/* run "<lease_change_script> init" once to get the
initial state of the database. If leasefile-ro is
set without a script, we just do without any
set without a script, we just do without any
lease database. */
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command)
@@ -56,106 +162,24 @@ void lease_init(time_t now)
{
/* NOTE: need a+ mode to create file if it doesn't exist */
leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
if (!leasestream)
die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
/* a+ mode leaves pointer at end. */
rewind(leasestream);
}
/* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes
Check various buffers are big enough for the code below */
#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764)
# error Buffer size breakage in leasefile parsing.
#endif
if (leasestream)
while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
{
#ifdef HAVE_DHCP6
if (strcmp(daemon->dhcp_buff3, "duid") == 0)
{
daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
daemon->duid = safe_malloc(daemon->duid_len);
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
continue;
}
#endif
{
if (!(readok = read_leases(now, leasestream)))
my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."),
daemon->dhcp_buff3, daemon->dhcp_buff2,
daemon->namebuff, daemon->dhcp_buff);
ei = atol(daemon->dhcp_buff3);
if (fscanf(leasestream, " %64s %255s %764s",
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
break;
clid_len = 0;
if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
(lease = lease4_allocate(addr.addr.addr4)))
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explicit MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
hw_len, hw_type, clid_len, now, 0);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
{
char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA;
int iaid;
if (s[0] == 'T')
{
lease_type = LEASE_TA;
s++;
}
iaid = strtoul(s, NULL, 10);
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
lease_set_iaid(lease, iaid);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
}
}
#endif
else
break;
if (!lease)
die (_("too many stored leases"), NULL, EC_MISC);
#ifdef HAVE_BROKEN_RTC
if (ei != 0)
lease->expires = (time_t)ei + now;
else
lease->expires = (time_t)0;
lease->length = ei;
#else
/* strictly time_t is opaque, but this hack should work on all sane systems,
even when sizeof(time_t) == 8 */
lease->expires = (time_t)ei;
#endif
/* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
}
if (ferror(leasestream))
die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
}
#ifdef HAVE_SCRIPT
if (!daemon->lease_stream)
@@ -169,6 +193,7 @@ void lease_init(time_t now)
errno = ENOENT;
else if (WEXITSTATUS(rc) == 126)
errno = EACCES;
die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
}
@@ -177,6 +202,12 @@ void lease_init(time_t now)
sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
}
/* Only die if we stopped reading due to a non-parsed line when running script,
this is expected behaviour when reading from a file, if the file was written with IPv6 data
and we are not compiled to understand that. */
if (!readok)
die(_("failed to read lease-init script output"), NULL, EC_FILE);
}
#endif

View File

@@ -288,7 +288,9 @@ void my_syslog(int priority, const char *format, ...)
func = "-tftp";
else if ((LOG_FACMASK & priority) == MS_DHCP)
func = "-dhcp";
else if ((LOG_FACMASK & priority) == MS_SCRIPT)
func = "-script";
#ifdef LOG_PRI
priority = LOG_PRI(priority);
#else

View File

@@ -244,6 +244,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1;
int auth_dns = 0;
int is_label = 0;
#if defined(HAVE_DHCP) || defined(HAVE_TFTP)
struct iname *tmp;
#endif
@@ -264,6 +265,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
if (!label)
label = ifr.ifr_name;
else
is_label = strcmp(label, ifr.ifr_name);
/* maintain a list of all addresses on all interfaces for --local-service option */
if (option_bool(OPT_LOCAL_SERVICE))
@@ -482,6 +485,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
iface->found = 1;
iface->done = iface->multicast_done = iface->warned = 0;
iface->index = if_index;
iface->label = is_label;
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
strcpy(iface->name, ifr.ifr_name);
@@ -1034,6 +1038,15 @@ void warn_bound_listeners(void)
my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"));
}
void warn_wild_labels(void)
{
struct irec *iface;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->found && iface->name && iface->label)
my_syslog(LOG_WARNING, _("warning: using interface %s instead"), iface->name);
}
void warn_int_names(void)
{
struct interface_name *intname;
@@ -1438,6 +1451,7 @@ void check_servers(void)
struct server *serv;
struct serverfd *sfd, *tmp, **up;
int port = 0, count;
int locals = 0;
/* interface may be new since startup */
if (!option_bool(OPT_NOWILD))
@@ -1541,7 +1555,11 @@ void check_servers(void)
s1 = _("domain"), s2 = serv->domain;
if (serv->flags & SERV_NO_ADDR)
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
{
count--;
if (++locals <= LOCALS_LOGGED)
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
}
else if (serv->flags & SERV_USE_RESOLV)
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
else
@@ -1558,6 +1576,8 @@ void check_servers(void)
}
}
if (locals > LOCALS_LOGGED)
my_syslog(LOG_INFO, _("using %d more local addresses"), locals - LOCALS_LOGGED);
if (count - 1 > SERVERS_LOGGED)
my_syslog(LOG_INFO, _("using %d more nameservers"), count - SERVERS_LOGGED - 1);

View File

@@ -159,6 +159,7 @@ struct myoption {
#define LOPT_SCRIPT_ARP 347
#define LOPT_DHCPTTL 348
#define LOPT_TFTP_MTU 349
#define LOPT_REPLY_DELAY 350
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -242,7 +243,7 @@ static const struct myoption opts[] =
{ "enable-tftp", 2, 0, LOPT_TFTP },
{ "tftp-secure", 0, 0, LOPT_SECURE },
{ "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
{ "tftp-unique-root", 0, 0, LOPT_APREF },
{ "tftp-unique-root", 2, 0, LOPT_APREF },
{ "tftp-root", 1, 0, LOPT_PREFIX },
{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
{ "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
@@ -323,6 +324,7 @@ static const struct myoption opts[] =
{ "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
{ "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
{ NULL, 0, 0, 0 }
};
@@ -430,7 +432,7 @@ static struct {
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
{ LOPT_APREF, ARG_DUP, "[=ip|mac]", gettext_noop("Add client IP or hardware address to tftp-root."), NULL },
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
{ LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
@@ -486,7 +488,7 @@ static struct {
#ifdef OPTION6_PREFIX_CLASS
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
#endif
{ LOPT_RA_PARAM, ARG_DUP, "<iface>,[<prio>,]<intval>[,<lifetime>]", gettext_noop("Set priority, resend-interval and router-lifetime"), NULL },
{ LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
@@ -494,6 +496,7 @@ static struct {
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
{ LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -757,6 +760,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
{
int source_port = 0, serv_port = NAMESERVER_PORT;
char *portno, *source;
char *interface_opt = NULL;
#ifdef HAVE_IPV6
int scope_index = 0;
char *scope_id;
@@ -782,6 +786,19 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
scope_id = split_chr(arg, '%');
#endif
if (source) {
interface_opt = split_chr(source, '@');
if (interface_opt)
{
#if defined(SO_BINDTODEVICE)
strncpy(interface, interface_opt, IF_NAMESIZE - 1);
#else
return _("interface binding not supported");
#endif
}
}
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
{
addr->in.sin_port = htons(serv_port);
@@ -800,6 +817,9 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
{
#if defined(SO_BINDTODEVICE)
if (interface_opt)
return _("interface can only be specified once");
source_addr->in.sin_addr.s_addr = INADDR_ANY;
strncpy(interface, source, IF_NAMESIZE - 1);
#else
@@ -832,7 +852,10 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
{
#if defined(SO_BINDTODEVICE)
source_addr->in6.sin6_addr = in6addr_any;
if (interface_opt)
return _("interface can only be specified once");
source_addr->in6.sin6_addr = in6addr_any;
strncpy(interface, source, IF_NAMESIZE - 1);
#else
return _("interface binding not supported");
@@ -850,19 +873,31 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
static struct server *add_rev4(struct in_addr addr, int msize)
{
struct server *serv = opt_malloc(sizeof(struct server));
in_addr_t a = ntohl(addr.s_addr) >> 8;
in_addr_t a = ntohl(addr.s_addr);
char *p;
memset(serv, 0, sizeof(struct server));
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
if (msize == 24)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
if (msize != 8)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
switch (msize)
{
case 32:
p += sprintf(p, "%d.", a & 0xff);
/* fall through */
case 24:
p += sprintf(p, "%d.", (a >> 8) & 0xff);
/* fall through */
case 16:
p += sprintf(p, "%d.", (a >> 16) & 0xff);
/* fall through */
case 8:
p += sprintf(p, "%d.", (a >> 24) & 0xff);
break;
default:
return NULL;
}
p += sprintf(p, "in-addr.arpa");
serv->flags = SERV_HAS_DOMAIN;
serv->next = daemon->servers;
@@ -2067,6 +2102,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* generate the equivalent of
local=/xxx.yyy.zzz.in-addr.arpa/ */
struct server *serv = add_rev4(new->start, msize);
if (!serv)
ret_err(_("bad prefix"));
serv->flags |= SERV_NO_ADDR;
/* local=/<domain>/ */
@@ -2438,7 +2476,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err);
if (inet_pton(AF_INET, arg, &addr4))
serv = add_rev4(addr4, size);
{
serv = add_rev4(addr4, size);
if (!serv)
ret_err(_("bad prefix"));
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr6))
serv = add_rev6(&addr6, size);
@@ -2678,6 +2720,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
break;
case LOPT_APREF: /* --tftp-unique-root */
if (!arg || strcasecmp(arg, "ip") == 0)
set_option_bool(OPT_TFTP_APREF_IP);
else if (strcasecmp(arg, "mac") == 0)
set_option_bool(OPT_TFTP_APREF_MAC);
else
ret_err(gen_err);
break;
#endif
case LOPT_BRIDGE: /* --bridge-interface */
@@ -3269,11 +3320,43 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break;
}
case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
{
struct dhcp_netid *id = NULL;
while (is_tag_prefix(arg))
{
struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
newid->next = id;
id = newid;
comma = split(arg);
newid->net = opt_string_alloc(arg+4);
arg = comma;
};
if (!arg)
ret_err(gen_err);
else
{
struct delay_config *new;
int delay;
if (!atoi_check(arg, &delay))
ret_err(gen_err);
new = opt_malloc(sizeof(struct delay_config));
new->delay = delay;
new->netid = id;
new->next = daemon->delay_conf;
daemon->delay_conf = new;
}
break;
}
case LOPT_PXE_PROMT: /* --pxe-prompt */
{
struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
int timeout;
new->netid = NULL;
new->opt = 10; /* PXE_MENU_PROMPT */
@@ -3623,7 +3706,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
new->lifetime = -1;
new->prio = 0;
new->mtu = 0;
new->mtu_name = NULL;
new->name = opt_string_alloc(arg);
if (strcasestr(comma, "mtu:") == comma)
{
arg = comma + 4;
if (!(comma = split(comma)))
goto err;
if (!strcasecmp(arg, "off"))
new->mtu = -1;
else if (!atoi_check(arg, &new->mtu))
new->mtu_name = opt_string_alloc(arg);
else if (new->mtu < 1280)
goto err;
}
if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
{
if (*comma == 'l' || *comma == 'L')
@@ -3635,6 +3732,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
arg = split(comma);
if (!atoi_check(comma, &new->interval) ||
(arg && !atoi_check(arg, &new->lifetime)))
err:
ret_err(_("bad RA-params"));
new->next = daemon->ra_interfaces;
@@ -4089,7 +4187,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
{
int white, i;
volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
char *errmess, *p, *arg = NULL, *start;
char *errmess, *p, *arg, *start;
size_t len;
/* Memory allocation failure longjmps here if mem_recover == 1 */
@@ -4100,6 +4198,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
mem_recover = 1;
}
arg = NULL;
lineno++;
errmess = NULL;

View File

@@ -243,7 +243,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg;
struct ra_interface *ra_param = find_iface_param(iface_name);
int done_dns = 0, old_prefix = 0;
int done_dns = 0, old_prefix = 0, mtu = 0;
unsigned int min_pref_time;
#ifdef HAVE_LINUX_NETWORK
FILE *f;
@@ -399,22 +399,32 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
}
/* Set the MTU from ra_param if any, an MTU of 0 mean automatic for linux, */
/* an MTU of -1 prevents the option from being sent. */
if (ra_param)
mtu = ra_param->mtu;
#ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
available from SIOCGIFMTU */
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
if ((f = fopen(daemon->namebuff, "r")))
if (mtu == 0)
{
if (fgets(daemon->namebuff, MAXDNAME, f))
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(atoi(daemon->namebuff));
}
fclose(f);
char *mtu_name = ra_param ? ra_param->mtu_name : NULL;
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", mtu_name ? : iface_name);
if ((f = fopen(daemon->namebuff, "r")))
{
if (fgets(daemon->namebuff, MAXDNAME, f))
mtu = atoi(daemon->namebuff);
fclose(f);
}
}
#endif
if (mtu > 0)
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(mtu);
}
iface_enumerate(AF_LOCAL, &send_iface, add_lla);

View File

@@ -426,6 +426,19 @@ int private_net(struct in_addr addr, int ban_localhost)
((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
}
#ifdef HAVE_IPV6
static int private_net6(struct in6_addr *a)
{
return
IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
IN6_IS_ADDR_LOOPBACK(a) || /* RFC 6303 4.3 */
IN6_IS_ADDR_LINKLOCAL(a) || /* RFC 6303 4.5 */
((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
}
#endif
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
{
int i, qtype, qclass, rdlen;
@@ -1184,7 +1197,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
if (crecp->flags & F_IMMORTAL)
return crecp->ttd;
/* Return the Max TTL value if it is lower then the actual TTL */
/* Return the Max TTL value if it is lower than the actual TTL */
if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
return crecp->ttd - now;
else
@@ -1440,20 +1453,48 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
anscount++;
}
}
else if (is_arpa == F_IPV4 &&
option_bool(OPT_BOGUSPRIV) &&
private_net(addr.addr.addr4, 1))
else if (option_bool(OPT_BOGUSPRIV) && (
#ifdef HAVE_IPV6
(is_arpa == F_IPV6 && private_net6(&addr.addr.addr6)) ||
#endif
(is_arpa == F_IPV4 && private_net(addr.addr.addr4, 1))))
{
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
ans = 1;
sec_data = 0;
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
name, &addr, NULL);
struct server *serv;
unsigned int namelen = strlen(name);
char *nameend = name + namelen;
/* see if have rev-server set */
for (serv = daemon->servers; serv; serv = serv->next)
{
unsigned int domainlen;
char *matchstart;
if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
continue;
domainlen = strlen(serv->domain);
if (domainlen == 0 || domainlen > namelen)
continue;
matchstart = nameend - domainlen;
if (hostname_isequal(matchstart, serv->domain) &&
(namelen == domainlen || *(matchstart-1) == '.' ))
break;
}
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
if (!serv)
{
ans = 1;
sec_data = 0;
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
name, &addr, NULL);
}
}
}
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
{
unsigned short type = T_A;
@@ -1520,7 +1561,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
enumerate_interfaces(0);
/* See if a putative address is on the network from which we recieved
/* See if a putative address is on the network from which we received
the query, is so we'll filter other answers. */
if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && type == T_A)
for (intr = daemon->int_names; intr; intr = intr->next)

View File

@@ -64,9 +64,10 @@ static int prune_vendor_opts(struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback, time_t recvtime)
{
unsigned char *opt, *clid = NULL;
struct dhcp_lease *ltmp, *lease = NULL;
@@ -918,6 +919,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
log_tags(tagif_netid, ntohl(mess->xid));
if (!ignore)
apply_delay(mess->xid, recvtime, tagif_netid);
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
}
}
@@ -1026,6 +1029,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (have_config(config, CONFIG_DECLINED) &&
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
else if (!do_icmp_ping(now, config->addr, 0))
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
else
conf = config->addr;
}
@@ -1038,7 +1043,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
!config_find_by_address(daemon->dhcp_conf, lease->addr))
mess->yiaddr = lease->addr;
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
!config_find_by_address(daemon->dhcp_conf, addr))
!config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0))
mess->yiaddr = addr;
else if (emac_len == 0)
message = _("no unique-id");
@@ -1058,7 +1063,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
log_tags(tagif_netid, ntohl(mess->xid));
apply_delay(mess->xid, recvtime, tagif_netid);
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
@@ -2615,6 +2620,29 @@ static void do_options(struct dhcp_context *context,
}
}
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
{
struct delay_config *delay_conf;
/* Decide which delay_config option we're using */
for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
if (match_netid(delay_conf->netid, netid, 0))
break;
if (!delay_conf)
/* No match, look for one without a netid */
for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
if (match_netid(delay_conf->netid, netid, 1))
break;
if (delay_conf)
{
if (!option_bool(OPT_QUIET_DHCP))
my_syslog(MS_DHCP | LOG_INFO, _("%u reply delay: %d"), ntohl(xid), delay_conf->delay);
delay_dhcp(recvtime, delay_conf->delay, -1, 0, 0);
}
}
#endif

View File

@@ -20,9 +20,7 @@
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
#ifndef __FreeBSD__
#include <string.h>
#endif
#include <sys/types.h>
#include <sys/ioctl.h>

View File

@@ -382,7 +382,7 @@ void tftp_request(struct listener *listen, time_t now)
if (prefix[strlen(prefix)-1] != '/')
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
if (option_bool(OPT_TFTP_APREF))
if (option_bool(OPT_TFTP_APREF_IP))
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
@@ -394,7 +394,40 @@ void tftp_request(struct listener *listen, time_t now)
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
daemon->namebuff[oldlen] = 0;
}
if (option_bool(OPT_TFTP_APREF_MAC))
{
unsigned char *macaddr = NULL;
unsigned char macbuf[DHCP_CHADDR_MAX];
#ifdef HAVE_DHCP
if (daemon->dhcp && peer.sa.sa_family == AF_INET)
{
/* Check if the client IP is in our lease database */
struct dhcp_lease *lease = lease_find_by_addr(peer.in.sin_addr);
if (lease && lease->hwaddr_type == ARPHRD_ETHER && lease->hwaddr_len == ETHER_ADDR_LEN)
macaddr = lease->hwaddr;
}
#endif
/* If no luck, try to find in ARP table. This only works if client is in same (V)LAN */
if (!macaddr && find_mac(&peer, macbuf, 1, now) > 0)
macaddr = macbuf;
if (macaddr)
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
snprintf(daemon->namebuff + oldlen, (MAXDNAME-1) - oldlen, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x/",
macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
/* remove unique-directory if it doesn't exist */
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
daemon->namebuff[oldlen] = 0;
}
}
/* Absolute pathnames OK if they match prefix */
if (filename[0] == '/')
{
@@ -407,7 +440,7 @@ void tftp_request(struct listener *listen, time_t now)
else if (filename[0] == '/')
daemon->namebuff[0] = 0;
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
/* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len, prefix)))
{

View File

@@ -1,9 +1,10 @@
# The root DNSSEC trust anchor, valid as at 30/01/2014
# The root DNSSEC trust anchor, valid as at 10/02/2017
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D