Compare commits
17 Commits
v2.53
...
v2.60test8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
205fafa577 | ||
|
|
8ecfaa4adf | ||
|
|
03bfcf6462 | ||
|
|
39bec5ff32 | ||
|
|
246839d64a | ||
|
|
3862deb398 | ||
|
|
5954608577 | ||
|
|
984d2fded6 | ||
|
|
a4f04ed45a | ||
|
|
07736e8dcb | ||
|
|
00fc082d68 | ||
|
|
c72daea868 | ||
|
|
74c95c2542 | ||
|
|
7de060b08d | ||
|
|
572b41eb50 | ||
|
|
28866e9567 | ||
|
|
c52e189734 |
3
Android.mk
Normal file
3
Android.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
include $(call all-subdir-makefiles)
|
||||
endif
|
||||
307
CHANGELOG
307
CHANGELOG
@@ -1,3 +1,310 @@
|
||||
version 2.60
|
||||
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
|
||||
Flebbe for the patch.
|
||||
|
||||
Fix DHCP when using --listen-address with an IP address
|
||||
which is not the primary address of an interface.
|
||||
|
||||
Add --dhcp-client-update option.
|
||||
|
||||
Add Lua integration. Dnsmasq can now execute a DHCP
|
||||
lease-change script written in Lua. This needs to be
|
||||
enabled at compile time by setting HAVE_LUASCRIPT in
|
||||
src/config.h or running "make COPTS=-DHAVE_LUASCRIPT"
|
||||
Thanks to Jan-Piet Mens for the idea and proof-of-concept
|
||||
implementation.
|
||||
|
||||
Tidied src/config.h to distinguish between
|
||||
platform-dependent compile-time options which are selected
|
||||
automatically, and builder-selectable compile time
|
||||
options. Document the latter better, and describe how to
|
||||
set them from the make command line.
|
||||
|
||||
Tidied up IPPROTO_IP/SOL_IP (and IPv6 equivalent)
|
||||
confusion. IPPROTO_IP works everywhere now.
|
||||
|
||||
Set TOS on DHCP sockets, this improves things on busy
|
||||
wireless networks. Thanks to Dave Taht for the patch.
|
||||
|
||||
Determine VERSION automatically based on git magic:
|
||||
release tags or hash values.
|
||||
|
||||
|
||||
version 2.59
|
||||
Fix regression in 2.58 which caused failure to start up
|
||||
with some combinations of dnsmasq config and IPv6 kernel
|
||||
network config. Thanks to Brielle Bruns for the bug
|
||||
report.
|
||||
|
||||
Improve dnsmasq's behaviour when network interfaces are
|
||||
still doing duplicate address detection (DAD). Previously,
|
||||
dnsmasq would wait up to 20 seconds at start-up for the
|
||||
DAD state to terminate. This is broken for bridge
|
||||
interfaces on recent Linux kernels, which don't start DAD
|
||||
until the bridge comes up, and so can take arbitrary
|
||||
time. The new behaviour lets dnsmasq poll for an arbitrary
|
||||
time whilst providing service on other interfaces. Thanks
|
||||
to Stephen Hemminger for pointing out the problem.
|
||||
|
||||
|
||||
version 2.58
|
||||
Provide a definition of the SA_SIZE macro where it's
|
||||
missing. Fixes build failure on openBSD.
|
||||
|
||||
Don't include a zero terminator at the end of messages
|
||||
sent to /dev/log when /dev/log is a datagram socket.
|
||||
Thanks to Didier Rabound for spotting the problem.
|
||||
|
||||
Add --dhcp-sequential-ip flag, to force allocation of IP
|
||||
addresses in ascending order. Note that the default
|
||||
pseudo-random mode is in general better but some
|
||||
server-deployment applications need this.
|
||||
|
||||
Fix problem where a server-id of 0.0.0.0 is sent to a
|
||||
client when a dhcp-relay is in use if a client renews a
|
||||
lease after dnsmasq restart and before any clients on the
|
||||
subnet get a new lease. Thanks to Mike Ruiz for assistance
|
||||
in chasing this one down.
|
||||
|
||||
Don't return NXDOMAIN to an AAAA query if we have CNAME
|
||||
which points to an A record only: NODATA is the correct
|
||||
reply in this case. Thanks to Tom Fernandes for spotting
|
||||
the problem.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
Add support for Linux conntrack connection marking. If
|
||||
enabled with --conntrack, the connection mark for incoming
|
||||
DNS queries will be copied to the outgoing connections
|
||||
used to answer those queries. This allows clever firewall
|
||||
and accounting stuff. Only available if dnsmasq is
|
||||
compiled with HAVE_CONNTRACK and adds a dependency on
|
||||
libnetfilter-conntrack. Thanks to Ed Wildgoose for the
|
||||
initial idea, testing and sponsorship of this function.
|
||||
|
||||
Provide a sane error message when someone attempts to
|
||||
match a tag in --dhcp-host.
|
||||
|
||||
Tweak the behaviour of --domain-needed, to avoid problems
|
||||
with recursive nameservers downstream of dnsmasq. The new
|
||||
behaviour only stops A and AAAA queries, and returns
|
||||
NODATA rather than NXDOMAIN replies.
|
||||
|
||||
Efficiency fix for very large DHCP configurations, thanks
|
||||
to James Gartrell and Mike Ruiz for help with this.
|
||||
|
||||
Allow the TFTP-server address in --dhcp-boot to be a
|
||||
domain-name which is looked up in /etc/hosts. This can
|
||||
give multiple IP addresses which are used round-robin,
|
||||
thus doing TFTP server load-balancing. Thanks to Sushil
|
||||
Agrawal for the patch.
|
||||
|
||||
When two tagged dhcp-options for a particular option
|
||||
number are both valid, use the one which is valid without
|
||||
a tag from the dhcp-range. Allows overriding of the value
|
||||
of a DHCP option for a particular host as well as
|
||||
per-network values. So
|
||||
--dhcp-range=set:interface1,......
|
||||
--dhcp-host=set:myhost,.....
|
||||
--dhcp-option=tag:interface1,option:nis-domain,"domain1"
|
||||
--dhcp-option=tag:myhost,option:nis-domain,"domain2"
|
||||
will set the NIS-domain to domain1 for hosts in the range, but
|
||||
override that to domain2 for a particular host.
|
||||
|
||||
Fix bug which resulted in truncated files and timeouts for
|
||||
some TFTP transfers. The bug only occurs with netascii
|
||||
transfers and needs an unfortunate relationship between
|
||||
file size, blocksize and the number of newlines in the
|
||||
last block before it manifests itself. Many thanks to
|
||||
Alkis Georgopoulos for spotting the problem and providing
|
||||
a comprehensive test-case.
|
||||
|
||||
Fix regression in TFTP server on *BSD platforms introduced
|
||||
in version 2.56, due to confusion with sockaddr
|
||||
length. Many thanks to Loïc Pefferkorn for finding this.
|
||||
|
||||
Support scope-ids in IPv6 addresses of nameservers from
|
||||
/etc/resolv.conf and in --server options. Eg
|
||||
nameserver fe80::202:a412:4512:7bbf%eth0 or
|
||||
server=fe80::202:a412:4512:7bbf%eth0. Thanks to
|
||||
Michael Stapelberg for the suggestion.
|
||||
|
||||
Update Polish translation, thanks to Jan Psota.
|
||||
|
||||
Update French translation. Thanks to Gildas Le Nadan.
|
||||
|
||||
|
||||
version 2.57
|
||||
Add patches to allow build under Android.
|
||||
|
||||
Provide our own header for the DNS protocol, rather than
|
||||
relying on arpa/nameser.h. This has proved more or less
|
||||
defective over the years and the final straw is that it's
|
||||
effectively empty on Android.
|
||||
|
||||
Fix regression in 2.56 which caused hex constants in
|
||||
configuration to be rejected if they contain the '*'
|
||||
wildcard.
|
||||
|
||||
Correct wrong casts of arguments to ctype.h functions,
|
||||
isdigit(), isxdigit() etc. Thanks to Matthias Andree for
|
||||
spotting this.
|
||||
|
||||
Allow build with IDN support independently from i18n.
|
||||
IDN support continues to be included automatically
|
||||
when i18n is included.
|
||||
'make COPTS=-DHAVE_IDN' is the magic incantation.
|
||||
|
||||
Modify check on extraneous command line junk (added in
|
||||
2.56) so that it doesn't complain about extra _empty_
|
||||
arguments. Otherwise this breaks libvirt.
|
||||
|
||||
|
||||
version 2.56
|
||||
Add a patch to allow dnsmasq to get interface names right in a
|
||||
Solaris zone. Thanks to Dj Padzensky for this.
|
||||
|
||||
Improve data-type parsing heuristics so that
|
||||
--dhcp-option=option:domain-search,.
|
||||
treats the value as a string and not an IP address.
|
||||
Thanks to Clemens Fischer for spotting that.
|
||||
|
||||
Add IPv6 support to the TFTP server. Many thanks to Jan
|
||||
'RedBully' Seiffert for the patches.
|
||||
|
||||
Log DNS queries at level LOG_INFO, rather then
|
||||
LOG_DEBUG. This makes things consistent with DHCP
|
||||
logging. Thanks to Adam Pribyl for spotting the problem.
|
||||
|
||||
Ensure that dnsmasq terminates cleanly when using
|
||||
--syslog-async even if it cannot make a connection to the
|
||||
syslogd.
|
||||
|
||||
Add --add-mac option. This is to support currently
|
||||
experimental DNS filtering facilities. Thanks to Benjamin
|
||||
Petrin for the orignal patch.
|
||||
|
||||
Fix bug which meant that tags were ignored in dhcp-range
|
||||
configuration specifying PXE-proxy service. Thanks to
|
||||
Cristiano Cumer for spotting this.
|
||||
|
||||
Raise an error if there is extra junk, not part of an
|
||||
option, on the command line.
|
||||
|
||||
Flag a couple of log messages in cache.c as coming from
|
||||
the DHCP subsystem. Thanks to Olaf Westrik for the patch.
|
||||
|
||||
Omit timestamps from logs when a) logging to stderr and
|
||||
b) --keep-in-forground is set. The logging facility on the
|
||||
other end of stderr can be assumned to supply them. Thanks
|
||||
to John Hallam for the patch.
|
||||
|
||||
Don't complain about strings longer than 255 characters in
|
||||
--txt-record, just split the long strings into 255
|
||||
character chunks instead.
|
||||
|
||||
Fix crash on double-free. This bug can only happen when
|
||||
dhcp-script is in use and then only in rare circumstances
|
||||
triggered by high DHCP transaction rate and a slow
|
||||
script. Thanks to Ferenc Wagner for finding the problem.
|
||||
|
||||
Only log that a file has been sent by TFTP after the
|
||||
transfer has completed succesfully.
|
||||
|
||||
A good suggestion from Ferenc Wagner: extend
|
||||
the --domain option to allow this sort of thing:
|
||||
--domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
which automatically creates
|
||||
--local=/thekelleys.org.uk/
|
||||
--local=/0.168.192.in-addr.arpa/
|
||||
|
||||
Tighten up syntax checking of hex contants in the config
|
||||
file. Thanks to Fred Damen for spotting this.
|
||||
|
||||
Add dnsmasq logo/icon, contributed by Justin Swift. Many
|
||||
thanks for that.
|
||||
|
||||
Never cache DNS replies which have the 'cd' bit set, or
|
||||
which result from queries forwarded with the 'cd' bit
|
||||
set. The 'cd' bit instructs a DNSSEC validating server
|
||||
upstream to ignore signature failures and return replies
|
||||
anyway. Without this change it's possible to pollute the
|
||||
dnsmasq cache with bad data by making a query with the
|
||||
'cd' bit set and subsequent queries would return this data
|
||||
without its being marked as suspect. Thanks to Anders
|
||||
Kaseorg for pointing out this problem.
|
||||
|
||||
Add --proxy-dnssec flag, for compliance with RFC
|
||||
4035. Dnsmasq will now clear the 'ad' bit in answers returned
|
||||
from upstream validating nameservers unless this option is
|
||||
set.
|
||||
|
||||
Allow a filename of "-" for --conf-file to read
|
||||
stdin. Suggestion from Timothy Redaelli.
|
||||
|
||||
Rotate the order of SRV records in replies, to provide
|
||||
round-robin load balancing when all the priorities are
|
||||
equal. Thanks to Peter McKinney for the suggestion.
|
||||
|
||||
Edit
|
||||
contrib/MacOSX-launchd/uk.org.thekelleys.dnsmasq.plist
|
||||
so that it doesn't log all queries to a file by
|
||||
default. Thanks again to Peter McKinney.
|
||||
|
||||
By default, setting an IPv4 address for a domain but not
|
||||
an IPv6 address causes dnsmasq to return
|
||||
an NODATA reply for IPv6 (or vice-versa). So
|
||||
--address=/google.com/1.2.3.4 stops IPv6 queries for
|
||||
*google.com from being forwarded. Make it possible to
|
||||
override this behaviour by defining the sematics if the
|
||||
same domain appears in both --server and --address.
|
||||
In that case, the --address has priority for the address
|
||||
family in which is appears, but the --server has priority
|
||||
of the address family which doesn't appear in --adddress
|
||||
So:
|
||||
--address=/google.com/1.2.3.4
|
||||
--server=/google.com/#
|
||||
will return 1.2.3.4 for IPv4 queries for *.google.com but
|
||||
forward IPv6 queries to the normal upstream nameserver.
|
||||
Similarly when setting an IPv6 address
|
||||
only this will allow forwarding of IPv4 queries. Thanks to
|
||||
William for pointing out the need for this.
|
||||
|
||||
Allow more than one --dhcp-optsfile and --dhcp-hostsfile
|
||||
and make them understand directories as arguments in the
|
||||
same way as --addn-hosts. Suggestion from John Hanks.
|
||||
|
||||
Ignore rebinding requests for leases we don't know
|
||||
about. Rebind is broadcast, so we might get to overhear a
|
||||
request meant for another DHCP server. NAKing this is
|
||||
wrong. Thanks to Brad D'Hondt for assistance with this.
|
||||
|
||||
Fix cosmetic bug which produced strange output when
|
||||
dumping cache statistics with some configurations. Thanks
|
||||
to Fedor Kozhevnikov for spotting this.
|
||||
|
||||
|
||||
version 2.55
|
||||
Fix crash when /etc/ethers is in use. Thanks to
|
||||
Gianluigi Tiesi for finding this.
|
||||
|
||||
Fix crash in netlink_multicast(). Thanks to Arno Wald for
|
||||
finding this one.
|
||||
|
||||
Allow the empty domain "." in dhcp domain-search (119)
|
||||
options.
|
||||
|
||||
|
||||
version 2.54
|
||||
There is no version 2.54 to avoid confusion with 2.53,
|
||||
which incorrectly identifies itself as 2.54.
|
||||
|
||||
|
||||
version 2.53
|
||||
Fix failure to compile on Debian/kFreeBSD. Thanks to
|
||||
Axel Beckert and Petr Salinger.
|
||||
|
||||
23
FAQ
23
FAQ
@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through
|
||||
|
||||
Q: What does the dhcp-authoritative option do?
|
||||
|
||||
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's
|
||||
A: See http://www.isc.org/files/auth.html - that's
|
||||
for the ISC daemon, but the same applies to dnsmasq.
|
||||
|
||||
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||
@@ -354,7 +354,7 @@ A: Yes, from version-2.21. The support is only available running under
|
||||
If a physical interface has more than one IP address or aliases
|
||||
with extra IP addresses, then any dhcp-ranges corresponding to
|
||||
these addresses can be used for address allocation. So if an
|
||||
interface has addresses 192.168.1.0/24 and 192.68.2.0/24 and there
|
||||
interface has addresses 192.168.1.0/24 and 192.168.2.0/24 and there
|
||||
are DHCP ranges 192.168.1.100-192.168.1.200 and
|
||||
192.168.2.100-192.168.2.200 then both ranges would be used for host
|
||||
connected to the physical interface. A more typical use might be to
|
||||
@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a
|
||||
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
||||
them, as recommended in RFC2131?
|
||||
|
||||
A: Yes, dynmaically allocated IP addresses are checked by sending an
|
||||
A: Yes, dynamically allocated IP addresses are checked by sending an
|
||||
ICMP echo request (ping). If a reply is received, then dnsmasq
|
||||
assumes that the address is in use, and attempts to allocate an
|
||||
different address. The wait for a reply is between two and three
|
||||
@@ -413,10 +413,11 @@ A: Change your kernel configuration: either deselect CONFIG_SECURITY
|
||||
_or_ select CONFIG_SECURITY_CAPABILITIES. Alternatively, you can
|
||||
remove the need to set capabilities by running dnsmasq as root.
|
||||
|
||||
Q: Where can I get .rpms Suitable for Suse?
|
||||
|
||||
A: Dnsmasq is in Suse itself, and the latest releases are also
|
||||
available at ftp://ftp.suse.com/pub/people/ug/
|
||||
Q: Where can I get .rpms Suitable for openSUSE/SLES?
|
||||
|
||||
A: Dnsmasq is in openSUSE itself, and the latest releases are also
|
||||
available at http://download.opensuse.org/repositories/network/
|
||||
|
||||
|
||||
Q: Can I run dnsmasq in a Linux vserver?
|
||||
@@ -466,8 +467,18 @@ A: The DHCP client on windows Vista (and possibly later versions)
|
||||
work).
|
||||
|
||||
|
||||
Q: DHCP doesn't work with windows 7 but everything else is fine.
|
||||
|
||||
A: There seems to be a problem if Windows 7 doesn't get a value for
|
||||
DHCP option 252 in DHCP packets it gets from the server. The
|
||||
symtoms have beeen variously reported as continual DHCPINFORM
|
||||
requests in an attempt to get an option-252, or even ignoring DHCP
|
||||
offers completely (and failing to get an IP address) if there is no
|
||||
option-252 supplied. DHCP option 252 is for WPAD, WWW Proxy
|
||||
Auto Detection and if you don't want or need to use that, then
|
||||
simplest fix seems to be to supply an empty option with:
|
||||
|
||||
dhcp-option=252,"\n"
|
||||
|
||||
|
||||
|
||||
|
||||
25
Makefile
25
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -32,18 +32,25 @@ SRC = src
|
||||
PO = po
|
||||
MAN = man
|
||||
|
||||
DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
DBUS_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
DBUS_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
CT_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||
CT_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
LUA_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
|
||||
LUA_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
|
||||
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
|
||||
VERSION= -DVERSION='\"`../bld/get-version`\"'
|
||||
|
||||
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o
|
||||
|
||||
all :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS)" \
|
||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS)" \
|
||||
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS)" \
|
||||
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS)" \
|
||||
-f ../Makefile dnsmasq
|
||||
|
||||
clean :
|
||||
@@ -59,9 +66,9 @@ install-common :
|
||||
|
||||
all-i18n :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||
I18N=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||
-f ../Makefile dnsmasq
|
||||
@cd $(PO); for f in *.po; do \
|
||||
cd ../$(SRC) && $(MAKE) \
|
||||
|
||||
18
bld/Android.mk
Normal file
18
bld/Android.mk
Normal file
@@ -0,0 +1,18 @@
|
||||
LOCAL_PATH := external/dnsmasq/src
|
||||
|
||||
#########################
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
forward.c helper.c lease.c log.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
LOCAL_C_INCLUDES := external/dnsmasq/src
|
||||
|
||||
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
28
bld/get-version
Executable file
28
bld/get-version
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Determine the version string to build into a binary.
|
||||
# When building in the git repository, we can use the output
|
||||
# of "git describe" which gives an unequivocal answer.
|
||||
#
|
||||
# Failing that, we use the contents of the VERSION file
|
||||
# which has a set of references substituted into it by git.
|
||||
# If we can find one which matches $v[0-9].* then we assume it's
|
||||
# a version-number tag, else we just use the whole string.
|
||||
|
||||
# we're called with pwd == src
|
||||
cd ..
|
||||
|
||||
if [ -d .git ]; then
|
||||
git describe
|
||||
else
|
||||
vers=`cat VERSION | sed 's/[(), ]/\n/ g' | grep -m 1 $v[0-9]`
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ${vers#v}
|
||||
else
|
||||
cat VERSION
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
search=$1
|
||||
shift
|
||||
|
||||
if grep "^\#.*define.*$search" config.h 2>&1 >/dev/null || \
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h 2>&1 >/dev/null || \
|
||||
grep $search 2>&1 >/dev/null ; then
|
||||
exec $*
|
||||
fi
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
<array>
|
||||
<string>/usr/local/sbin/dnsmasq</string>
|
||||
<string>--keep-in-foreground</string>
|
||||
<string>--log-queries</string>
|
||||
<string>--log-facility=/var/log/dnsmasq.log</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
54
contrib/conntrack/README
Normal file
54
contrib/conntrack/README
Normal file
@@ -0,0 +1,54 @@
|
||||
Linux iptables includes that ability to mark individual network packets
|
||||
with a "firewall mark". Additionally there is a component called
|
||||
"conntrack" which tries to string sequences of related packets together
|
||||
into a "connection" (it even relates sequences of UDP and ICMP packets).
|
||||
There is a related mark for a connection called a "connection mark".
|
||||
Marks can be copied freely between the firewall and connection marks
|
||||
|
||||
Using these two features it become possible to tag all related traffic
|
||||
in arbitrary ways, eg authenticated users, traffic from a particular IP,
|
||||
port, etc. Unfortunately any kind of "proxy" breaks this relationship
|
||||
because network packets go in one side of the proxy and a completely new
|
||||
connection comes out of the other side. However, sometimes, we want to
|
||||
maintain that relationship through the proxy and continue the connection
|
||||
mark on packets upstream of our proxy
|
||||
|
||||
DNSMasq includes such a feature enabled by the --conntrack
|
||||
option. This allows, for example, using iptables to mark traffic from
|
||||
a particular IP, and that mark to be persisted to requests made *by*
|
||||
DNSMasq. Such a feature could be useful for bandwidth accounting,
|
||||
captive portals and the like. Note a similar feature has been
|
||||
implemented in Squid 2.2
|
||||
|
||||
|
||||
As an example consider the following iptables rules:
|
||||
|
||||
|
||||
1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
|
||||
2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
|
||||
-j MARK --set-mark 137
|
||||
3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
|
||||
|
||||
4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
|
||||
|
||||
1-3) are all applied to the PREROUTING table and affect all packets
|
||||
entering the firewall.
|
||||
|
||||
1) copies any existing connection mark into the firewall mark. 2) Checks
|
||||
the packet not already marked and if not applies an arbitrary mark based
|
||||
on IP address. 3) Saves the firewall mark back to the connection mark
|
||||
(which will persist it across related packets)
|
||||
|
||||
4) is applied to the OUTPUT table, which is where we first see packets
|
||||
generated locally. DNSMasq will have already copied the firewall mark
|
||||
from the request, across to the new packet, and so all that remains is
|
||||
for iptables to copy it to the connection mark so it's persisted across
|
||||
packets.
|
||||
|
||||
Note: iptables can be quite confusing to the beginner. The following
|
||||
diagram is extremely helpful in understanding the flows
|
||||
http://linux-ip.net/nf/nfk-traversal.png
|
||||
Additionally the following URL contains a useful "starting guide" on
|
||||
linux connection tracking/marking
|
||||
http://home.regit.org/netfilter-en/netfilter-connmark/
|
||||
|
||||
16
contrib/systemd/README
Normal file
16
contrib/systemd/README
Normal file
@@ -0,0 +1,16 @@
|
||||
Hello,
|
||||
|
||||
I created a systemd service file for dnsmasq.
|
||||
systemd is a sysvinit replacement (see [1] for more information).
|
||||
One of the goals of systemd is to encourage standardization between different
|
||||
distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
|
||||
I would like to ask you to accept this service file as the upstream
|
||||
distributor, so that other distributions can use the same service file and
|
||||
don’t have to ship their own.
|
||||
|
||||
Please include this file in your next release (just like in init script).
|
||||
|
||||
|
||||
[1] http://en.wikipedia.org/wiki/Systemd
|
||||
|
||||
|
||||
12
contrib/systemd/dnsmasq.service
Normal file
12
contrib/systemd/dnsmasq.service
Normal file
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=A lightweight DHCP and caching DNS server
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=uk.org.thekelleys.dnsmasq
|
||||
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
ExecStart=/usr/sbin/dnsmasq -k
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
23
contrib/wrt/dhcp_lease_time.1
Normal file
23
contrib/wrt/dhcp_lease_time.1
Normal file
@@ -0,0 +1,23 @@
|
||||
.TH DHCP_LEASE_TIME 1
|
||||
.SH NAME
|
||||
dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
|
||||
.SH SYNOPSIS
|
||||
.B dhcp_lease_time <address>
|
||||
.SH "DESCRIPTION"
|
||||
Send a DHCPINFORM message to a dnsmasq server running on the local host
|
||||
and print (to stdout) the time remaining in any lease for the given
|
||||
address. The time is given as string printed to stdout.
|
||||
|
||||
If an error occurs or no lease exists for the given address,
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
|
||||
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||
|
||||
|
||||
35
contrib/wrt/dhcp_release.1
Normal file
35
contrib/wrt/dhcp_release.1
Normal file
@@ -0,0 +1,35 @@
|
||||
.TH DHCP_RELEASE 1
|
||||
.SH NAME
|
||||
dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
|
||||
.SH SYNOPSIS
|
||||
.B dhcp_release <interface> <address> <MAC address> <client_id>
|
||||
.SH "DESCRIPTION"
|
||||
A utility which forces the DHCP server running on this machine to release a
|
||||
DHCP lease.
|
||||
.PP
|
||||
Send a DHCPRELEASE message via the specified interface to tell the
|
||||
local DHCP server to delete a particular lease.
|
||||
|
||||
The interface argument is the interface in which a DHCP
|
||||
request _would_ be received if it was coming from the client,
|
||||
rather than being faked up here.
|
||||
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
|
||||
The MAC address is colon separated hex, and is mandatory. It may be
|
||||
prefixed by an address-type byte followed by -, eg
|
||||
|
||||
10-11:22:33:44:55:66
|
||||
|
||||
but if the address-type byte is missing it is assumed to be 1, the type
|
||||
for ethernet. This encoding is the one used in dnsmasq lease files.
|
||||
|
||||
The client-id is optional. If it is "*" then it treated as being missing.
|
||||
.SH NOTES
|
||||
MUST be run as root - will fail otherwise.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
}
|
||||
|
||||
static struct in_addr find_interface(struct in_addr client, int fd, int index)
|
||||
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
|
||||
1011
debian/changelog
vendored
Normal file
1011
debian/changelog
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
debian/conffiles
vendored
Normal file
6
debian/conffiles
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/etc/init.d/dnsmasq
|
||||
/etc/default/dnsmasq
|
||||
/etc/dnsmasq.conf
|
||||
/etc/resolvconf/update.d/dnsmasq
|
||||
/etc/dbus-1/system.d/dnsmasq.conf
|
||||
/etc/insserv.conf.d/dnsmasq
|
||||
41
debian/control
vendored
Normal file
41
debian/control
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
Source: dnsmasq
|
||||
Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Standards-Version: 3.9.2
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
Dnsmasq is a lightweight, easy to configure, DNS forwarder and DHCP
|
||||
server. It is designed to provide DNS and optionally, DHCP, to a
|
||||
small network. It can serve the names of local machines which are
|
||||
not in the global DNS. The DHCP server integrates with the DNS
|
||||
server and allows machines with DHCP-allocated addresses
|
||||
to appear in the DNS with names configured either in each host or
|
||||
in a central configuration file. Dnsmasq supports static and dynamic
|
||||
DHCP leases and BOOTP/TFTP for network booting of diskless machines.
|
||||
|
||||
Package: dnsmasq-base
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: dnsmasq (<<2.41)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
that, install the dnsmasq package.
|
||||
|
||||
Package: dnsmasq-utils
|
||||
Architecture: linux-any
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: dnsmasq (<<2.40)
|
||||
Description: Utilities for manipulating DHCP leases
|
||||
Small utilities to query a DHCP server's lease database and
|
||||
remove leases from it. These programs are distributed with dnsmasq
|
||||
and may not work correctly with other DHCP servers.
|
||||
|
||||
|
||||
21
debian/copyright
vendored
Normal file
21
debian/copyright
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
On Debian GNU/Linux systems, the text of the GNU general public license is
|
||||
available in the file /usr/share/common-licenses/GPL-2 or
|
||||
/usr/share/common-licenses/GPL-3
|
||||
|
||||
The Debian package of dnsmasq was created by Simon Kelley with assistance
|
||||
from Lars Bahner.
|
||||
|
||||
18
debian/dbus.conf
vendored
Normal file
18
debian/dbus.conf
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||
</policy>
|
||||
<policy user="dnsmasq">
|
||||
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||
</policy>
|
||||
<policy context="default">
|
||||
<deny own="uk.org.thekelleys.dnsmasq"/>
|
||||
<deny send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
|
||||
33
debian/default
vendored
Normal file
33
debian/default
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# This file has five functions:
|
||||
# 1) to completely disable starting dnsmasq,
|
||||
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
|
||||
# 3) to select an alternative config file
|
||||
# by setting DNSMASQ_OPTS to --conf-file=<file>
|
||||
# 4) to tell dnsmasq to read the files in /etc/dnsmasq.d for
|
||||
# more configuration variables.
|
||||
# 5) to stop the resolvconf package from controlling dnsmasq's
|
||||
# idea of which upstream nameservers to use.
|
||||
# For upgraders from very old versions, all the shell variables set
|
||||
# here in previous versions are still honored by the init script
|
||||
# so if you just keep your old version of this file nothing will break.
|
||||
|
||||
#DOMAIN_SUFFIX=`dnsdomainname`
|
||||
#DNSMASQ_OPTS="--conf-file=/etc/dnsmasq.alt"
|
||||
|
||||
# Whether or not to run the dnsmasq daemon; set to 0 to disable.
|
||||
ENABLED=1
|
||||
|
||||
# By default search this drop directory for configuration options.
|
||||
# Libvirt leaves a file here to make the system dnsmasq play nice.
|
||||
# Comment out this line if you don't want this. The dpkg-* are file
|
||||
# endings which cause dnsmasq to skip that file. This avoids pulling
|
||||
# in backups made by dpkg.
|
||||
CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||
|
||||
# If the resolvconf package is installed, dnsmasq will use its output
|
||||
# rather than the contents of /etc/resolv.conf to find upstream
|
||||
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||
# Not that including a "resolv-file=<filename>" line in
|
||||
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||
# installed: the line below must be uncommented.
|
||||
#IGNORE_RESOLVCONF=yes
|
||||
266
debian/init
vendored
Normal file
266
debian/init
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: dnsmasq
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop: $network $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Description: DHCP and DNS server
|
||||
### END INIT INFO
|
||||
|
||||
set +e # Don't exit on error status
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=/usr/sbin/dnsmasq
|
||||
NAME=dnsmasq
|
||||
DESC="DNS forwarder and DHCP server"
|
||||
|
||||
# Most configuration options in /etc/default/dnsmasq are deprecated
|
||||
# but still honoured.
|
||||
ENABLED=1
|
||||
if [ -r /etc/default/$NAME ]; then
|
||||
. /etc/default/$NAME
|
||||
fi
|
||||
|
||||
# Get the system locale, so that messages are in the correct language, and the
|
||||
# charset for IDN is correct
|
||||
if [ -r /etc/default/locale ]; then
|
||||
. /etc/default/locale
|
||||
export LANG
|
||||
fi
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
# Provide skeleton LSB log functions for backports which don't have LSB functions.
|
||||
if [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
log_warning_msg () {
|
||||
echo "${@}."
|
||||
}
|
||||
|
||||
log_success_msg () {
|
||||
echo "${@}."
|
||||
}
|
||||
|
||||
log_daemon_msg () {
|
||||
echo -n "${1}: $2"
|
||||
}
|
||||
|
||||
log_end_msg () {
|
||||
if [ $1 -eq 0 ]; then
|
||||
echo "."
|
||||
elif [ $1 -eq 255 ]; then
|
||||
/bin/echo -e " (warning)."
|
||||
else
|
||||
/bin/echo -e " failed!"
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
# RESOLV_CONF:
|
||||
# If the resolvconf package is installed then use the resolv conf file
|
||||
# that it provides as the default. Otherwise use /etc/resolv.conf as
|
||||
# the default.
|
||||
#
|
||||
# If IGNORE_RESOLVCONF is set in /etc/default/dnsmasq or an explicit
|
||||
# filename is set there then this inhibits the use of the resolvconf-provided
|
||||
# information.
|
||||
#
|
||||
# Note that if the resolvconf package is installed it is not possible to
|
||||
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
|
||||
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
|
||||
|
||||
if [ ! "$RESOLV_CONF" ] &&
|
||||
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
|
||||
[ -x /sbin/resolvconf ]
|
||||
then
|
||||
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
|
||||
fi
|
||||
|
||||
for INTERFACE in $DNSMASQ_INTERFACE; do
|
||||
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -i $INTERFACE"
|
||||
done
|
||||
|
||||
for INTERFACE in $DNSMASQ_EXCEPT; do
|
||||
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -I $INTERFACE"
|
||||
done
|
||||
|
||||
if [ ! "$DNSMASQ_USER" ]; then
|
||||
DNSMASQ_USER="dnsmasq"
|
||||
fi
|
||||
|
||||
start()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been started
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
|
||||
# /var/run may be volatile, so we need to ensure that
|
||||
# /var/run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
|
||||
fi
|
||||
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||
-x /var/run/dnsmasq/$NAME.pid \
|
||||
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||
${MAILTARGET:+ -t $MAILTARGET} \
|
||||
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
|
||||
${DHCP_LEASE:+ -l $DHCP_LEASE} \
|
||||
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
|
||||
${RESOLV_CONF:+ -r $RESOLV_CONF} \
|
||||
${CACHESIZE:+ -c $CACHESIZE} \
|
||||
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
|
||||
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} \
|
||||
|| return 2
|
||||
}
|
||||
|
||||
start_resolvconf()
|
||||
{
|
||||
# If interface "lo" is explicitly disabled in /etc/default/dnsmasq
|
||||
# Then dnsmasq won't be providing local DNS, so don't add it to
|
||||
# the resolvconf server set.
|
||||
for interface in $DNSMASQ_EXCEPT
|
||||
do
|
||||
[ $interface = lo ] && return
|
||||
done
|
||||
|
||||
if [ -x /sbin/resolvconf ] ; then
|
||||
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been stopped
|
||||
# 1 if daemon was already stopped
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
return "$RETVAL"
|
||||
}
|
||||
|
||||
stop_resolvconf()
|
||||
{
|
||||
if [ -x /sbin/resolvconf ] ; then
|
||||
/sbin/resolvconf -d lo.$NAME
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
status()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon is running
|
||||
# 1 if daemon is dead and pid file exists
|
||||
# 3 if daemon is not running
|
||||
# 4 if daemon status is unknown
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||
case "$?" in
|
||||
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||
1) return 0 ;;
|
||||
*) return 4 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
test "$ENABLED" != "0" || exit 0
|
||||
log_daemon_msg "Starting $DESC" "$NAME"
|
||||
start
|
||||
case "$?" in
|
||||
0)
|
||||
log_end_msg 0
|
||||
start_resolvconf
|
||||
exit 0
|
||||
;;
|
||||
1)
|
||||
log_success_msg "(already running)"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_end_msg 1
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
stop)
|
||||
stop_resolvconf
|
||||
if [ "$ENABLED" != "0" ]; then
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
fi
|
||||
stop
|
||||
RETVAL="$?"
|
||||
if [ "$ENABLED" = "0" ]; then
|
||||
case "$RETVAL" in
|
||||
0) log_daemon_msg "Stopping $DESC" "$NAME"; log_end_msg 0 ;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
case "$RETVAL" in
|
||||
0) log_end_msg 0 ; exit 0 ;;
|
||||
1) log_warning_msg "(not running)" ; exit 0 ;;
|
||||
*) log_end_msg 1; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
restart|force-reload)
|
||||
test "$ENABLED" != "0" || exit 1
|
||||
$DAEMON --test ${CONFIG_DIR:+ -7 $CONFIG_DIR} ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
NAME="configuration syntax check"
|
||||
RETVAL="2"
|
||||
else
|
||||
stop_resolvconf
|
||||
stop
|
||||
RETVAL="$?"
|
||||
fi
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
case "$RETVAL" in
|
||||
0|1)
|
||||
sleep 2
|
||||
start
|
||||
case "$?" in
|
||||
0)
|
||||
log_end_msg 0
|
||||
start_resolvconf
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_end_msg 1
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
log_end_msg 1
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
log_daemon_msg "Checking $DESC" "$NAME"
|
||||
status
|
||||
case "$?" in
|
||||
0) log_success_msg "(running)" ; exit 0 ;;
|
||||
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
|
||||
3) log_success_msg "(not running)" ; exit 3 ;;
|
||||
*) log_success_msg "(unknown)" ; exit 4 ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
1
debian/insserv
vendored
Normal file
1
debian/insserv
vendored
Normal file
@@ -0,0 +1 @@
|
||||
$named dnsmasq
|
||||
49
debian/postinst
vendored
Normal file
49
debian/postinst
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# create a user to run as (code stolen from dovecot-common)
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||
--no-create-home --disabled-password \
|
||||
--quiet dnsmasq || true
|
||||
fi
|
||||
|
||||
# Make the directory where we keep the pid file - this
|
||||
# has to be owned by "dnsmasq" do that the file can be unlinked.
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||
fi
|
||||
|
||||
# handle new location of pidfile during an upgrade
|
||||
if [ -e /var/run/dnsmasq.pid ]; then
|
||||
mv /var/run/dnsmasq.pid /var/run/dnsmasq
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -x /etc/init.d/dnsmasq ]; then
|
||||
update-rc.d dnsmasq defaults 15 85 >/dev/null
|
||||
|
||||
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
|
||||
if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then
|
||||
ACTION=restart
|
||||
else
|
||||
ACTION=start
|
||||
fi
|
||||
|
||||
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||
invoke-rc.d dnsmasq $ACTION || true
|
||||
else
|
||||
/etc/init.d/dnsmasq $ACTION || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# dpkg can botch the change of /usr/share/doc/dnsmasq from
|
||||
# directory to symlink. Fix up here.
|
||||
if [ ! -h /usr/share/doc/dnsmasq ] && { rmdir /usr/share/doc/dnsmasq; }; then
|
||||
cd /usr/share/doc/
|
||||
ln -s /usr/share/doc/dnsmasq-base dnsmasq
|
||||
fi
|
||||
|
||||
12
debian/postrm
vendored
Normal file
12
debian/postrm
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ purge = "$1" ]; then
|
||||
update-rc.d dnsmasq remove >/dev/null
|
||||
if [ -x "$(command -v deluser)" ]; then
|
||||
deluser --quiet --system dnsmasq > /dev/null || true
|
||||
else
|
||||
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||
fi
|
||||
rm -rf /var/run/dnsmasq
|
||||
fi
|
||||
14
debian/prerm
vendored
Normal file
14
debian/prerm
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ "$1" = "remove" ]; then
|
||||
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||
invoke-rc.d dnsmasq stop || true
|
||||
else
|
||||
/etc/init.d/dnsmasq stop || true
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
70
debian/readme
vendored
Normal file
70
debian/readme
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
Notes on configuring dnsmasq as packaged for Debian.
|
||||
|
||||
(1) To configure dnsmasq edit /etc/dnsmasq.conf. The file is well
|
||||
commented; see also the dnsmasq.8 man page for explanation of
|
||||
the options. The file /etc/default/dnsmasq also exists but it
|
||||
shouldn't need to be touched in most cases. To set up DHCP
|
||||
options you might need to refer to a copy of RFC 2132. This is
|
||||
available on Debian systems in the package doc-rfc-std as the file
|
||||
/usr/share/doc/RFC/draft-standard/rfc2132.txt.gz .
|
||||
|
||||
(2) Installing the dnsmasq package also creates the directory
|
||||
/etc/dnsmasq.d which is searched by dnsmasq for configuration file
|
||||
fragments. This behaviour can be disabled by editing
|
||||
/etc/default/dnsmasq.
|
||||
|
||||
(3) If the Debian resolvconf package is installed then, regardless
|
||||
of what interface configuration daemons are employed, the list of
|
||||
nameservers to which dnsmasq should forward queries can be found
|
||||
in /var/run/dnsmasq/resolv.conf; also, 127.0.0.1 is listed as the
|
||||
first nameserver address in /etc/resolv.conf. This works using the
|
||||
default configurations of resolvconf and dnsmasq.
|
||||
|
||||
(4) In the absence of resolvconf, if you are using dhcpcd then
|
||||
dnsmasq should read the list of nameservers from the automatically
|
||||
generated file /etc/dhcpc/resolv.conf. You should list 127.0.0.1
|
||||
as the first nameserver address in /etc/resolv.conf.
|
||||
|
||||
(5) In the absence of resolvconf, if you are using pppd then
|
||||
dnsmasq should read the list of nameservers from the automatically
|
||||
generated file /etc/ppp/resolv.conf. You should list 127.0.0.1
|
||||
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
|
||||
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.
|
||||
|
||||
(7) If you run multiple DNS servers on a single machine, each
|
||||
listening on a different interface, then it is necessary to use
|
||||
the bind-interfaces option by uncommenting "bind-interfaces" in
|
||||
/etc/dnsmasq.conf. This option stops dnsmasq from binding the
|
||||
wildcard address and allows servers listening on port 53 on
|
||||
interfaces not in use by dnsmasq to work. The Debian
|
||||
libvirt package will add a configuration file in /etc/dnsmasq.d
|
||||
which does this so that the "system" dnsmasq and "private" dnsmasq
|
||||
instances started by libvirt do not clash.
|
||||
|
||||
(8) The following options are supported in DEB_BUILD_OPTIONS
|
||||
noopt : compile without optimisation.
|
||||
nostrip : don't remove symbols from binary.
|
||||
nodocs : omit documentation.
|
||||
notftp : omit TFTP support.
|
||||
nodhcp : omit DHCP support.
|
||||
noscript : omit lease-change script support.
|
||||
noipv6 : omit IPv6 support.
|
||||
nodbus : omit DBus support.
|
||||
noconntrack : omit connection tracking support.
|
||||
nortc : compile alternate mode suitable for systems without an RTC.
|
||||
noi18n : omit translations and internationalisation support.
|
||||
noidn : omit international domain name support, must be
|
||||
combined with noi18n to be effective.
|
||||
|
||||
(9) Dnsmasq comes as two packages - dnsmasq-base and
|
||||
dnsmasq. dnsmasq-base provides the dnsmasq executable and
|
||||
documentation (including this file). Dnsmasq, which depends on
|
||||
dnsmasq-base, provides the init script and configuration
|
||||
infrastructure. This file assumes that both are installed. It is
|
||||
possible to install only dnsmasq-base and use dnsmasq as a
|
||||
non-"system" daemon. Libvirt, for instance, does this.
|
||||
7
debian/readme.dnsmasq.d
vendored
Normal file
7
debian/readme.dnsmasq.d
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# All files in this directory will be read by dnsmasq as
|
||||
# configuration files, except if their names end in
|
||||
# ".dpkg-dist",".dpkg-old" or ".dpkg-new"
|
||||
#
|
||||
# This can be changed by editing /etc/default/dnsmasq
|
||||
|
||||
|
||||
70
debian/resolvconf
vendored
Normal file
70
debian/resolvconf
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to update the resolver list for dnsmasq
|
||||
#
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||
# If dnsmasq is installed then we go ahead and update
|
||||
# the resolver list in case dnsmasq is started later.
|
||||
#
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||
#
|
||||
# Requires bash because it uses a non-POSIX printf extension.
|
||||
#
|
||||
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||
|
||||
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||
|
||||
PATH=/bin:/sbin
|
||||
|
||||
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||
|
||||
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||
# Doesn't work properly if an argument itself contain whitespace
|
||||
uniquify()
|
||||
{
|
||||
RSLT=""
|
||||
while [ "$1" ] ; do
|
||||
for E in $RSLT ; do
|
||||
[ "$1" = "$E" ] && { shift ; continue 2 ; }
|
||||
done
|
||||
RSLT="${RSLT:+$RSLT }$1"
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||
report_err "Failed trying to create directory $RUN_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||
|
||||
NMSRVRS=""
|
||||
if [ "$RSLVCNFFILES" ] ; then
|
||||
uniquify $(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]\+//p' $RSLVCNFFILES)
|
||||
NMSRVRS="$RSLT"
|
||||
fi
|
||||
|
||||
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||
# within one second of the previous one then dnsmasq may fail to notice the
|
||||
# more recent change. To work around this problem we sleep here to ensure
|
||||
# that the new mtime is different.
|
||||
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
clean_up() { rm -f "$TMP_FILE" ; }
|
||||
trap clean_up EXIT
|
||||
: >| "$TMP_FILE"
|
||||
for N in $NMSRVRS ; do echo "nameserver $N" >> "$TMP_FILE" ; done
|
||||
mv -f "$TMP_FILE" "$RSLVRLIST_FILE"
|
||||
|
||||
13
debian/resolvconf-package
vendored
Normal file
13
debian/resolvconf-package
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# Resolvconf packaging event hook script for the dnsmasq package
|
||||
restart_dnsmasq() {
|
||||
if which invoke-rc.d >/dev/null 2>&1 ; then
|
||||
invoke-rc.d dnsmasq restart
|
||||
elif [ -x /etc/init.d/dnsmasq ] ; then
|
||||
/etc/init.d/dnsmasq restart
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
install) restart_dnsmasq ;;
|
||||
esac
|
||||
186
debian/rules
vendored
Executable file
186
debian/rules
vendored
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/make -f
|
||||
# debian/rules file - for dnsmasq.
|
||||
# Copyright 2001-2011 by Simon Kelley
|
||||
# Based on the sample in the debian hello package which carries the following:
|
||||
# Copyright 1994,1995 by Ian Jackson.
|
||||
# I hereby give you perpetual unlimited permission to copy,
|
||||
# modify and relicense this file, provided that you do not remove
|
||||
# my name from the file itself. (I assert my moral right of
|
||||
# paternity under the Copyright, Designs and Patents Act 1988.)
|
||||
# This file may have to be extensively modified
|
||||
|
||||
package=dnsmasq-base
|
||||
|
||||
# policy manual, section 10.1
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS = -g -O0 -Wall -W
|
||||
else
|
||||
CFLAGS = -g -O2 -Wall -W
|
||||
endif
|
||||
|
||||
COPTS =
|
||||
TARGET = install-i18n
|
||||
|
||||
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||
|
||||
ifeq (,$(findstring nodbus,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_DBUS
|
||||
endif
|
||||
|
||||
ifeq (,$(findstring noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
COPTS += -DHAVE_CONNTRACK
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring noipv6,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_IPV6
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring notftp,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_TFTP
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring nodhcp,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_DHCP
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring noscript,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_SCRIPT
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring nortc,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_BROKEN_RTC
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring noi18n,$(DEB_BUILD_OPTIONS)))
|
||||
TARGET = install
|
||||
ifeq (,$(findstring noidn, $(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_IDN
|
||||
endif
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
make clean
|
||||
make -C contrib/wrt clean
|
||||
|
||||
binary-indep: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon
|
||||
install -m 755 \
|
||||
-d debian/daemon/DEBIAN \
|
||||
-d debian/daemon/usr/share/doc \
|
||||
-d debian/daemon/etc/init.d \
|
||||
-d debian/daemon/etc/dnsmasq.d \
|
||||
-d debian/daemon/etc/resolvconf/update.d \
|
||||
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/daemon/etc/default \
|
||||
-d debian/daemon/etc/dbus-1/system.d \
|
||||
-d debian/daemon/lib/systemd/system \
|
||||
-d debian/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
|
||||
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
|
||||
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
|
||||
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
|
||||
install -m 644 debian/dbus.conf debian/daemon/etc/dbus-1/system.d/dnsmasq.conf
|
||||
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
|
||||
chown -R root.root debian/daemon
|
||||
chmod -R g-ws debian/daemon
|
||||
dpkg --build debian/daemon ..
|
||||
|
||||
binary-arch: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/base
|
||||
install -m 755 \
|
||||
-d debian/base/DEBIAN \
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/var/run \
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog
|
||||
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
endif
|
||||
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
|
||||
for f in debian/base/usr/share/man/*; do \
|
||||
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||
gzip -9 $$f/man8/dnsmasq.8 ; \
|
||||
fi \
|
||||
done
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||
endif
|
||||
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
|
||||
chown -R root.root debian/base
|
||||
chmod -R g-ws debian/base
|
||||
dpkg --build debian/base ..
|
||||
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
rm -rf debian/utils
|
||||
install -m 755 -d debian/utils/DEBIAN \
|
||||
-d debian/utils/usr/share/man/man1 \
|
||||
-d debian/utils/usr/bin \
|
||||
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
endif
|
||||
|
||||
define checkdir
|
||||
test -f Makefile -a -f debian/rules
|
||||
endef
|
||||
|
||||
# Below here is fairly generic really
|
||||
|
||||
binary: binary-arch binary-indep
|
||||
build:
|
||||
|
||||
checkroot:
|
||||
test root = "`whoami`"
|
||||
|
||||
.PHONY: binary binary-arch binary-indep clean checkroot
|
||||
|
||||
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0
|
||||
31
debian/systemd.service
vendored
Normal file
31
debian/systemd.service
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
[Unit]
|
||||
Description=A lightweight DHCP and caching DNS server
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=uk.org.thekelleys.dnsmasq
|
||||
|
||||
# Test the config file and refuse starting if it is not valid.
|
||||
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
|
||||
# Enable DBus by default because we use DBus activation.
|
||||
#
|
||||
# Drop privileges and become the 'dnsmasq' user. It is recommended by dnsmasq
|
||||
# upstream to run dnsmasq as an isolated user that does not run any other
|
||||
# processes, owns no files and has no shell. The default 'nobody' user has a
|
||||
# shell and might be used for other processes.
|
||||
#
|
||||
# Debian-specific: add /etc/dnsmasq.d to config search path (with the exception
|
||||
# of .dpkg-*). Packages such as libvirt leave config files there.
|
||||
#
|
||||
# --pid-file without argument disables writing a PIDfile, we don't need one.
|
||||
ExecStart=/usr/sbin/dnsmasq -k \
|
||||
--enable-dbus \
|
||||
--user=dnsmasq \
|
||||
-7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new \
|
||||
--pid-file
|
||||
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -7,8 +7,8 @@
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
# uneccessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link uneccessarily.
|
||||
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link unnecessarily.
|
||||
|
||||
# Never forward plain names (without a dot or domain part)
|
||||
#domain-needed
|
||||
@@ -48,7 +48,7 @@
|
||||
# non-public domains.
|
||||
#server=/localnet/192.168.0.1
|
||||
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||
|
||||
@@ -57,14 +57,14 @@
|
||||
#local=/localnet/
|
||||
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in doubleclick.net to a local
|
||||
# webserver.
|
||||
#address=/doubleclick.net/127.0.0.1
|
||||
# The example below send any host in double-click.net to a local
|
||||
# web-server.
|
||||
#address=/double-click.net/127.0.0.1
|
||||
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
#listen-address=
|
||||
# If you want dnsmasq to provide only DNS service on an interface,
|
||||
# configure it as shown above, and then use the following line to
|
||||
# disable DHCP on it.
|
||||
# disable DHCP and TFTP on it.
|
||||
#no-dhcp-interface=
|
||||
|
||||
# On systems which support it, dnsmasq binds the wildcard address,
|
||||
@@ -145,7 +145,7 @@
|
||||
# some DHCP options may be set only for this network.
|
||||
#dhcp-range=set:red,192.168.0.50,192.168.0.150
|
||||
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# Specify a subnet which can't be used for dynamic address allocation,
|
||||
@@ -153,17 +153,18 @@
|
||||
# dhcp-host declarations will be ignored unless there is a dhcp-range
|
||||
# of some type for the subnet in question.
|
||||
# In this case the netmask is implied (it comes from the network
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explict netmask instead.
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explicit netmask instead.
|
||||
#dhcp-range=192.168.0.0,static
|
||||
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
# need to be on the same network. The order of the parameters in these
|
||||
# do not matter, it's permissble to give name,adddress and MAC in any order
|
||||
# do not matter, it's permissible to give name, address and MAC in any
|
||||
# order.
|
||||
|
||||
# Always allocate the host with ethernet address 11:22:33:44:55:66
|
||||
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||
# The IP address 192.168.0.60
|
||||
#dhcp-host=11:22:33:44:55:66,192.168.0.60
|
||||
|
||||
@@ -171,13 +172,13 @@
|
||||
# 11:22:33:44:55:66 to be "fred"
|
||||
#dhcp-host=11:22:33:44:55:66,fred
|
||||
|
||||
# Always give the host with ethernet address 11:22:33:44:55:66
|
||||
# Always give the host with Ethernet address 11:22:33:44:55:66
|
||||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||
|
||||
# Give a host with ethernet address 11:22:33:44:55:66 or
|
||||
# Give a host with Ethernet address 11:22:33:44:55:66 or
|
||||
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
|
||||
# that these two ethernet interfaces will never be in use at the same
|
||||
# that these two Ethernet interfaces will never be in use at the same
|
||||
# time, and give the IP address to the second, even if it is already
|
||||
# in use by the first. Useful for laptops with wired and wireless
|
||||
# addresses.
|
||||
@@ -200,27 +201,27 @@
|
||||
# it asks for a DHCP lease.
|
||||
#dhcp-host=judge
|
||||
|
||||
# Never offer DHCP service to a machine whose ethernet
|
||||
# Never offer DHCP service to a machine whose Ethernet
|
||||
# address is 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,ignore
|
||||
|
||||
# Ignore any client-id presented by the machine with ethernet
|
||||
# Ignore any client-id presented by the machine with Ethernet
|
||||
# address 11:22:33:44:55:66. This is useful to prevent a machine
|
||||
# being treated differently when running under different OS's or
|
||||
# between PXE boot and OS boot.
|
||||
#dhcp-host=11:22:33:44:55:66,id:*
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# the machine with ethernet address 11:22:33:44:55:66
|
||||
# the machine with Ethernet address 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,set:red
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# any machine with ethernet address starting 11:22:33:
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Ignore any clients which are specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unkown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
#dhcp-ignore=tag:!known
|
||||
|
||||
@@ -244,11 +245,11 @@
|
||||
|
||||
# Send options to hosts which ask for a DHCP lease.
|
||||
# See RFC 2132 for details of available options.
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# run "dnsmasq --help dhcp" to get a list.
|
||||
# Note that all the common settings, such as netmask and
|
||||
# broadcast address, DNS server and default route, are given
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# any dhcp-options. If you use Windows clients and Samba, there
|
||||
# are some options which are recommended, they are detailed at the
|
||||
# end of this section.
|
||||
@@ -262,7 +263,7 @@
|
||||
|
||||
# Override the default route supplied by dnsmasq and send no default
|
||||
# route at all. Note that this only works for the options sent by
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# for all other option numbers.
|
||||
#dhcp-option=3
|
||||
|
||||
@@ -296,13 +297,16 @@
|
||||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# adapted for a typical dnsmasq installation where the host running
|
||||
# dnsmasq is also the host running samba.
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# Windows clients and Samba.
|
||||
#dhcp-option=19,0 # option ip-forwarding off
|
||||
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
|
||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||
#dhcp-option=46,8 # netbios node type
|
||||
|
||||
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||
#dhcp-option=252,"\n"
|
||||
|
||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||
# probably doesn't support this......
|
||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||
@@ -310,10 +314,10 @@
|
||||
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# The meaning of the options is defined by the vendor-class so
|
||||
# options are sent only when the client supplied vendor class
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients.
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
@@ -330,7 +334,7 @@
|
||||
|
||||
# Send options to PXELinux. Note that we need to send the options even
|
||||
# though they don't appear in the parameter request list, so we need
|
||||
# to use dhcp-option-force here.
|
||||
# to use dhcp-option-force here.
|
||||
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||
# Magic number - needed before anything else is recognised
|
||||
#dhcp-option-force=208,f1:00:74:7e
|
||||
@@ -341,24 +345,27 @@
|
||||
# Reboot time. (Note 'i' to send 32-bit value)
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Boot for Etherboot gPXE. The idea is to send two different
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
|
||||
|
||||
# Encapsulated options for Etherboot gPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 189, 1b # BIOS drive code
|
||||
#dhcp-option=encap:175, 190, user # iSCSI username
|
||||
#dhcp-option=encap:175, 191, pass # iSCSI password
|
||||
@@ -368,7 +375,7 @@
|
||||
#dhcp-match=peecees, option:client-arch, 0 #x86-32
|
||||
#dhcp-match=itanics, option:client-arch, 2 #IA64
|
||||
#dhcp-match=hammers, option:client-arch, 6 #x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
|
||||
# Do real PXE, rather than just booting a single file, this is an
|
||||
# alternative to dhcp-boot.
|
||||
@@ -380,11 +387,11 @@
|
||||
#pxe-service=x86PC, "Boot from local disk"
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
|
||||
# Beware this fails on old PXE ROMS.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
|
||||
# Use bootserver on network, found my multicast or broadcast.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1
|
||||
@@ -395,20 +402,20 @@
|
||||
# If you have multicast-FTP available,
|
||||
# information for that can be passed in a similar way using options 1
|
||||
# to 5. See page 19 of
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
|
||||
|
||||
|
||||
# Enable dnsmasq's built-in TFTP server
|
||||
#enable-tftp
|
||||
|
||||
# Set the root directory for files availble via FTP.
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# transfers. It will slow things down, but may rescue some broken TFTP
|
||||
# clients.
|
||||
#tftp-no-blocksize
|
||||
@@ -421,6 +428,14 @@
|
||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||
|
||||
# If there are multiple external tftp servers having a same name
|
||||
# (using /etc/hosts) then that name can be specified as the
|
||||
# tftp_servername (the third option to dhcp-boot) and in that
|
||||
# case dnsmasq resolves this name and returns the resultant IP
|
||||
# addresses in round robin fasion. This facility can be used to
|
||||
# load balance the tftp load among a set of servers.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||
|
||||
# Set the limit on DHCP leases, the default is 150
|
||||
#dhcp-lease-max=150
|
||||
|
||||
@@ -433,16 +448,16 @@
|
||||
# and take over the lease for any client which broadcasts on the network,
|
||||
# whether it has a record of the lease or not. This avoids long timeouts
|
||||
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||
# the slighest chance that you might end up accidentally configuring a DHCP
|
||||
# the slightest chance that you might end up accidentally configuring a DHCP
|
||||
# server for your campus/company accidentally. The ISC server uses
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/index.pl?/sw/dhcp/authoritative.php
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
# if there is one.
|
||||
# if there is one.
|
||||
#dhcp-script=/bin/echo
|
||||
|
||||
# Set the cachesize here.
|
||||
|
||||
35
doc.html
35
doc.html
@@ -1,9 +1,17 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
|
||||
<link rel="icon"
|
||||
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="WHITE">
|
||||
<H1 ALIGN=center>Dnsmasq</H1>
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td align="left" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td>
|
||||
<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
|
||||
<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
|
||||
</table>
|
||||
|
||||
Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
|
||||
server. It is designed to provide DNS and, optionally, DHCP, to a
|
||||
small network. It can serve the names of local machines which are
|
||||
@@ -19,7 +27,7 @@ connection but would be a good choice for any smallish network (up to
|
||||
1000 clients is known to work) where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), *BSD,
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
|
||||
Solaris and Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse, Fedora,
|
||||
@@ -80,24 +88,19 @@ for any or all local machines.
|
||||
</LI>
|
||||
</DIR>
|
||||
|
||||
<H2>Download.</H2>
|
||||
<H2>Get code.</H2>
|
||||
|
||||
<A HREF="http://www.thekelleys.org.uk/dnsmasq/"> Download</A> dnsmasq here.
|
||||
<A HREF="http://www.thekelleys.org.uk/dnsmasq/">Download</A> dnsmasq here.
|
||||
The tarball includes this documentation, source, and manpage.
|
||||
There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>.
|
||||
Dnsmasq is part of the Debian distribution, it can be downloaded from
|
||||
<A HREF="http://ftp.debian.org/debian/pool/main/d/dnsmasq/"> here</A> or installed using <TT>apt</TT>.
|
||||
|
||||
<H2>Links.</H2>
|
||||
Damien Raude-Morvan has an article in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
||||
There is a good article about dnsmasq at <A
|
||||
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
|
||||
and another at <A
|
||||
HREF="http://www.linux.com/articles/149040">http://www.linux.com/articles/149040</A>
|
||||
and Ilya Evseev has an article in Russian about dnsmasq to be found at
|
||||
<A HREF="http://ilya-evseev.narod.ru/articles/dnsmasq">
|
||||
http://ilya-evseev.narod.ru/articles/dnsmasq</A>. Ismael Ull has an
|
||||
article about dnsmasq in Spanish at <A HREF="http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq">http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq</A>
|
||||
Dnsmasq has a git repository which contains the complete release
|
||||
history of version 2 and development history from 2.60. You can
|
||||
<A HREF="http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=summary">browse</A>
|
||||
the repo, or get a copy using git protocol with the command
|
||||
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||
for details.
|
||||
|
||||
12
logo/README
Normal file
12
logo/README
Normal file
@@ -0,0 +1,12 @@
|
||||
Dnsmasq logo, contributed by Justin Clift.
|
||||
|
||||
The source format is Inkscape SVG vector format, which is scalable and
|
||||
easy to export to other formats. For convenience I've included a 56x31
|
||||
png export and a 16x16 ico suitable for use as a web favicon.
|
||||
|
||||
Simon Kelley, 22/10/2010
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
logo/favicon.ico
Normal file
BIN
logo/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
logo/icon.png
Normal file
BIN
logo/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
157
logo/icon.svg
Normal file
157
logo/icon.svg
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="56"
|
||||
height="31"
|
||||
viewBox="0 0 56 31"
|
||||
enable-background="new 0 0 72.833 46.667"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="dnsmasq_icon.svg"
|
||||
inkscape:export-filename="/x/centos_home/jc/workspace/git_repos/libvirt-media/libvirt-media/png/dnsmasq_icon.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><metadata
|
||||
id="metadata27"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs25"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 23.3335 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="72.833 : 23.3335 : 1"
|
||||
inkscape:persp3d-origin="36.4165 : 15.555667 : 1"
|
||||
id="perspective4857" />
|
||||
<filter
|
||||
id="filter3802"
|
||||
inkscape:label="filter1"
|
||||
color-interpolation-filters="sRGB" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#SVGID_3_"
|
||||
id="linearGradient4929"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="30.564501"
|
||||
y1="-8.8144999"
|
||||
x2="32.937"
|
||||
y2="32.715599" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#SVGID_3_"
|
||||
id="linearGradient5798"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="30.564501"
|
||||
y1="-8.8144999"
|
||||
x2="32.937"
|
||||
y2="32.715599" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#SVGID_3_"
|
||||
id="linearGradient5812"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="30.564501"
|
||||
y1="-8.8144999"
|
||||
x2="32.937"
|
||||
y2="32.715599" /><filter
|
||||
id="filter6262"
|
||||
inkscape:label="Drop shadow"
|
||||
width="1.5"
|
||||
height="1.5"
|
||||
x="-0.25"
|
||||
y="-0.25"
|
||||
color-interpolation-filters="sRGB"><feGaussianBlur
|
||||
id="feGaussianBlur6264"
|
||||
in="SourceAlpha"
|
||||
stdDeviation="2.500000"
|
||||
result="blur" /><feColorMatrix
|
||||
id="feColorMatrix6266"
|
||||
result="bluralpha"
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /><feOffset
|
||||
id="feOffset6268"
|
||||
in="bluralpha"
|
||||
dx="2.700000"
|
||||
dy="2.600000"
|
||||
result="offsetBlur" /><feMerge
|
||||
id="feMerge6270"><feMergeNode
|
||||
id="feMergeNode6272"
|
||||
in="offsetBlur" /><feMergeNode
|
||||
id="feMergeNode6274"
|
||||
in="SourceGraphic" /></feMerge></filter></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1568"
|
||||
inkscape:window-height="1076"
|
||||
id="namedview23"
|
||||
showgrid="false"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="31.966768"
|
||||
inkscape:cy="21.211869"
|
||||
inkscape:window-x="567"
|
||||
inkscape:window-y="328"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:showpageshadow="false"
|
||||
showborder="true" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="dnsmasq"
|
||||
style="display:inline"
|
||||
transform="translate(5.2838057,-15.545371)"><g
|
||||
id="g3790"
|
||||
transform="matrix(0.8183832,0,0,0.8183832,65.304897,9.8747678)"
|
||||
style="filter:url(#filter6262)"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><g
|
||||
transform="translate(-91.018462,1.0687099)"
|
||||
id="g9">
|
||||
<path
|
||||
style="fill:#6700ad"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path11"
|
||||
d="M 54.997,12.151 C 50.083,9.132 43.29,7.266 35.791,7.266 c -7.5,0 -14.29,1.866 -19.204,4.885 -4.915,3.016 -7.956,7.184 -7.956,11.789 0,4.604 3.041,8.772 7.956,11.788 4.914,3.02 11.704,-4.271 19.204,-4.271 7.499,0 14.292,7.291 19.206,4.271 4.914,-3.016 7.955,-7.185 7.955,-11.788 0,-4.606 -3.041,-8.773 -7.955,-11.789 z M 24.996,24.318 c -2.698,0 -4.885,-0.922 -4.885,-2.061 0,-1.14 2.187,-2.063 4.885,-2.063 2.697,0 4.885,0.924 4.885,2.063 0,1.139 -2.188,2.061 -4.885,2.061 z m 21.501,0.191 c -2.686,0 -4.861,-0.856 -4.861,-1.912 0,-1.054 2.176,-1.911 4.861,-1.911 2.685,0 4.863,0.857 4.863,1.911 0,1.056 -2.178,1.912 -4.863,1.912 z" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffb616;stroke-width:1.85353255"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path13"
|
||||
d="M 54.997,12.151 C 50.083,9.132 43.29,7.266 35.791,7.266 c -7.5,0 -14.29,1.866 -19.204,4.885 -4.915,3.016 -7.956,7.184 -7.956,11.789 0,4.604 3.041,8.772 7.956,11.788 4.914,3.02 11.704,-4.271 19.204,-4.271 7.499,0 14.292,7.291 19.206,4.271 4.914,-3.016 7.955,-7.185 7.955,-11.788 0,-4.606 -3.041,-8.773 -7.955,-11.789 z M 24.996,24.318 c -2.698,0 -4.885,-0.922 -4.885,-2.061 0,-1.14 2.187,-2.063 4.885,-2.063 2.697,0 4.885,0.924 4.885,2.063 0,1.139 -2.188,2.061 -4.885,2.061 z m 21.501,0.191 c -2.686,0 -4.861,-0.856 -4.861,-1.912 0,-1.054 2.176,-1.911 4.861,-1.911 2.685,0 4.863,0.857 4.863,1.911 0,1.056 -2.178,1.912 -4.863,1.912 z" />
|
||||
</g><g
|
||||
transform="translate(-91.018462,1.0687099)"
|
||||
id="Layer_2">
|
||||
<linearGradient
|
||||
y2="32.715599"
|
||||
x2="32.937"
|
||||
y1="-8.8144999"
|
||||
x1="30.564501"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="SVGID_3_">
|
||||
<stop
|
||||
id="stop17"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0.73"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop19"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient5812)"
|
||||
id="path21"
|
||||
d="m 54.1,15.361 c -0.924,1.078 -2.782,1.265 -3.857,1.06 C 38,14.083 22.75,12.75 16.027,23.031 14.858,24.819 11.992,25.39 10.293,23.887 8.631,22.417 13.105,15.804 17.646,13.033 22.194,10.252 28.474,8.53 35.41,8.53 c 6.936,0 13.215,1.722 17.756,4.502 0.731,0.442 1.627,1.52 0.934,2.329 z" />
|
||||
</g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
133
man/dnsmasq.8
133
man/dnsmasq.8
@@ -23,7 +23,7 @@ options. It includes a secure, read-only,
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
|
||||
.PP
|
||||
Dnsmasq
|
||||
supports IPv6 for DNS, but not DHCP.
|
||||
supports IPv6 for DNS and TFTP, but not DHCP.
|
||||
.SH OPTIONS
|
||||
Note that in general missing parameters are allowed and switch off
|
||||
functions, for instance "--pid-file" disables writing a PID file. On
|
||||
@@ -51,7 +51,7 @@ apply to domain names in cnames, PTR records, TXT records etc.
|
||||
.B \-T, --local-ttl=<time>
|
||||
When replying with information from /etc/hosts or the DHCP leases
|
||||
file dnsmasq by default sets the time-to-live field to zero, meaning
|
||||
that the requestor should not itself cache the information. This is
|
||||
that the requester should not itself cache the information. This is
|
||||
the correct thing to do in almost all situations. This option allows a
|
||||
time-to-live (in seconds) to be given for these replies. This will
|
||||
reduce the load on the server at the expense of clients using stale
|
||||
@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests.
|
||||
.B \-r, --resolv-file=<file>
|
||||
Read the IP addresses of the upstream nameservers from <file>, instead of
|
||||
/etc/resolv.conf. For the format of this file see
|
||||
.BR resolv.conf (5)
|
||||
the only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
||||
.BR resolv.conf (5).
|
||||
The only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
||||
be told to poll more than one resolv.conf file, the first file name specified
|
||||
overrides the default, subsequent ones add to the list. This is only
|
||||
allowed when polling; the file with the currently latest modification
|
||||
@@ -276,7 +276,7 @@ server strictly in the order they appear in /etc/resolv.conf
|
||||
By default, when dnsmasq has more than one upstream server available,
|
||||
it will send queries to just one server. Setting this flag forces
|
||||
dnsmasq to send all queries to all available servers. The reply from
|
||||
the server which answers first will be returned to the original requestor.
|
||||
the server which answers first will be returned to the original requester.
|
||||
.TP
|
||||
.B --stop-dns-rebind
|
||||
Reject (and log) addresses from upstream nameservers which are in the
|
||||
@@ -303,7 +303,7 @@ This is useful when new nameservers may have different
|
||||
data than that held in cache.
|
||||
.TP
|
||||
.B \-D, --domain-needed
|
||||
Tells dnsmasq to never forward queries for plain names, without dots
|
||||
Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
@@ -350,6 +350,9 @@ is a synonym for
|
||||
.B server
|
||||
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
|
||||
@@ -415,7 +418,9 @@ all that match are returned.
|
||||
.TP
|
||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||
so any number may be included, split by commas.
|
||||
so any number may be included, delimited by commas; use quotes to put
|
||||
commas into a string. Note that the maximum length of a single string
|
||||
is 255 characters, longer strings are split into 255 character chunks.
|
||||
.TP
|
||||
.B --ptr-record=<name>[,<target>]
|
||||
Return a PTR DNS record.
|
||||
@@ -442,6 +447,15 @@ the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping.
|
||||
.TP
|
||||
.B --add-mac
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
forwarded upstream. This may be used to DNS filtering by the upstream
|
||||
server. The MAC address can only be added if the requestor is on the same
|
||||
subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
|
||||
is not yet standardised, so this should be considered
|
||||
experimental. Also note that exposing MAC addresses in this way may
|
||||
have security and privacy implications.
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
|
||||
.TP
|
||||
@@ -456,6 +470,30 @@ Set the maximum number of concurrent DNS queries. The default value is
|
||||
where this needs to be increased is when using web-server log file
|
||||
resolvers, which can generate large numbers of concurrent queries.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
A resolver on a client machine can do DNSSEC validation in two ways: it
|
||||
can perform the cryptograhic operations on the reply it receives, or
|
||||
it can rely on the upstream recursive nameserver to do the validation
|
||||
and set a bit in the reply if it succeeds. Dnsmasq is not a DNSSEC
|
||||
validator, so it cannot perform the validation role of the recursive nameserver,
|
||||
but it can pass through the validation results from its own upstream
|
||||
nameservers. This option enables this behaviour. You should only do
|
||||
this if you trust all the configured upstream nameservers
|
||||
.I and the network between you and them.
|
||||
If you use the first DNSSEC mode, validating resolvers in clients,
|
||||
this option is not required. Dnsmasq always returns all the data
|
||||
needed for a client to do validation itself.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Read the Linux connection track mark associated with incoming DNS
|
||||
queries and set the same mark value on upstream traffic used to answer
|
||||
those queries. This allows traffic generated by dnsmasq to be
|
||||
associated with the queries which cause it, useful for bandwidth
|
||||
accounting and firewalling. Dnsmasq must have conntrack support
|
||||
compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
@@ -469,8 +507,11 @@ minimum lease time is two minutes. This
|
||||
option may be repeated, with different addresses, to enable DHCP
|
||||
service to more than one network. For directly connected networks (ie,
|
||||
networks on which the machine running dnsmasq has an interface) the
|
||||
netmask is optional. It is, however, required for networks which
|
||||
receive DHCP service via a relay agent. The broadcast address is
|
||||
netmask is optional: dnsmasq will determine it from the interface
|
||||
configuration. For networks which receive DHCP service via a relay
|
||||
agent, dnsmasq cannot determine the netmask itself, so it should be
|
||||
specified, otherwise dnsmasq will have to guess, based on the class (A, B or
|
||||
C) of the network address. The broadcast address is
|
||||
always optional. It is always
|
||||
allowed to have more than one dhcp-range in a single subnet.
|
||||
|
||||
@@ -504,7 +545,7 @@ Specify per host parameters for the DHCP server. This allows a machine
|
||||
with a particular hardware address to be always allocated the same
|
||||
hostname, IP address and lease time. A hostname specified like this
|
||||
overrides any supplied by the DHCP client on the machine. It is also
|
||||
allowable to ommit the hardware address and include the hostname, in
|
||||
allowable to omit the hardware address and include the hostname, in
|
||||
which case the IP address and lease times will apply to any machine
|
||||
claiming that name. For example
|
||||
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
||||
@@ -588,15 +629,17 @@ time and there is no way for dnsmasq to enforce this. It is, for instance,
|
||||
useful to allocate a stable IP address to a laptop which
|
||||
has both wired and wireless interfaces.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<file>
|
||||
Read DHCP host information from the specified file. The file contains
|
||||
.B --dhcp-hostsfile=<path>
|
||||
Read DHCP host information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The file contains
|
||||
information about one host per line. The format of a line is the same
|
||||
as text to the right of '=' in --dhcp-host. The advantage of storing DHCP host information
|
||||
in this file is that it can be changed without re-starting dnsmasq:
|
||||
the file will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<file>
|
||||
Read DHCP option information from the specified file. The advantage of
|
||||
.B --dhcp-optsfile=<path>
|
||||
Read DHCP option information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The advantage of
|
||||
using this option is the same as for --dhcp-hostsfile: the
|
||||
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
|
||||
it is possible to encode the information in a
|
||||
@@ -818,7 +861,7 @@ to supply no tags, in which case this is unconditional. Most DHCP clients which
|
||||
need broadcast replies set a flag in their requests so that this
|
||||
happens automatically, some old BOOTP clients do not.
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>]]
|
||||
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
|
||||
Set BOOTP options to be returned by the DHCP server. Server name and
|
||||
address are optional: if not provided, the name is left empty, and the
|
||||
address set to the address of the machine running dnsmasq. If dnsmasq
|
||||
@@ -827,6 +870,23 @@ is providing a TFTP service (see
|
||||
) then only the filename is required here to enable network booting.
|
||||
If the optional tag(s) are given,
|
||||
they must match for this configuration to be sent.
|
||||
Instead of an IP address, the TFTP server address can be given as a domain
|
||||
name which is looked up in /etc/hosts. This name can be associated in
|
||||
/etc/hosts with multiple IP addresses, which are used round-robin.
|
||||
This facility can be used to load balance the tftp load among a set of servers.
|
||||
.TP
|
||||
.B --dhcp-sequential-ip
|
||||
Dnsmasq is designed to choose IP addresses for DHCP clients using a
|
||||
hash of the client's MAC address. This normally allows a client's
|
||||
address to remain stable long-term, even if the client sometimes allows its DHCP
|
||||
lease to expire. In this default mode IP addresses are distributed
|
||||
pseudo-randomly over the entire available address range. There are
|
||||
sometimes circumstances (typically server deployment) where it is more
|
||||
convenient to have IP
|
||||
addresses allocated sequentially, starting from the lowest available
|
||||
address, and setting this flag enables this mode. Note that in the
|
||||
sequential mode, clients which allow a lease to expire are much more
|
||||
likely to move IP address; for this reason it should not be generally used.
|
||||
.TP
|
||||
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
|
||||
Most uses of PXE boot-ROMS simply allow the PXE
|
||||
@@ -946,7 +1006,8 @@ all of the following variables added.
|
||||
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
||||
|
||||
DNSMASQ_DOMAIN if the fully-qualified domain name of the host is
|
||||
known, this is set to the domain part.
|
||||
known, this is set to the domain part. (Note that the hostname passed
|
||||
to the script as an argument is never fully-qualified.)
|
||||
|
||||
If the client provides vendor-class, hostname or user-class,
|
||||
these are provided in DNSMASQ_VENDOR_CLASS
|
||||
@@ -1020,7 +1081,7 @@ as if they had arrived at <interface>. This option is necessary when
|
||||
using "old style" bridging on BSD platforms, since
|
||||
packets arrive at tap interfaces which don't have an IP address.
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>]
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
Specifies DNS domains for the DHCP server. Domains may be be given
|
||||
unconditionally (without the IP range) or for limited IP ranges. This has two effects;
|
||||
firstly it causes the DHCP server to return the domain to any hosts
|
||||
@@ -1039,11 +1100,22 @@ and have a machine whose DHCP hostname is "laptop". The IP address for that mach
|
||||
.B dnsmasq
|
||||
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
|
||||
given as "#" then the domain is read from the first "search" directive
|
||||
in /etc/resolv.conf (or equivalent). The address range can be of the form
|
||||
in /etc/resolv.conf (or equivalent).
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask> or just a single
|
||||
<ip address>. See
|
||||
.B --dhcp-fqdn
|
||||
which can change the behaviour of dnsmasq with domains.
|
||||
|
||||
If the address range is given as ip-address/network-size, then a
|
||||
additional flag "local" may be supplied which has the effect of adding
|
||||
--local declarations for forward and reverse DNS queries. Eg.
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
is identical to
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
The network size must be 8, 16 or 24 for this to be legal.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
In the default mode, dnsmasq inserts the unqualified names of
|
||||
@@ -1062,6 +1134,14 @@ without an address specified when
|
||||
.B --dhcp-fqdn
|
||||
is set.
|
||||
.TP
|
||||
.B --dhcp-client-update
|
||||
Normally, when giving a DHCP lease, dnsmasq sets flags in the FQDN
|
||||
option to tell the client not to attempt a DDNS update with its name
|
||||
and IP address. This is because the name-IP pair is automatically
|
||||
added into dnsmasq's DNS view. This flag suppresses that behaviour,
|
||||
this is useful, for instance, to allow Windows clients to update
|
||||
Active Directory servers. See RFC 4702 for details.
|
||||
.TP
|
||||
.B --enable-tftp[=<interface>]
|
||||
Enable the TFTP server function. This is deliberately limited to that
|
||||
needed to net-boot a client. Only reading is allowed; the tsize and
|
||||
@@ -1123,7 +1203,8 @@ of concurrent TFTP connections is limited by the size of the port range.
|
||||
.TP
|
||||
.B \-C, --conf-file=<file>
|
||||
Specify a different configuration file. The conf-file option is also allowed in
|
||||
configuration files, to include multiple configuration files.
|
||||
configuration files, to include multiple configuration files. A
|
||||
filename of "-" causes dnsmasq to read configuration from stdin.
|
||||
.TP
|
||||
.B \-7, --conf-dir=<directory>[,<file-extension>......]
|
||||
Read all the files in the given directory as configuration
|
||||
@@ -1284,6 +1365,17 @@ so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
tag purple is not in the set of valid tags. (If using this in a
|
||||
command line rather than a configuration file, be sure to escape !,
|
||||
which is a shell metacharacter)
|
||||
|
||||
When selecting dhcp-options, a tag from dhcp-range is second class
|
||||
relative to other tags, to make it easy to override options for
|
||||
individual hosts, so
|
||||
.B dhcp-range=set:interface1,......
|
||||
.B dhcp-host=set:myhost,.....
|
||||
.B dhcp-option=tag:interface1,option:nis-domain,"domain1"
|
||||
.B dhcp-option=tag:myhost,option:nis-domain,"domain2"
|
||||
will set the NIS-domain to domain1 for hosts in the range, but
|
||||
override that to domain2 for a particular host.
|
||||
|
||||
.PP
|
||||
Note that for
|
||||
.B dhcp-range
|
||||
@@ -1445,6 +1537,9 @@ assume that it is the system default.
|
||||
.IR /usr/local/etc/dnsmasq.conf
|
||||
|
||||
.IR /etc/resolv.conf
|
||||
.IR /var/run/dnsmasq/resolv.conf
|
||||
.IR /etc/ppp/resolv.conf
|
||||
.IR /etc/dhcpc/resolv.conf
|
||||
|
||||
.IR /etc/hosts
|
||||
|
||||
|
||||
150
man/fr/dnsmasq.8
150
man/fr/dnsmasq.8
@@ -22,7 +22,7 @@ peut être configuré pour envoyer n'importe quel option DHCP.
|
||||
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
|
||||
.PP
|
||||
Dnsmasq supporte IPv6 pour le DNS mais pas pour le DHCP.
|
||||
Dnsmasq supporte IPv6 pour le DNS et TFTP mais pas pour le DHCP.
|
||||
.SH OPTIONS
|
||||
Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
|
||||
Dans ce cas, la fonction correspondante sera désactivée. Par exemple
|
||||
@@ -347,10 +347,10 @@ Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
|
||||
différentes de celles stockées dans le cache.
|
||||
.TP
|
||||
.B \-D, --domain-needed
|
||||
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes pour des noms
|
||||
simples, ne comprenant donc ni points ni nom de domaine. Si un nom n'est pas
|
||||
dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse de type
|
||||
"non trouvé" est renvoyée.
|
||||
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
|
||||
des noms simples, c'est à dire ne comprenant ni points ni nom de domaine. Si un
|
||||
nom n'est pas dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse
|
||||
de type "non trouvé" est renvoyée.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
|
||||
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
|
||||
@@ -402,6 +402,10 @@ est synonyme de
|
||||
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
|
||||
usage particulier.
|
||||
|
||||
Les adresses IPv6 peuvent inclure un identifiant de zone sous la forme
|
||||
%interface tel que par exemple
|
||||
fe80::202:a412:4512:7bbf%eth0.
|
||||
|
||||
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
|
||||
la source que Dnsmasq doit utiliser pour les réponses à ce
|
||||
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
|
||||
@@ -491,7 +495,10 @@ retournés dans la réponse.
|
||||
.B \-Y, --txt-record=<nom>[[,<texte>],<texte>]
|
||||
Définit un enregistrement DNS de type TXT. La valeur de l'enregistrement TXT est
|
||||
un ensemble de chaînes de caractères, donc un nombre variable de chaînes de
|
||||
caractères peuvent être spécifiées, séparées par des virgules.
|
||||
caractères peuvent être spécifiées, séparées par des virgules. Utilisez des
|
||||
guillemets pour mettre une virgule dans une chaîne de caractères. Notez que la
|
||||
longueur maximale pour une chaîne est de 255 caractères, les chaînes plus
|
||||
longues étant découpées en morceaux de 255 caractères de longs.
|
||||
.TP
|
||||
.B --ptr-record=<nom>[,<cible>]
|
||||
Définit un enregistrement DNS de type PTR.
|
||||
@@ -519,6 +526,16 @@ Plus d'un nom peut être associé à une interface donnée en répétant cette o
|
||||
plusieurs fois; dans ce cas, l'enregistrement inverse pointe vers le nom fourni
|
||||
dans la première instance de cette option.
|
||||
.TP
|
||||
.B --add-mac
|
||||
Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises aux serveurs
|
||||
amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
|
||||
amonts. L'adresse MAC peut uniquement être ajoutée si le requêteur est sur le
|
||||
même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme
|
||||
utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée,
|
||||
aussi cette fonctionalité doit être considérée comme expérimentale. Notez
|
||||
également qu'exposer les adresses MAC de la sorte peut avoir des implications
|
||||
en termes de sécurité et de vie privée.
|
||||
.TP
|
||||
.B \-c, --cache-size=<taille>
|
||||
Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
|
||||
Définir une valeur de zéro désactive le cache.
|
||||
@@ -537,6 +554,31 @@ lorsqu'un serveur web a la résolution de nom activée pour l'enregistrement de
|
||||
son journal des requêtes, ce qui peut générer un nombre important de requêtes
|
||||
simultanées.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Un resolveur sur une machine cliente peut effectuer la validation DNSSEC de
|
||||
deux façons : il peut effectuer lui-même les opérations de chiffrements sur
|
||||
la réponse reçue, ou il peut laisser le serveur récursif amont faire la
|
||||
validation et positionner un drapeau dans la réponse au cas où celle-ci est
|
||||
correcte. Dnsmasq n'est pas un validateur DNSSEC, aussi il ne peut effectuer
|
||||
la validation comme un serveur de nom récursif, cependant il peut retransmettre
|
||||
les résultats de validation de ses serveurs amonts. Cette option permet
|
||||
l'activation de cette fonctionalité. Vous ne devriez utiliser cela que si vous
|
||||
faites confiance aux serveurs amonts
|
||||
.I ainsi que le réseau entre vous et eux.
|
||||
Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
|
||||
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
||||
données nécessaires par un client pour effectuer la validation lui-même.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
|
||||
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
|
||||
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
|
||||
avec le support conntrack, le noyau doit également inclure conntrack et être
|
||||
configuré pour cela. Cette option ne peut pas être combinée avec
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
||||
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||
@@ -551,9 +593,14 @@ minutes.
|
||||
Cette option peut être répétée, avec différentes adresses,
|
||||
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
|
||||
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
|
||||
Dnsmasq possède une interface), le masque de réseau est optionnel. Il est par
|
||||
contre requis pour les réseaux pour lesquels le service DHCP se fait via un
|
||||
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
|
||||
Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
|
||||
déterminera à partir de la configuration des interfaces.
|
||||
|
||||
Pour les réseaux pour lesquels le service DHCP se fait via un relais DHCP
|
||||
("relay agent"), Dnsmasq est incapable de déterminer le masque par lui-même,
|
||||
aussi il doit être spécifié, faute de quoi Dnsmasq essaiera de le deviner en
|
||||
fonction de la classe (A, B ou C) de l'adresse réseau. L'adresse de broadcast
|
||||
est toujours optionnelle.
|
||||
|
||||
Il est toujours possible d'avoir plus d'une plage DHCP pour un même
|
||||
sous-réseau.
|
||||
@@ -674,20 +721,24 @@ donné et dnsmasq n'a aucun moyen de s'assurer de cela. Cela est utile,
|
||||
par exemple, pour allouer une adresse IP stable à un laptop qui
|
||||
aurait à la fois une connexion filaire et sans-fil.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<fichier>
|
||||
Lis les informations d'hôtes DHCP dans le fichier spécifié. Le fichier contient
|
||||
des informations à raison d'un hôte par ligne. Le format d'une ligne est la même
|
||||
que le texte fourni à la droite sur caractère "=" dans l'option
|
||||
.B --dhcp-hostsfile=<chemin>
|
||||
Lis les informations d'hôtes DHCP dans le fichier spécifié. Si l'argument est
|
||||
un chemin vers un répertoire, lis tous les fichiers de ce répertoire. Le
|
||||
fichier contient des informations à raison d'un hôte par ligne. Le format
|
||||
d'une ligne est la même que le texte fourni à la droite sur caractère "=" dans
|
||||
l'option
|
||||
.B --dhcp-host.
|
||||
L'avantage de stocker les informations sur les hôtes DHCP dans ce fichier est
|
||||
que celles-ci peuvent être modifiées sans recharger Dnsmasq; le fichier sera
|
||||
relu lorsque Dnsmasq reçoit un signal SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<fichier>
|
||||
Lis les informations relatives aux options DHCP dans le fichier spécifié.
|
||||
L'intérêt d'utiliser cette option est le même que pour --dhcp-hostsfile : le
|
||||
fichier spécifié sera rechargé à la réception par dnsmasq d'un signal SIGHUP.
|
||||
Notez qu'il est possible d'encoder l'information via
|
||||
.B --dhcp-optsfile=<chemin>
|
||||
Lis les informations relatives aux options DHCP dans le fichier spécifié. Si
|
||||
l'argument est un chemin vers un répertoire, lis tous les fichiers de ce
|
||||
répertoire. L'intérêt d'utiliser cette option est le même que pour
|
||||
--dhcp-hostsfile : le fichier spécifié sera rechargé à la réception par
|
||||
dnsmasq d'un signal SIGHUP. Notez qu'il est possible d'encoder l'information
|
||||
via
|
||||
.B --dhcp-boot
|
||||
en utilisant les noms optionnels bootfile-name, server-ip-address et
|
||||
tftp-server. Ceci permet d'inclure ces options dans un fichier "dhcp-optsfile".DNSMASQ_SUPPLIED_HOSTNAME
|
||||
@@ -937,7 +988,7 @@ option s'applique inconditionnellement. La plupart des clients DHCP nécessitant
|
||||
d'un broadcast activent une option dans leur requête, ce qui fait que cela
|
||||
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>]]
|
||||
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
|
||||
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
|
||||
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
|
||||
est laissé vide et l'adresse fournie est celle de la machine sur laquelle
|
||||
@@ -947,6 +998,25 @@ s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
|
||||
le réseau.
|
||||
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
||||
ceux du client pour que cet élement de configuration lui soit envoyé.
|
||||
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
|
||||
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
|
||||
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
|
||||
celles-ci seront utilisées tour à tour (algorithme round-robin).
|
||||
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
|
||||
.TP
|
||||
.B --dhcp-sequential-ip
|
||||
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
|
||||
un hachage de l'adresse MAC du client. Cela permet en général à l'adresse
|
||||
IP du client de rester stable au fil du temps, même lorsque le client laisse
|
||||
expirer son bail DHCP de temps en temps. Dans ce mode de fonctionnement par
|
||||
défaut, les adresses IP sont distribuées de façon pseudo-aléatoire dans la
|
||||
totalité de la plage d'adresses utilisable. Il existe des circonstances (par
|
||||
exemples pour du déploiement de serveur) où il est plus pratique d'allouer les
|
||||
adresses IP de manière séquentielle, en commençant par la plus petite adresse
|
||||
disponible, et c'est ce mode de fonctionnement qui est permis par cette option.
|
||||
Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
|
||||
leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
|
||||
cette option ne devrait pas être utilisée dans un cas général.
|
||||
.TP
|
||||
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
|
||||
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
|
||||
@@ -1074,7 +1144,8 @@ auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous :
|
||||
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
||||
|
||||
DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la
|
||||
part relative au domaine y est stockée.
|
||||
part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme
|
||||
argument au script n'est jamais pleinement qualifié).
|
||||
|
||||
Si le client fournit une information de classe de vendeur, un nom d'hôte, ou
|
||||
des classes d'utilisateur, celles-ci sont fournies dans les
|
||||
@@ -1151,7 +1222,7 @@ nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
|
||||
BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
|
||||
pas d'adresse IP.
|
||||
.TP
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>]
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
|
||||
Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
|
||||
inconditionnelle (sans spécifier de gamme d'adresses IP) ou pour des gammes
|
||||
d'adresses IP limitées. Cela a deux effets; tout d'abord, le
|
||||
@@ -1173,11 +1244,23 @@ et avoir une machine dont le nom DHCP serait "laptop". L'adresse IP de cette
|
||||
machine sera disponible à la fois pour "laptop" et "laptop.thekelleys.org.uk".
|
||||
Si la valeur fournie pour <domaine> est "#", alors le nom de domaine est
|
||||
positionné à la première valeur de la directive "search" du fichier
|
||||
/etc/resolv.conf (ou équivalent). La gamme d'adresses peut être de la forme
|
||||
/etc/resolv.conf (ou équivalent).
|
||||
|
||||
La gamme d'adresses peut être de la forme
|
||||
<adresse ip>,<adresse ip> ou <adresse ip>/<masque de réseau> voire une simple
|
||||
<adresse ip>. Voir
|
||||
.B --dhcp-fqdn
|
||||
qui peut changer le comportement de dnsmasq relatif aux domaines.
|
||||
|
||||
Si la gamme d'adresse est fournie sous la forme
|
||||
<adresse ip>/<taille de réseau>, alors le drapeau "local" peut-être rajouté
|
||||
qui a pour effect d'ajouter --local-declarations aux requêtes DNS directes et
|
||||
inverses. C-à-d
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
est indentique à
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
La taille de réseau doit-être de 8, 16 ou 24 pour être valide.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients
|
||||
@@ -1284,7 +1367,9 @@ est limitée par la taille de la plage de ports ainsi définie.
|
||||
.B \-C, --conf-file=<fichier>
|
||||
Spécifie un fichier de configuration différent. L'option "conf-file" est
|
||||
également autorisée dans des fichiers de configuration, ce qui permet
|
||||
l'inclusion de multiples fichiers de configuration.
|
||||
l'inclusion de multiples fichiers de configuration. L'utilisation de "-" comme
|
||||
nom de fichier permet la lecture par dnsmasq de sa configuration sur l'entrée standard
|
||||
stdin.
|
||||
.TP
|
||||
.B \-7, --conf-dir=<répertoire>[,<extension de fichier>...]
|
||||
Lis tous les fichiers du répertoire spécifié et les traite comme des fichiers de
|
||||
@@ -1370,7 +1455,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
|
||||
.B create
|
||||
et
|
||||
.B delaycompress.
|
||||
|
||||
|
||||
.PP
|
||||
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
|
||||
@@ -1462,6 +1546,21 @@ labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une
|
||||
ligne de commande au lieu d'un fichier de configuration, ne pas oublier
|
||||
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
|
||||
shell).
|
||||
|
||||
+When selecting dhcp-options, a tag from dhcp-range is second class
|
||||
+relative to other tags, to make it easy to override options for
|
||||
+individual hosts, so
|
||||
|
||||
Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
|
||||
passe après les autres étiquettes, ce qui permet de facilement remplacer des
|
||||
option génériques pour des hôtes spécifiques, ainsi :
|
||||
.B dhcp-range=set:interface1,......
|
||||
.B dhcp-host=set:monhote,.....
|
||||
.B dhcp-option=tag:interface1,option:nis-domain,"domaine1"
|
||||
.B dhcp-option=tag:monhote,option:nis-domain,"domaine2"
|
||||
va positionner l'option NIS-domain à domaine1 pour les hôtes dans la plage
|
||||
d'adresse, sauf pour monhote pour lequel cette valeur sera domaine2.
|
||||
|
||||
.PP
|
||||
Veuillez noter que pour
|
||||
.B dhcp-range
|
||||
@@ -1621,6 +1720,9 @@ et assume de ce fait qu'il s'agit de la valeur par défaut du système.
|
||||
.IR /etc/dnsmasq.conf
|
||||
|
||||
.IR /usr/local/etc/dnsmasq.conf
|
||||
.IR /var/run/dnsmasq/resolv.conf
|
||||
.IR /etc/ppp/resolv.conf
|
||||
.IR /etc/dhcpc/resolv.conf
|
||||
|
||||
.IR /etc/resolv.conf
|
||||
|
||||
|
||||
1072
po/pt_BR.po
1072
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
|
||||
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
|
||||
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
|
||||
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
|
||||
cause to to write cache usage statisticss to the log, typically
|
||||
cause to write cache usage statisticss to the log, typically
|
||||
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
|
||||
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
|
||||
it is handling and causes SIGUSR1 to trigger a complete dump of the
|
||||
|
||||
2
src/NOTES
Normal file
2
src/NOTES
Normal file
@@ -0,0 +1,2 @@
|
||||
Worry about IPv6 leases and DUID in script-storage.
|
||||
|
||||
137
src/bpf.c
137
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -28,7 +28,71 @@ static struct iovec ifreq = {
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#ifndef SA_SIZE
|
||||
#define SA_SIZE(sa) \
|
||||
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
||||
sizeof(long) : \
|
||||
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||
#endif
|
||||
|
||||
int arp_enumerate(void *parm, int (*callback)())
|
||||
{
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
char *next;
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr_inarp *sin2;
|
||||
struct sockaddr_dl *sdl;
|
||||
int rc;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET;
|
||||
mib[4] = NET_RT_FLAGS;
|
||||
#ifdef RTF_LLINFO
|
||||
mib[5] = RTF_LLINFO;
|
||||
#else
|
||||
mib[5] = 0;
|
||||
#endif
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!expand_buf(&ifconf, needed))
|
||||
return 0;
|
||||
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 ||
|
||||
errno != ENOMEM)
|
||||
break;
|
||||
needed += needed / 8;
|
||||
}
|
||||
if (rc == -1)
|
||||
return 0;
|
||||
|
||||
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
sin2 = (struct sockaddr_inarp *)(rtm + 1);
|
||||
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
|
||||
if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
@@ -37,6 +101,13 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
int lastlen = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
return arp_enumerate(parm, callback);
|
||||
#else
|
||||
return 0; /* need code for Solaris and MacOS*/
|
||||
#endif
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
@@ -83,39 +154,43 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
ifr = (struct ifreq *)ifreq.iov_base;
|
||||
memcpy(ifr, ptr, len);
|
||||
|
||||
if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
|
||||
if (ifr->ifr_addr.sa_family == family)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*ipv4_callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
/* We have no way to determine the prefix, so we assume it's 64 for now....... */
|
||||
if (!((*callback)(addr, 64,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name), 0,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
if (!((*ipv6_callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
270
src/cache.c
270
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -25,7 +25,6 @@ static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 0;
|
||||
static char *addrbuff = NULL;
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -75,9 +74,6 @@ void cache_init(void)
|
||||
struct crec *crecp;
|
||||
int i;
|
||||
|
||||
if (daemon->options & OPT_LOG)
|
||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
bignames_left = daemon->cachesize/10;
|
||||
|
||||
if (daemon->cachesize > 0)
|
||||
@@ -226,7 +222,7 @@ char *cache_get_name(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_BIGNAME)
|
||||
return crecp->name.bname->name;
|
||||
else if (crecp->flags & (F_DHCP | F_CONFIG))
|
||||
else if (crecp->flags & F_NAMEP)
|
||||
return crecp->name.namep;
|
||||
|
||||
return crecp->name.sname;
|
||||
@@ -366,9 +362,6 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
|
||||
/* CONFIG bit means something else when stored in cache entries */
|
||||
flags &= ~F_CONFIG;
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return NULL;
|
||||
@@ -503,7 +496,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
/* first search, look for relevant entries and push to top of list
|
||||
also free anything which has expired */
|
||||
struct crec *next, **up, **insert = NULL, **chainp = &ans;
|
||||
int ins_flags = 0;
|
||||
unsigned short ins_flags = 0;
|
||||
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
|
||||
{
|
||||
@@ -642,11 +635,12 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
}
|
||||
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||
unsigned short flags, int index, int addr_dup)
|
||||
unsigned short flags, int index, struct crec **rhash)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
|
||||
int i, nameexists = 0;
|
||||
struct cname *a;
|
||||
unsigned int j;
|
||||
|
||||
/* Remove duplicates in hosts files. */
|
||||
if (lookup && (lookup->flags & F_HOSTS))
|
||||
@@ -660,33 +654,41 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
}
|
||||
|
||||
/* Ensure there is only one address -> name mapping (first one trumps)
|
||||
We do this by steam here, first we see if the address is the same as
|
||||
the last one we saw, which eliminates most in the case of an ad-block
|
||||
file with thousands of entries for the same address.
|
||||
Then we search and bail at the first matching address that came from
|
||||
We do this by steam here, The entries are kept in hash chains, linked
|
||||
by ->next (which is unused at this point) held in hash buckets in
|
||||
the array rhash. Note that rhash and the values in ->next are only valid
|
||||
whilst reading hosts files: the buckets are then freed, and the
|
||||
->next pointer used for other things.
|
||||
|
||||
We search and bail at the first matching address that came from
|
||||
a HOSTS file. Since the first host entry gets reverse, we know
|
||||
then that it must exist without searching exhaustively for it. */
|
||||
then that it must exist without searching exhaustively for it.
|
||||
|
||||
This complexity avoids O(n^2) divergent CPU use whilst reading
|
||||
large (10000 entry) hosts files. */
|
||||
|
||||
if (addr_dup)
|
||||
flags &= ~F_REVERSE;
|
||||
else
|
||||
for (i=0; i<hash_size; i++)
|
||||
/* hash address */
|
||||
for (j = 0, i = 0; i < addrlen; i++)
|
||||
j += ((unsigned char *)addr)[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (lookup = rhash[j % RHASHSIZE]; lookup; lookup = lookup->next)
|
||||
if ((lookup->flags & F_HOSTS) &&
|
||||
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
|
||||
if ((lookup->flags & F_HOSTS) &&
|
||||
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
flags &= ~F_REVERSE;
|
||||
break;
|
||||
}
|
||||
if (lookup)
|
||||
break;
|
||||
flags &= ~F_REVERSE;
|
||||
break;
|
||||
}
|
||||
|
||||
cache->flags = flags;
|
||||
cache->uid = index;
|
||||
|
||||
/* maintain address has chain */
|
||||
cache->next = rhash[j % RHASHSIZE];
|
||||
rhash[j % RHASHSIZE] = cache;
|
||||
|
||||
memcpy(&cache->addr.addr, addr, addrlen);
|
||||
|
||||
cache_hash(cache);
|
||||
|
||||
/* don't need to do alias stuff for second and subsequent addresses. */
|
||||
@@ -695,7 +697,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
if (hostname_isequal(cache->name.sname, a->target) &&
|
||||
(lookup = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
|
||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
|
||||
lookup->name.namep = a->alias;
|
||||
lookup->addr.cname.cache = cache;
|
||||
lookup->addr.cname.uid = index;
|
||||
@@ -750,14 +752,14 @@ static int gettok(FILE *f, char *token)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hostsfile(char *filename, int index, int cache_size)
|
||||
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
int addr_count = 0, name_count = cache_size, lineno = 0;
|
||||
unsigned short flags = 0, saved_flags = 0;
|
||||
struct all_addr addr, saved_addr;
|
||||
int atnl, addrlen = 0, addr_dup;
|
||||
unsigned short flags = 0;
|
||||
struct all_addr addr;
|
||||
int atnl, addrlen = 0;
|
||||
|
||||
if (!f)
|
||||
{
|
||||
@@ -769,7 +771,6 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
||||
|
||||
while ((atnl = gettok(f, token)) != EOF)
|
||||
{
|
||||
addr_dup = 0;
|
||||
lineno++;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -801,14 +802,6 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
|
||||
addr_dup = 1;
|
||||
else
|
||||
{
|
||||
saved_flags = flags;
|
||||
saved_addr = addr;
|
||||
}
|
||||
|
||||
addr_count++;
|
||||
|
||||
/* rehash every 1000 names. */
|
||||
@@ -832,21 +825,20 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
||||
if ((canon = canonicalise(token, &nomem)))
|
||||
{
|
||||
/* If set, add a version of the name with a default domain appended */
|
||||
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
(cache = whine_malloc(sizeof(struct crec) +
|
||||
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
strcat(cache->name.sname, ".");
|
||||
strcat(cache->name.sname, domain_suffix);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
|
||||
addr_dup = 1;
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash);
|
||||
name_count++;
|
||||
}
|
||||
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
|
||||
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash);
|
||||
name_count++;
|
||||
}
|
||||
free(canon);
|
||||
@@ -870,6 +862,7 @@ void cache_reload(void)
|
||||
struct crec *cache, **up, *tmp;
|
||||
int i, total_size = daemon->cachesize;
|
||||
struct hostsfile *ah;
|
||||
struct crec **reverse_hash;
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
@@ -896,110 +889,28 @@ void cache_reload(void)
|
||||
up = &cache->hash_next;
|
||||
}
|
||||
|
||||
if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||
{
|
||||
if (daemon->cachesize > 0)
|
||||
my_syslog(LOG_INFO, _("cleared cache"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(daemon->options & OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
|
||||
|
||||
for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
{
|
||||
if (i <= ah->index)
|
||||
i = ah->index + 1;
|
||||
|
||||
if (ah->flags & AH_DIR)
|
||||
ah->flags |= AH_INACTIVE;
|
||||
else
|
||||
ah->flags &= ~AH_INACTIVE;
|
||||
}
|
||||
|
||||
if (!(reverse_hash = whine_malloc(sizeof(struct crec *) * RHASHSIZE)))
|
||||
return;
|
||||
|
||||
for (i = 0; i < RHASHSIZE; i++)
|
||||
reverse_hash[i] = NULL;
|
||||
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size, reverse_hash);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
|
||||
{
|
||||
DIR *dir_stream;
|
||||
struct dirent *ent;
|
||||
|
||||
/* don't read this as a file */
|
||||
ah->flags |= AH_INACTIVE;
|
||||
|
||||
if (!(dir_stream = opendir(ah->fname)))
|
||||
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
else
|
||||
{
|
||||
while ((ent = readdir(dir_stream)))
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
struct hostsfile *ah1;
|
||||
char *path;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (lenfile == 0 ||
|
||||
ent->d_name[lenfile - 1] == '~' ||
|
||||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
|
||||
ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
/* see if we have an existing record.
|
||||
dir is ah->fname
|
||||
file is ent->d_name
|
||||
path to match is ah1->fname */
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, reverse_hash);
|
||||
|
||||
for (ah1 = daemon->addn_hosts; ah1; ah1 = ah1->next)
|
||||
{
|
||||
if (lendir < strlen(ah1->fname) &&
|
||||
strstr(ah1->fname, ah->fname) == ah1->fname &&
|
||||
ah1->fname[lendir] == '/' &&
|
||||
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
|
||||
{
|
||||
ah1->flags &= ~AH_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* make new record */
|
||||
if (!ah1)
|
||||
{
|
||||
if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
|
||||
continue;
|
||||
|
||||
if (!(path = whine_malloc(lendir + lenfile + 2)))
|
||||
{
|
||||
free(ah1);
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(path, ah->fname);
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
ah1->fname = path;
|
||||
ah1->index = i++;
|
||||
ah1->flags = AH_DIR;
|
||||
ah1->next = daemon->addn_hosts;
|
||||
daemon->addn_hosts = ah1;
|
||||
}
|
||||
|
||||
/* inactivate record if not regular file */
|
||||
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
|
||||
ah1->flags |= AH_INACTIVE;
|
||||
|
||||
}
|
||||
closedir(dir_stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size);
|
||||
free(reverse_hash);
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
@@ -1015,6 +926,21 @@ char *get_domain(struct in_addr addr)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now)
|
||||
{
|
||||
struct crec *crecp = NULL;
|
||||
struct in_addr ret;
|
||||
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
|
||||
if (crecp->flags & F_HOSTS)
|
||||
return *(struct in_addr *)&crecp->addr;
|
||||
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
|
||||
|
||||
ret.s_addr = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cache_unhash_dhcp(void)
|
||||
{
|
||||
struct crec *cache, **up;
|
||||
@@ -1036,7 +962,7 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
struct in_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec = NULL, *aliasc;
|
||||
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
int in_hosts = 0;
|
||||
struct cname *a;
|
||||
|
||||
@@ -1049,13 +975,13 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
in_hosts = 1;
|
||||
|
||||
if (crec->flags & F_CNAME)
|
||||
my_syslog(LOG_WARNING,
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
||||
host_name, inet_ntoa(*host_address));
|
||||
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
{
|
||||
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||
my_syslog(LOG_WARNING,
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s"),
|
||||
host_name, inet_ntoa(*host_address),
|
||||
@@ -1109,7 +1035,7 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
|
||||
if (aliasc)
|
||||
{
|
||||
aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
|
||||
aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
|
||||
if (ttd == 0)
|
||||
aliasc->flags |= F_IMMORTAL;
|
||||
else
|
||||
@@ -1135,34 +1061,34 @@ void dump_cache(time_t now)
|
||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||
daemon->queries_forwarded, daemon->local_answer);
|
||||
|
||||
if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
|
||||
return;
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)))
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
int port;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, addrbuff);
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
|
||||
if ((daemon->options & (OPT_DEBUG | OPT_LOG)))
|
||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||
{
|
||||
struct crec *cache ;
|
||||
int i;
|
||||
my_syslog(LOG_DEBUG, "Host Address Flags Expires");
|
||||
my_syslog(LOG_INFO, "Host Address Flags Expires");
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||
@@ -1180,11 +1106,11 @@ void dump_cache(time_t now)
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
a = addrbuff;
|
||||
a = daemon->addrbuff;
|
||||
if (cache->flags & F_IPV4)
|
||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
|
||||
else if (cache->flags & F_IPV6)
|
||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
|
||||
}
|
||||
#else
|
||||
else
|
||||
@@ -1208,7 +1134,7 @@ void dump_cache(time_t now)
|
||||
/* ctime includes trailing \n - eat it */
|
||||
*(p-1) = 0;
|
||||
#endif
|
||||
my_syslog(LOG_DEBUG, daemon->namebuff);
|
||||
my_syslog(LOG_INFO, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1237,28 +1163,28 @@ void querystr(char *str, unsigned short type)
|
||||
sprintf(str,"query[%s]", typestr[i].name);
|
||||
}
|
||||
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg)
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
{
|
||||
char *source, *dest = addrbuff;
|
||||
char *source, *dest = daemon->addrbuff;
|
||||
char *verb = "is";
|
||||
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
if (addr)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, addrbuff, ADDRSTRLEN);
|
||||
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#else
|
||||
strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flags & F_REVERSE)
|
||||
{
|
||||
dest = name;
|
||||
name = addrbuff;
|
||||
name = daemon->addrbuff;
|
||||
}
|
||||
|
||||
if (flags & F_NEG)
|
||||
@@ -1283,13 +1209,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
|
||||
}
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
/* nasty abuse of NXDOMAIN and CNAME flags */
|
||||
if (flags & F_NXDOMAIN)
|
||||
dest = arg;
|
||||
else
|
||||
dest = "<CNAME>";
|
||||
}
|
||||
dest = "<CNAME>";
|
||||
else if (flags & F_RRNAME)
|
||||
dest = arg;
|
||||
|
||||
if (flags & F_CONFIG)
|
||||
source = "config";
|
||||
@@ -1315,6 +1237,6 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
|
||||
if (strlen(name) == 0)
|
||||
name = ".";
|
||||
|
||||
my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
}
|
||||
|
||||
|
||||
310
src/config.h
310
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,15 +14,14 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VERSION "2.54"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define RHASHSIZE 1024 /* hash buckets for address lookup during hostfile read */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 10 seconds */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#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 */
|
||||
@@ -34,80 +33,19 @@
|
||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#ifdef __uClinux__
|
||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||
#else
|
||||
# define RESOLVFILE "/etc/resolv.conf"
|
||||
#endif
|
||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||
|
||||
#ifndef LEASEFILE
|
||||
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||
# elif defined(__sun__) || defined (__sun)
|
||||
# define LEASEFILE "/var/cache/dnsmasq.leases"
|
||||
# else
|
||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFFILE
|
||||
# if defined(__FreeBSD__)
|
||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||
# else
|
||||
# define CONFFILE "/etc/dnsmasq.conf"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_ALTPORT 1067
|
||||
#define DHCP_CLIENT_ALTPORT 1068
|
||||
#define PXE_PORT 4011
|
||||
#define TFTP_PORT 69
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
||||
|
||||
/* DBUS interface specifics */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* DBUS interface specifics */
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
|
||||
/* A small collection of RR-types which are missing on some platforms */
|
||||
|
||||
#ifndef T_SIG
|
||||
# define T_SIG 24
|
||||
#endif
|
||||
|
||||
#ifndef T_SRV
|
||||
# define T_SRV 33
|
||||
#endif
|
||||
|
||||
#ifndef T_OPT
|
||||
# define T_OPT 41
|
||||
#endif
|
||||
|
||||
#ifndef T_TKEY
|
||||
# define T_TKEY 249
|
||||
#endif
|
||||
|
||||
#ifndef T_TSIG
|
||||
# define T_TSIG 250
|
||||
#endif
|
||||
|
||||
|
||||
/* Follows system specific switches. If you run on a
|
||||
new system, you may want to edit these.
|
||||
May replace this with Autoconf one day.
|
||||
|
||||
HAVE_LINUX_NETWORK
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOLARIS_NETWORK
|
||||
define exactly one of these to alter interaction with kernel networking.
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
|
||||
HAVE_BROKEN_RTC
|
||||
define this on embedded systems which don't have an RTC
|
||||
@@ -127,69 +65,118 @@ HAVE_TFTP
|
||||
define this to get dnsmasq's built-in TFTP server.
|
||||
|
||||
HAVE_DHCP
|
||||
define this to get dnsmasq's DHCP server.
|
||||
define this to get dnsmasq's DHCPv4 server.
|
||||
|
||||
HAVE_DHCP6
|
||||
define this to get dnsmasq's DHCPv6 server. (implies HAVE_DHCP).
|
||||
|
||||
HAVE_SCRIPT
|
||||
define this to get the ability to call scripts on lease-change
|
||||
define this to get the ability to call scripts on lease-change.
|
||||
|
||||
HAVE_GETOPT_LONG
|
||||
define this if you have GNU libc or GNU getopt.
|
||||
|
||||
HAVE_ARC4RANDOM
|
||||
define this if you have arc4random() to get better security from DNS spoofs
|
||||
by using really random ids (OpenBSD)
|
||||
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
define this if struct sockaddr has sa_len field (*BSD)
|
||||
HAVE_LUASCRIPT
|
||||
define this to get the ability to call Lua script on lease-change. (implies HAVE_SCRIPT)
|
||||
|
||||
HAVE_DBUS
|
||||
Define this if you want to link against libdbus, and have dnsmasq
|
||||
define some methods to allow (re)configuration of the upstream DNS
|
||||
define this if you want to link against libdbus, and have dnsmasq
|
||||
support some methods to allow (re)configuration of the upstream DNS
|
||||
servers via DBus.
|
||||
|
||||
NOTES:
|
||||
For Linux you should define
|
||||
HAVE_LINUX_NETWORK
|
||||
HAVE_GETOPT_LONG
|
||||
you should NOT define
|
||||
HAVE_ARC4RANDOM
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
HAVE_IDN
|
||||
define this if you want international domain name support.
|
||||
NOTE: for backwards compatibility, IDN support is automatically
|
||||
included when internationalisation support is built, using the
|
||||
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
||||
|
||||
For *BSD systems you should define
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
and you MAY define
|
||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
||||
HAVE_CONNTRACK
|
||||
define this to include code which propogates conntrack marks from
|
||||
incoming DNS queries to the corresponding upstream queries. This adds
|
||||
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||
still run happily on a kernel without conntrack support.
|
||||
|
||||
NO_IPV6
|
||||
NO_TFTP
|
||||
NO_DHCP
|
||||
NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
these are avilable to explictly 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.
|
||||
|
||||
LEASEFILE
|
||||
CONFFILE
|
||||
RESOLVFILE
|
||||
the default locations of these files are determined below, but may be overridden
|
||||
in a build command line using COPTS.
|
||||
|
||||
*/
|
||||
|
||||
/* platform independent options- uncomment to enable */
|
||||
|
||||
/* The default set of options to build. Built with these options, dnsmasq
|
||||
has no library dependencies other than libc */
|
||||
|
||||
#define HAVE_DHCP
|
||||
/* #define HAVE_DHCP6 */
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
/* #define HAVE_LUASCRIPT */
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
/* #define HAVE_DBUS */
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
|
||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
||||
#ifdef NO_TFTP
|
||||
#undef HAVE_TFTP
|
||||
|
||||
|
||||
/* Default locations for important system files. */
|
||||
|
||||
#ifndef LEASEFILE
|
||||
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||
# elif defined(__sun__) || defined (__sun)
|
||||
# define LEASEFILE "/var/cache/dnsmasq.leases"
|
||||
# elif defined(__ANDROID__)
|
||||
# define LEASEFILE "/data/misc/dhcp/dnsmasq.leases"
|
||||
# else
|
||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Allow DHCP to be disabled with COPTS=-DNO_DHCP */
|
||||
#ifdef NO_DHCP
|
||||
#undef HAVE_DHCP
|
||||
#ifndef CONFFILE
|
||||
# if defined(__FreeBSD__)
|
||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||
# else
|
||||
# define CONFFILE "/etc/dnsmasq.conf"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Allow scripts to be disabled with COPTS=-DNO_SCRIPT */
|
||||
#ifdef NO_SCRIPT
|
||||
#undef HAVE_SCRIPT
|
||||
#ifndef RESOLVFILE
|
||||
# if defined(__uClinux__)
|
||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||
# else
|
||||
# define RESOLVFILE "/etc/resolv.conf"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* platform dependent options. */
|
||||
/* platform dependent options: these are determined automatically below
|
||||
|
||||
HAVE_LINUX_NETWORK
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOLARIS_NETWORK
|
||||
define exactly one of these to alter interaction with kernel networking.
|
||||
|
||||
HAVE_GETOPT_LONG
|
||||
defined when GNU-sty;e getopt_long available.
|
||||
|
||||
HAVE_ARC4RANDOM
|
||||
defined if arc4random() available to get better security from DNS spoofs
|
||||
by using really random ids (OpenBSD)
|
||||
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
defined if struct sockaddr has sa_len field (*BSD)
|
||||
*/
|
||||
|
||||
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
||||
#if defined(__uClinux__)
|
||||
@@ -265,18 +252,12 @@ NOTES:
|
||||
#endif
|
||||
|
||||
/* Decide if we're going to support IPv6 */
|
||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
||||
/* We assume that systems which don't have IPv6
|
||||
headers don't have ntop and pton either */
|
||||
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||
# define HAVE_IPV6
|
||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||
# if defined(SOL_IPV6)
|
||||
# define IPV6_LEVEL SOL_IPV6
|
||||
# else
|
||||
# define IPV6_LEVEL IPPROTO_IPV6
|
||||
# endif
|
||||
#elif defined(INET_ADDRSTRLEN)
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||
@@ -285,8 +266,103 @@ NOTES:
|
||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
#endif
|
||||
|
||||
/* Can't do scripts without fork */
|
||||
#ifdef NOFORK
|
||||
# undef HAVE_SCRIPT
|
||||
|
||||
/* rules to implement compile-time option dependencies and
|
||||
the NO_XXX flags */
|
||||
|
||||
#ifdef NO_IPV6
|
||||
#undef HAVE_IPV6
|
||||
#endif
|
||||
|
||||
#ifdef NO_TFTP
|
||||
#undef HAVE_TFTP
|
||||
#endif
|
||||
|
||||
#ifdef NO_DHCP
|
||||
#undef HAVE_DHCP
|
||||
#undef HAVE_DHCP6
|
||||
#endif
|
||||
|
||||
#if defined(NO_DHCP6) || !defined(HAVE_IPV6)
|
||||
#undef HAVE_DHCP6
|
||||
#endif
|
||||
|
||||
/* DHCP6 needs DHCP too */
|
||||
#ifdef HAVE_DHCP6
|
||||
#define HAVE_DHCP
|
||||
#endif
|
||||
|
||||
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
|
||||
#undef HAVE_SCRIPT
|
||||
#undef HAVE_LUASCRIPT
|
||||
#endif
|
||||
|
||||
/* Must HAVE_SCRIPT to HAVE_LUASCRIPT */
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
#define HAVE_SCRIPT
|
||||
#endif
|
||||
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
|
||||
#ifdef DNSMASQ_COMPILE_OPTS
|
||||
|
||||
static char *compile_opts =
|
||||
#ifndef HAVE_IPV6
|
||||
"no-"
|
||||
#endif
|
||||
"IPv6 "
|
||||
#ifndef HAVE_GETOPT_LONG
|
||||
"no-"
|
||||
#endif
|
||||
"GNU-getopt "
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
"no-RTC "
|
||||
#endif
|
||||
#ifdef NO_FORK
|
||||
"no-MMU "
|
||||
#endif
|
||||
#ifndef HAVE_DBUS
|
||||
"no-"
|
||||
#endif
|
||||
"DBus "
|
||||
#ifndef LOCALEDIR
|
||||
"no-"
|
||||
#endif
|
||||
"i18n "
|
||||
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||
"no-"
|
||||
#endif
|
||||
"IDN "
|
||||
#ifndef HAVE_DHCP
|
||||
"no-"
|
||||
#endif
|
||||
"DHCP "
|
||||
#if defined(HAVE_DHCP)
|
||||
# if !defined (HAVE_DHCP6)
|
||||
"no-"
|
||||
# endif
|
||||
"DHCPv6 "
|
||||
# if !defined(HAVE_SCRIPT)
|
||||
"no-scripts "
|
||||
# else
|
||||
# if !defined(HAVE_LUASCRIPT)
|
||||
"no-"
|
||||
# endif
|
||||
"Lua "
|
||||
# endif
|
||||
#endif
|
||||
#ifndef HAVE_TFTP
|
||||
"no-"
|
||||
#endif
|
||||
"TFTP "
|
||||
#ifndef HAVE_CONNTRACK
|
||||
"no-"
|
||||
#endif
|
||||
"conntrack";
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
90
src/conntrack.c
Normal file
90
src/conntrack.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
|
||||
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
||||
|
||||
static int gotit = 0; /* yuck */
|
||||
|
||||
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
|
||||
|
||||
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp)
|
||||
{
|
||||
struct nf_conntrack *ct;
|
||||
struct nfct_handle *h;
|
||||
|
||||
gotit = 0;
|
||||
|
||||
if ((ct = nfct_new()))
|
||||
{
|
||||
nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
|
||||
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (peer_addr->sa.sa_family == AF_INET6)
|
||||
{
|
||||
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
|
||||
nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
|
||||
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
|
||||
nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
|
||||
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
|
||||
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
|
||||
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
|
||||
}
|
||||
|
||||
|
||||
if ((h = nfct_open(CONNTRACK, 0)))
|
||||
{
|
||||
nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);
|
||||
if (nfct_query(h, NFCT_Q_GET, ct) == -1)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
|
||||
warned = 1;
|
||||
}
|
||||
}
|
||||
nfct_close(h);
|
||||
}
|
||||
nfct_destroy(ct);
|
||||
}
|
||||
|
||||
return gotit;
|
||||
}
|
||||
|
||||
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
|
||||
{
|
||||
unsigned int *ret = (unsigned int *)data;
|
||||
*ret = nfct_get_attr_u32(ct, ATTR_MARK);
|
||||
(void)type; /* eliminate warning */
|
||||
gotit = 1;
|
||||
|
||||
return NFCT_CB_CONTINUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
358
src/dhcp.c
358
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,13 +19,19 @@
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
struct iface_param {
|
||||
struct in_addr relay, primary;
|
||||
struct dhcp_context *current;
|
||||
int ind;
|
||||
};
|
||||
|
||||
struct match_param {
|
||||
int ind, matched;
|
||||
struct in_addr netmask, broadcast, addr;
|
||||
};
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
|
||||
static int make_fd(int port)
|
||||
{
|
||||
@@ -35,16 +41,22 @@ static int make_fd(int port)
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
int mtu = IP_PMTUDISC_DONT;
|
||||
#endif
|
||||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||
int tos = IPTOS_CLASS_CS6;
|
||||
#endif
|
||||
|
||||
if (fd == -1)
|
||||
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
if (!fix_fd(fd) ||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||
#endif
|
||||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#else
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#endif
|
||||
@@ -54,7 +66,7 @@ static int make_fd(int port)
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
@@ -96,7 +108,7 @@ void dhcp_init(void)
|
||||
we drop root. Also, set buffer size small, to avoid wasting
|
||||
kernel buffers */
|
||||
|
||||
if (daemon->options & OPT_NO_PING)
|
||||
if (option_bool(OPT_NO_PING))
|
||||
daemon->dhcp_icmp_fd = -1;
|
||||
else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
|
||||
@@ -111,7 +123,41 @@ void dhcp_init(void)
|
||||
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
||||
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
||||
}
|
||||
|
||||
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
{
|
||||
ssize_t sz;
|
||||
|
||||
while (1)
|
||||
{
|
||||
msg->msg_flags = 0;
|
||||
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
||||
|
||||
if (sz == -1)
|
||||
return -1;
|
||||
|
||||
if (!(msg->msg_flags & MSG_TRUNC))
|
||||
break;
|
||||
|
||||
/* Very new Linux kernels return the actual size needed,
|
||||
older ones always return truncated size */
|
||||
if ((size_t)sz == daemon->dhcp_packet.iov_len)
|
||||
{
|
||||
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
expand_buf(&daemon->dhcp_packet, sz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
|
||||
}
|
||||
|
||||
void dhcp_packet(time_t now, int pxe_fd)
|
||||
{
|
||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||
@@ -125,7 +171,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
struct iovec iov;
|
||||
ssize_t sz;
|
||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||
struct in_addr iface_addr, *addrp = NULL;
|
||||
struct in_addr iface_addr;
|
||||
struct iface_param parm;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
struct arpreq arp_req;
|
||||
@@ -141,56 +187,23 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||
#endif
|
||||
} control_u;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_name = &dest;
|
||||
msg.msg_namelen = sizeof(dest);
|
||||
msg.msg_iov = &daemon->dhcp_packet;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
msg.msg_flags = 0;
|
||||
while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
||||
|
||||
if (sz == -1)
|
||||
return;
|
||||
|
||||
if (!(msg.msg_flags & MSG_TRUNC))
|
||||
break;
|
||||
|
||||
/* Very new Linux kernels return the actual size needed,
|
||||
older ones always return truncated size */
|
||||
if ((size_t)sz == daemon->dhcp_packet.iov_len)
|
||||
{
|
||||
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
expand_buf(&daemon->dhcp_packet, sz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* expand_buf may have moved buffer */
|
||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = &dest;
|
||||
msg.msg_namelen = sizeof(dest);
|
||||
|
||||
while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
|
||||
|
||||
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
|
||||
if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
|
||||
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
||||
return;
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK)
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK)
|
||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
@@ -237,26 +250,50 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
#endif
|
||||
|
||||
/* One form of bridging on BSD has the property that packets
|
||||
can be recieved on bridge interfaces which do not have an IP address.
|
||||
We allow these to be treated as aliases of another interface which does have
|
||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
|
||||
{
|
||||
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alias)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef MSG_BCAST
|
||||
/* OpenBSD tells us when a packet was broadcast */
|
||||
if (!(msg.msg_flags & MSG_BCAST))
|
||||
unicast_dest = 1;
|
||||
#endif
|
||||
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
else
|
||||
{
|
||||
addrp = &iface_addr;
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||
@@ -264,42 +301,40 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
parm.relay = mess->giaddr;
|
||||
parm.primary = iface_addr;
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
/* interface may have been changed by alias in iface_check, make sure it gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
|
||||
{
|
||||
struct in_addr netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
||||
{
|
||||
struct in_addr broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
complete_context(iface_addr, iface_index, netmask, broadcast, &parm);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
|
||||
if (!iface_enumerate(&parm, complete_context, NULL))
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
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);
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns();
|
||||
|
||||
@@ -319,7 +354,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
dest.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
|
||||
if (pxe_fd)
|
||||
{
|
||||
if (mess->ciaddr.s_addr != 0)
|
||||
@@ -357,7 +392,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
pkt->ipi_ifindex = iface_index;
|
||||
pkt->ipi_spec_dst.s_addr = 0;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = SOL_IP;
|
||||
cmptr->cmsg_level = IPPROTO_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
@@ -414,6 +449,30 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
||||
}
|
||||
|
||||
/* check against secondary interface addresses */
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct match_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if ( tmp->addr.sa.sa_family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == local.s_addr)
|
||||
{
|
||||
param->matched = 1;
|
||||
param->addr = local;
|
||||
param->netmask = netmask;
|
||||
param->broadcast = broadcast;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
||||
of each interface (and any relay address) and does the following things:
|
||||
|
||||
@@ -448,38 +507,27 @@ static int complete_context(struct in_addr local, int if_index,
|
||||
context->netmask = netmask;
|
||||
}
|
||||
|
||||
if (context->netmask.s_addr)
|
||||
if (context->netmask.s_addr != 0 &&
|
||||
is_same_net(local, context->start, context->netmask) &&
|
||||
is_same_net(local, context->end, context->netmask))
|
||||
{
|
||||
if (is_same_net(local, context->start, context->netmask) &&
|
||||
is_same_net(local, context->end, context->netmask))
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (if_index == param->ind && context->current == context)
|
||||
{
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (if_index == param->ind && context->current == context)
|
||||
{
|
||||
context->router = local;
|
||||
context->local = local;
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
}
|
||||
|
||||
if (!(context->flags & CONTEXT_BRDCAST))
|
||||
{
|
||||
if (is_same_net(broadcast, context->start, context->netmask))
|
||||
context->broadcast = broadcast;
|
||||
else
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
}
|
||||
}
|
||||
else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
|
||||
context->router = local;
|
||||
context->local = local;
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
}
|
||||
|
||||
if (!(context->flags & CONTEXT_BRDCAST))
|
||||
{
|
||||
context->router = param->relay;
|
||||
context->local = param->primary;
|
||||
/* fill in missing broadcast addresses for relayed ranges */
|
||||
if (!(context->flags & CONTEXT_BRDCAST))
|
||||
if (is_same_net(broadcast, context->start, context->netmask))
|
||||
context->broadcast = broadcast;
|
||||
else
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -505,7 +553,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
start = ntohl(tmp->start.s_addr);
|
||||
end = ntohl(tmp->end.s_addr);
|
||||
|
||||
if (!(tmp->flags & CONTEXT_STATIC) &&
|
||||
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
@@ -540,7 +588,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
if (!tmp)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net(taddr, tmp->start, tmp->netmask))
|
||||
is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||
!(tmp->flags & CONTEXT_PROXY))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -626,16 +675,22 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & CONTEXT_STATIC)
|
||||
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(c->start.s_addr) +
|
||||
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||
if (option_bool(OPT_CONSEC_ADDR))
|
||||
/* seed is largest extant lease addr in this context */
|
||||
start = lease_find_max_addr(c);
|
||||
else
|
||||
/* pick a seed based on hwaddr */
|
||||
start.s_addr = htonl(ntohl(c->start.s_addr) +
|
||||
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||
|
||||
/* iterate until we find a free address. */
|
||||
addr = start;
|
||||
|
||||
do {
|
||||
/* eliminate addresses in use by the server. */
|
||||
@@ -660,9 +715,6 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
*addrp = addr;
|
||||
|
||||
if (daemon->options & OPT_NO_PING)
|
||||
return 1;
|
||||
|
||||
/* 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
|
||||
@@ -672,33 +724,51 @@ int address_allocate(struct dhcp_context *context,
|
||||
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 if (++count == max || r->addr.s_addr == addr.s_addr)
|
||||
return 1;
|
||||
|
||||
if (icmp_ping(addr))
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
c->addr_epoch++;
|
||||
else
|
||||
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)
|
||||
{
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
|
||||
{
|
||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||
/* 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)
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = 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;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* record that this address is OK for 30s
|
||||
without more ping checks */
|
||||
if (victim)
|
||||
{
|
||||
victim->addr = addr;
|
||||
victim->time = now;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,6 +779,7 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -917,6 +988,7 @@ void dhcp_read_ethers(void)
|
||||
config->flags = CONFIG_FROM_ETHERS;
|
||||
config->hwaddr = NULL;
|
||||
config->domain = NULL;
|
||||
config->netid = NULL;
|
||||
config->next = daemon->dhcp_conf;
|
||||
daemon->dhcp_conf = config;
|
||||
}
|
||||
|
||||
220
src/dhcp6.c
Normal file
220
src/dhcp6.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
int ind;
|
||||
};
|
||||
|
||||
static int join_multicast(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, void *vparam);
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, void *vparam);
|
||||
|
||||
void dhcp6_init(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in6 saddr;
|
||||
int class = IPTOS_CLASS_CS6;
|
||||
|
||||
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
!set_ipv6pktinfo(fd))
|
||||
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin6_len = sizeof(addr.in6);
|
||||
#endif
|
||||
saddr.sin6_family = AF_INET6;
|
||||
saddr.sin6_addr = in6addr_any;
|
||||
saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
|
||||
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* join multicast groups on each interface we're interested in */
|
||||
if (!iface_enumerate(AF_INET6, &fd, join_multicast))
|
||||
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
|
||||
|
||||
daemon->dhcp6fd = fd;
|
||||
|
||||
}
|
||||
|
||||
static int join_multicast(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, void *vparam)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct ipv6_mreq mreq;
|
||||
struct in6_addr maddr;
|
||||
int fd = *((int *)vparam);
|
||||
struct dhcp_context *context;
|
||||
struct iname *tmp;
|
||||
|
||||
(void)prefix;
|
||||
(void)scope; /* warnings */
|
||||
|
||||
if (!indextoname(fd, if_index, ifrn_name))
|
||||
return 0;
|
||||
|
||||
/* Are we doing DHCP on this interface? */
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
|
||||
return 1;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
|
||||
return 1;
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
return 1;
|
||||
|
||||
mreq.ipv6mr_interface = if_index;
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &maddr);
|
||||
|
||||
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &maddr);
|
||||
|
||||
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void dhcp6_packet(time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct iface_param parm;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
int if_index = 0;
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
} control_u;
|
||||
union mysockaddr from;
|
||||
struct all_addr dest;
|
||||
ssize_t sz;
|
||||
struct ifreq ifr;
|
||||
struct iname *tmp;
|
||||
|
||||
msg.msg_control = control_u.control6;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = &from;
|
||||
msg.msg_namelen = sizeof(from);
|
||||
msg.msg_iov = &daemon->dhcp_packet;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg) == -1) || sz <= 4)
|
||||
return;
|
||||
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in6_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
dest.addr.addr6 = p.p->ipi6_addr;
|
||||
}
|
||||
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
ls -l
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = if_index;
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
msg.msg_iov = &daemon->dhcp_packet;
|
||||
sz = dhcp6_reply(parm.current, sz);
|
||||
/* ifr.ifr_name, if_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
|
||||
lease_update_file(now);
|
||||
lease_update_dns();
|
||||
|
||||
if (sz != 0)
|
||||
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, sz, &from, &dest, if_index);
|
||||
}
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if ((context->flags & CONTEXT_IPV6) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (if_index == param->ind && context->current == context)
|
||||
{
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
55
src/dhcp6_protocol.h
Normal file
55
src/dhcp6_protocol.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DHCPV6_SERVER_PORT 547
|
||||
#define DHCPV6_CLIENT_PORT 546
|
||||
|
||||
#define ALL_SERVERS "FF05::1:3"
|
||||
#define ALL_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
|
||||
|
||||
#define DHCP6SOLICIT 1
|
||||
#define DHCP6ADVERTISE 2
|
||||
#define DHCP6REQUEST 3
|
||||
#define DHCP6CONFIRM 4
|
||||
#define DHCP6RENEW 5
|
||||
#define DHCP6REBIND 6
|
||||
#define DHCP6REPLY 7
|
||||
#define DHCP6RELEASE 8
|
||||
#define DHCP6DECLINE 9
|
||||
#define DHCP6RECONFIGURE 10
|
||||
#define DHCP6IREQ 11
|
||||
#define DHCP6RELAYFORW 12
|
||||
#define DHCP6RELAYREPL 13
|
||||
|
||||
#define OPTION6_CLIENT_ID 1
|
||||
#define OPTION6_SERVER_ID 2
|
||||
#define OPTION6_IA_NA 3
|
||||
#define OPTION6_IA_TA 4
|
||||
#define OPTION6_IAADDR 5
|
||||
#define OPTION6_ORO 6
|
||||
#define OPTION6_PREFERENCE 7
|
||||
#define OPTION6_ELAPSED_TIME 8
|
||||
#define OPTION6_RELAY_MSG 9
|
||||
#define OPTION6_AUTH 11
|
||||
#define OPTION6_UNICAST 12
|
||||
#define OPTION6_STATUS_CODE 13
|
||||
#define OPTION6_RAPID_COMMIT 14
|
||||
#define OPTION6_USER_CLASS 15
|
||||
#define OPTION6_VENDOR_CLASS 16
|
||||
#define OPTION6_VENDOR_OPTS 17
|
||||
#define OPTION6_INTERFACE_ID 18
|
||||
#define OPTION6_RECONFIGURE_MSG 19
|
||||
#define OPTION6_RECONF_ACCEPT 20
|
||||
96
src/dhcp_protocol.h
Normal file
96
src/dhcp_protocol.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_ALTPORT 1067
|
||||
#define DHCP_CLIENT_ALTPORT 1068
|
||||
#define PXE_PORT 4011
|
||||
|
||||
#define BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
|
||||
/* The Linux in-kernel DHCP client silently ignores any packet
|
||||
smaller than this. Sigh........... */
|
||||
#define MIN_PACKETSZ 300
|
||||
|
||||
#define OPTION_PAD 0
|
||||
#define OPTION_NETMASK 1
|
||||
#define OPTION_ROUTER 3
|
||||
#define OPTION_DNSSERVER 6
|
||||
#define OPTION_HOSTNAME 12
|
||||
#define OPTION_DOMAINNAME 15
|
||||
#define OPTION_BROADCAST 28
|
||||
#define OPTION_VENDOR_CLASS_OPT 43
|
||||
#define OPTION_REQUESTED_IP 50
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_SERVER_IDENTIFIER 54
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_MESSAGE 56
|
||||
#define OPTION_MAXMESSAGE 57
|
||||
#define OPTION_T1 58
|
||||
#define OPTION_T2 59
|
||||
#define OPTION_VENDOR_ID 60
|
||||
#define OPTION_CLIENT_ID 61
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_ARCH 93
|
||||
#define OPTION_PXE_UUID 97
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
#define OPTION_DOMAIN_SEARCH 119
|
||||
#define OPTION_SIP_SERVER 120
|
||||
#define OPTION_VENDOR_IDENT 124
|
||||
#define OPTION_VENDOR_IDENT_OPT 125
|
||||
#define OPTION_END 255
|
||||
|
||||
#define SUBOPT_CIRCUIT_ID 1
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||
#define SUBOPT_PXE_DISCOVERY 6
|
||||
#define SUBOPT_PXE_SERVERS 8
|
||||
#define SUBOPT_PXE_MENU 9
|
||||
#define SUBOPT_PXE_MENU_PROMPT 10
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
#define DHCPREQUEST 3
|
||||
#define DHCPDECLINE 4
|
||||
#define DHCPACK 5
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
|
||||
struct dhcp_packet {
|
||||
u8 op, htype, hlen, hops;
|
||||
u32 xid;
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
u8 options[312];
|
||||
};
|
||||
114
src/dns_protocol.h
Normal file
114
src/dns_protocol.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define NAMESERVER_PORT 53
|
||||
#define TFTP_PORT 69
|
||||
|
||||
#define IN6ADDRSZ 16
|
||||
#define INADDRSZ 4
|
||||
|
||||
#define PACKETSZ 512 /* maximum packet size */
|
||||
#define MAXDNAME 1025 /* maximum presentation domain name */
|
||||
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
||||
#define MAXLABEL 63 /* maximum length of domain label */
|
||||
|
||||
#define NOERROR 0 /* no error */
|
||||
#define FORMERR 1 /* format error */
|
||||
#define SERVFAIL 2 /* server failure */
|
||||
#define NXDOMAIN 3 /* non existent domain */
|
||||
#define NOTIMP 4 /* not implemented */
|
||||
#define REFUSED 5 /* query refused */
|
||||
|
||||
#define QUERY 0 /* opcode */
|
||||
|
||||
#define C_IN 1 /* the arpa internet */
|
||||
#define C_CHAOS 3 /* for chaos net (MIT) */
|
||||
#define C_ANY 255 /* wildcard match */
|
||||
|
||||
#define T_A 1
|
||||
#define T_NS 2
|
||||
#define T_CNAME 5
|
||||
#define T_SOA 6
|
||||
#define T_PTR 12
|
||||
#define T_MX 15
|
||||
#define T_TXT 16
|
||||
#define T_SIG 24
|
||||
#define T_AAAA 28
|
||||
#define T_SRV 33
|
||||
#define T_NAPTR 35
|
||||
#define T_OPT 41
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
u16 qdcount,ancount,nscount,arcount;
|
||||
};
|
||||
|
||||
#define HB3_QR 0x80
|
||||
#define HB3_OPCODE 0x78
|
||||
#define HB3_AA 0x04
|
||||
#define HB3_TC 0x02
|
||||
#define HB3_RD 0x01
|
||||
|
||||
#define HB4_RA 0x80
|
||||
#define HB4_AD 0x20
|
||||
#define HB4_CD 0x10
|
||||
#define HB4_RCODE 0x0f
|
||||
|
||||
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
|
||||
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
|
||||
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
|
||||
|
||||
#define GETSHORT(s, cp) { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(s) = ((u16)t_cp[0] << 8) \
|
||||
| ((u16)t_cp[1]) \
|
||||
; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define GETLONG(l, cp) { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(l) = ((u32)t_cp[0] << 24) \
|
||||
| ((u32)t_cp[1] << 16) \
|
||||
| ((u32)t_cp[2] << 8) \
|
||||
| ((u32)t_cp[3]) \
|
||||
; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
#define PUTSHORT(s, cp) { \
|
||||
u16 t_s = (u16)(s); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define PUTLONG(l, cp) { \
|
||||
u32 t_l = (u32)(l); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
281
src/dnsmasq.c
281
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,47 +14,13 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Declare static char *compiler_opts in config.h */
|
||||
#define DNSMASQ_COMPILE_OPTS
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
struct daemon *daemon;
|
||||
|
||||
static char *compile_opts =
|
||||
#ifndef HAVE_IPV6
|
||||
"no-"
|
||||
#endif
|
||||
"IPv6 "
|
||||
#ifndef HAVE_GETOPT_LONG
|
||||
"no-"
|
||||
#endif
|
||||
"GNU-getopt "
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
"no-RTC "
|
||||
#endif
|
||||
#ifdef NO_FORK
|
||||
"no-MMU "
|
||||
#endif
|
||||
#ifndef HAVE_DBUS
|
||||
"no-"
|
||||
#endif
|
||||
"DBus "
|
||||
#ifndef LOCALEDIR
|
||||
"no-"
|
||||
#endif
|
||||
"I18N "
|
||||
#ifndef HAVE_DHCP
|
||||
"no-"
|
||||
#endif
|
||||
"DHCP "
|
||||
#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
|
||||
"no-scripts "
|
||||
#endif
|
||||
#ifndef HAVE_TFTP
|
||||
"no-"
|
||||
#endif
|
||||
"TFTP";
|
||||
|
||||
|
||||
|
||||
static volatile pid_t pid = 0;
|
||||
static volatile int pipewrite;
|
||||
|
||||
@@ -62,7 +28,8 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
||||
static void check_dns_listeners(fd_set *set, time_t now);
|
||||
static void sig_handler(int sig);
|
||||
static void async_event(int pipe, time_t now);
|
||||
static void fatal_event(struct event_desc *ev);
|
||||
static void fatal_event(struct event_desc *ev, char *msg);
|
||||
static int read_event(int fd, struct event_desc *evp, char **msg);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
@@ -72,7 +39,7 @@ int main (int argc, char **argv)
|
||||
struct iname *if_tmp;
|
||||
int piperead, pipefd[2], err_pipe[2];
|
||||
struct passwd *ent_pw = NULL;
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
||||
#if defined(HAVE_SCRIPT)
|
||||
uid_t script_uid = 0;
|
||||
gid_t script_gid = 0;
|
||||
#endif
|
||||
@@ -115,6 +82,8 @@ int main (int argc, char **argv)
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
|
||||
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (!daemon->lease_file)
|
||||
{
|
||||
@@ -133,10 +102,10 @@ int main (int argc, char **argv)
|
||||
#elif !(defined(IP_RECVDSTADDR) && \
|
||||
defined(IP_RECVIF) && \
|
||||
defined(IP_SENDSRCADDR))
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
bind_fallback = 1;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
set_option_bool(OPT_NOWILD);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -145,11 +114,24 @@ int main (int argc, char **argv)
|
||||
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
|
||||
die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
|
||||
#else
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
if (daemon->max_logs != 0)
|
||||
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (daemon->max_logs != 0)
|
||||
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
rand_init();
|
||||
|
||||
now = dnsmasq_time();
|
||||
@@ -168,9 +150,9 @@ int main (int argc, char **argv)
|
||||
if (!enumerate_interfaces())
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
daemon->listeners = create_bound_listeners();
|
||||
create_bound_listeners(1);
|
||||
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
@@ -183,14 +165,13 @@ int main (int argc, char **argv)
|
||||
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else if ((daemon->port != 0 || daemon->tftp_interfaces || daemon->tftp_unlimited) &&
|
||||
!(daemon->listeners = create_wildcard_listeners()))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
else
|
||||
create_wildcard_listeners();
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
|
||||
if (daemon->options & OPT_DBUS)
|
||||
if (option_bool(OPT_DBUS))
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
char *err;
|
||||
@@ -206,9 +187,10 @@ int main (int argc, char **argv)
|
||||
if (daemon->port != 0)
|
||||
pre_allocate_sfds();
|
||||
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
||||
#if defined(HAVE_SCRIPT)
|
||||
/* Note getpwnam returns static storage */
|
||||
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
|
||||
if (daemon->dhcp && daemon->scriptuser &&
|
||||
(daemon->lease_change_command || daemon->luascript))
|
||||
{
|
||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||
{
|
||||
@@ -271,11 +253,11 @@ int main (int argc, char **argv)
|
||||
piperead = pipefd[0];
|
||||
pipewrite = pipefd[1];
|
||||
/* prime the pipe to load stuff first time. */
|
||||
send_event(pipewrite, EVENT_RELOAD, 0);
|
||||
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* The following code "daemonizes" the process.
|
||||
See Stevens section 12.4 */
|
||||
@@ -284,7 +266,7 @@ int main (int argc, char **argv)
|
||||
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
|
||||
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_NO_FORK))
|
||||
if (!option_bool(OPT_NO_FORK))
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
@@ -294,18 +276,19 @@ int main (int argc, char **argv)
|
||||
|
||||
if ((pid = fork()) == -1)
|
||||
/* fd == -1 since we've not forked, never returns. */
|
||||
send_event(-1, EVENT_FORK_ERR, errno);
|
||||
send_event(-1, EVENT_FORK_ERR, errno, NULL);
|
||||
|
||||
if (pid != 0)
|
||||
{
|
||||
struct event_desc ev;
|
||||
|
||||
char *msg;
|
||||
|
||||
/* close our copy of write-end */
|
||||
close(err_pipe[1]);
|
||||
|
||||
/* check for errors after the fork */
|
||||
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
|
||||
fatal_event(&ev);
|
||||
if (read_event(err_pipe[0], &ev, &msg))
|
||||
fatal_event(&ev, msg);
|
||||
|
||||
_exit(EC_GOOD);
|
||||
}
|
||||
@@ -317,7 +300,7 @@ int main (int argc, char **argv)
|
||||
setsid();
|
||||
|
||||
if ((pid = fork()) == -1)
|
||||
send_event(err_pipe[1], EVENT_FORK_ERR, errno);
|
||||
send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
|
||||
|
||||
if (pid != 0)
|
||||
_exit(0);
|
||||
@@ -337,7 +320,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
else if (getuid() == 0)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_PIDFILE, errno);
|
||||
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
@@ -345,7 +328,7 @@ int main (int argc, char **argv)
|
||||
|
||||
log_err = log_start(ent_pw, err_pipe[1]);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* open stdout etc to /dev/null */
|
||||
int nullfd = open("/dev/null", O_RDWR);
|
||||
@@ -357,12 +340,12 @@ int main (int argc, char **argv)
|
||||
|
||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||
daemon->helperfd = -1;
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
||||
if (daemon->dhcp && daemon->lease_change_command)
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (daemon->dhcp && (daemon->lease_change_command || daemon->luascript))
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
|
||||
if (!option_bool(OPT_DEBUG) && getuid() == 0)
|
||||
{
|
||||
int bad_capabilities = 0;
|
||||
gid_t dummy;
|
||||
@@ -372,20 +355,26 @@ int main (int argc, char **argv)
|
||||
(setgroups(0, &dummy) == -1 ||
|
||||
setgid(gp->gr_gid) == -1))
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
|
||||
send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (ent_pw && ent_pw->pw_uid != 0)
|
||||
{
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||
CAP_NET_RAW (for icmp) if we're doing dhcp */
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
||||
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
|
||||
if (is_dad_listeners())
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
||||
else
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||
|
||||
/* Tell kernel to not clear capabilities when dropping root */
|
||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
|
||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
||||
bad_capabilities = errno;
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
@@ -412,26 +401,30 @@ int main (int argc, char **argv)
|
||||
|
||||
if (bad_capabilities != 0)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
|
||||
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* finally drop root */
|
||||
if (setuid(ent_pw->pw_uid) == -1)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_USER_ERR, errno);
|
||||
send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
if (is_dad_listeners())
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
||||
else
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
data->inheritable = 0;
|
||||
|
||||
/* lose the setuid and setgid capbilities */
|
||||
if (capset(hdr, data) == -1)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
|
||||
send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
|
||||
_exit(0);
|
||||
}
|
||||
#endif
|
||||
@@ -440,8 +433,8 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (daemon->options & OPT_DEBUG)
|
||||
prctl(PR_SET_DUMPABLE, 1);
|
||||
if (option_bool(OPT_DEBUG))
|
||||
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
#endif
|
||||
|
||||
if (daemon->port == 0)
|
||||
@@ -454,7 +447,7 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
if (daemon->options & OPT_DBUS)
|
||||
if (option_bool(OPT_DBUS))
|
||||
{
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
|
||||
@@ -470,12 +463,12 @@ int main (int argc, char **argv)
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
|
||||
|
||||
if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
|
||||
if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
|
||||
{
|
||||
if (daemon->resolv_files && !daemon->resolv_files->is_default)
|
||||
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
|
||||
@@ -518,7 +511,7 @@ int main (int argc, char **argv)
|
||||
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
|
||||
daemon->tftp_prefix ? _("root is ") : _("enabled"),
|
||||
daemon->tftp_prefix ? daemon->tftp_prefix: "",
|
||||
daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
|
||||
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
||||
|
||||
/* This is a guess, it assumes that for small limits,
|
||||
disjoint files might be served, but for large limits,
|
||||
@@ -580,12 +573,19 @@ int main (int argc, char **argv)
|
||||
|
||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||
if (daemon->tftp_trans ||
|
||||
((daemon->options & OPT_DBUS) && !daemon->dbus))
|
||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||
{
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 250000;
|
||||
tp = &t;
|
||||
}
|
||||
/* Wake every second whilst waiting for DAD to complete */
|
||||
else if (is_dad_listeners())
|
||||
{
|
||||
t.tv_sec = 1;
|
||||
t.tv_usec = 0;
|
||||
tp = &t;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
||||
@@ -640,6 +640,20 @@ int main (int argc, char **argv)
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
|
||||
/* Check the interfaces to see if any have exited DAD state
|
||||
and if so, bind the address. */
|
||||
if (is_dad_listeners())
|
||||
{
|
||||
enumerate_interfaces();
|
||||
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast();
|
||||
#endif
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
/* Don't go silent for long periods if the clock goes backwards. */
|
||||
@@ -657,14 +671,9 @@ int main (int argc, char **argv)
|
||||
if (FD_ISSET(piperead, &rset))
|
||||
async_event(piperead, now);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* if we didn't create a DBus connection, retry now. */
|
||||
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
{
|
||||
char *err;
|
||||
if ((err = dbus_init()))
|
||||
@@ -734,28 +743,57 @@ static void sig_handler(int sig)
|
||||
else
|
||||
return;
|
||||
|
||||
send_event(pipewrite, event, 0);
|
||||
send_event(pipewrite, event, 0, NULL);
|
||||
errno = errsave;
|
||||
}
|
||||
}
|
||||
|
||||
void send_event(int fd, int event, int data)
|
||||
void send_event(int fd, int event, int data, char *msg)
|
||||
{
|
||||
struct event_desc ev;
|
||||
|
||||
struct iovec iov[2];
|
||||
|
||||
ev.event = event;
|
||||
ev.data = data;
|
||||
ev.msg_sz = msg ? strlen(msg) : 0;
|
||||
|
||||
iov[0].iov_base = &ev;
|
||||
iov[0].iov_len = sizeof(ev);
|
||||
iov[1].iov_base = msg;
|
||||
iov[1].iov_len = ev.msg_sz;
|
||||
|
||||
/* error pipe, debug mode. */
|
||||
if (fd == -1)
|
||||
fatal_event(&ev);
|
||||
fatal_event(&ev, msg);
|
||||
else
|
||||
/* pipe is non-blocking and struct event_desc is smaller than
|
||||
PIPE_BUF, so this either fails or writes everything */
|
||||
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
|
||||
while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
static void fatal_event(struct event_desc *ev)
|
||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||
to describe fatal errors. */
|
||||
static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
|
||||
return 0;
|
||||
|
||||
*msg = NULL;
|
||||
|
||||
if (evp->msg_sz != 0 &&
|
||||
(buf = malloc(evp->msg_sz + 1)) &&
|
||||
read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
|
||||
{
|
||||
buf[evp->msg_sz] = 0;
|
||||
*msg = buf;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void fatal_event(struct event_desc *ev, char *msg)
|
||||
{
|
||||
errno = ev->data;
|
||||
|
||||
@@ -774,19 +812,19 @@ static void fatal_event(struct event_desc *ev)
|
||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||
|
||||
case EVENT_USER_ERR:
|
||||
case EVENT_HUSER_ERR:
|
||||
die(_("failed to change user-id to %s: %s"),
|
||||
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
|
||||
EC_MISC);
|
||||
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
|
||||
|
||||
case EVENT_GROUP_ERR:
|
||||
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
|
||||
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
|
||||
|
||||
case EVENT_PIDFILE:
|
||||
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
|
||||
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
|
||||
|
||||
case EVENT_LOG_ERR:
|
||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
||||
die(_("cannot open log %s: %s"), msg, EC_FILE);
|
||||
|
||||
case EVENT_LUA_ERR:
|
||||
die(_("failed to load Lua script: %s"), msg, EC_MISC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,13 +833,17 @@ static void async_event(int pipe, time_t now)
|
||||
pid_t p;
|
||||
struct event_desc ev;
|
||||
int i;
|
||||
|
||||
if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
|
||||
char *msg;
|
||||
|
||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||
to describe fatal errors. */
|
||||
|
||||
if (read_event(pipe, &ev, &msg))
|
||||
switch (ev.event)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
clear_cache_and_reload(now);
|
||||
if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check_servers();
|
||||
@@ -841,11 +883,11 @@ static void async_event(int pipe, time_t now)
|
||||
break;
|
||||
|
||||
case EVENT_KILLED:
|
||||
my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
|
||||
my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
|
||||
break;
|
||||
|
||||
case EVENT_EXITED:
|
||||
my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
|
||||
my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
|
||||
break;
|
||||
|
||||
case EVENT_EXEC_ERR:
|
||||
@@ -854,9 +896,10 @@ static void async_event(int pipe, time_t now)
|
||||
break;
|
||||
|
||||
/* necessary for fatal errors in helper */
|
||||
case EVENT_HUSER_ERR:
|
||||
case EVENT_USER_ERR:
|
||||
case EVENT_DIE:
|
||||
fatal_event(&ev);
|
||||
case EVENT_LUA_ERR:
|
||||
fatal_event(&ev, msg);
|
||||
break;
|
||||
|
||||
case EVENT_REOPEN:
|
||||
@@ -873,7 +916,7 @@ static void async_event(int pipe, time_t now)
|
||||
if (daemon->tcp_pids[i] != 0)
|
||||
kill(daemon->tcp_pids[i], SIGALRM);
|
||||
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
||||
#if defined(HAVE_SCRIPT)
|
||||
/* handle pending lease transitions */
|
||||
if (daemon->helperfd != -1)
|
||||
{
|
||||
@@ -908,7 +951,7 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
Go through and find the one which changed _last_.
|
||||
Warn of any which can't be read. */
|
||||
|
||||
if (daemon->port == 0 || (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port == 0 || option_bool(OPT_NO_POLL))
|
||||
return;
|
||||
|
||||
for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
|
||||
@@ -954,7 +997,7 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
my_syslog(LOG_INFO, _("reading %s"), latest->name);
|
||||
warned = 0;
|
||||
check_servers();
|
||||
if ((daemon->options & OPT_RELOAD) && do_reload)
|
||||
if (option_bool(OPT_RELOAD) && do_reload)
|
||||
clear_cache_and_reload(now);
|
||||
}
|
||||
else
|
||||
@@ -977,7 +1020,7 @@ void clear_cache_and_reload(time_t now)
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
if (daemon->options & OPT_ETHERS)
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
@@ -1094,7 +1137,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface;
|
||||
else
|
||||
{
|
||||
@@ -1120,7 +1163,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
close(confd);
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
|
||||
else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
|
||||
{
|
||||
if (p != -1)
|
||||
{
|
||||
@@ -1140,14 +1183,11 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
unsigned char *buff;
|
||||
struct server *s;
|
||||
int flags;
|
||||
struct in_addr dst_addr_4;
|
||||
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
#ifndef NO_FORK
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
alarm(CHILD_LIFETIME);
|
||||
#endif
|
||||
|
||||
@@ -1161,10 +1201,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
if (listener->family == AF_INET)
|
||||
dst_addr_4 = iface->addr.in.sin_addr;
|
||||
|
||||
buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
|
||||
buff = tcp_request(confd, now, &iface->addr, iface->netmask);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1179,7 +1216,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
close(s->tcpfd);
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
flush_log();
|
||||
_exit(0);
|
||||
|
||||
272
src/dnsmasq.h
272
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2010 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2012 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
/* Get linux C library versions and define _GNU_SOURCE for kFreeBSD. */
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
# define _GNU_SOURCE
|
||||
# ifndef __ANDROID__
|
||||
# define _GNU_SOURCE
|
||||
# endif
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
@@ -37,20 +39,28 @@
|
||||
/* get these before config.h for IPv6 stuff... */
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <nameser.h>
|
||||
# include <arpa/nameser_compat.h>
|
||||
#else
|
||||
# include <arpa/nameser.h>
|
||||
/* Define before netinet/in.h to select API. OSX Lion onwards. */
|
||||
# define __APPLE_USE_RFC_3542
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* and this. */
|
||||
/* Also needed before config.h. */
|
||||
#include <getopt.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
#include "dns_protocol.h"
|
||||
#include "dhcp_protocol.h"
|
||||
#ifdef HAVE_DHCP6
|
||||
#include "dhcp6_protocol.h"
|
||||
#endif
|
||||
|
||||
#define gettext_noop(S) (S)
|
||||
#ifndef LOCALEDIR
|
||||
# define _(S) (S)
|
||||
@@ -89,7 +99,7 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdarg.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun) || defined (__ANDROID__)
|
||||
# include <netinet/if_ether.h>
|
||||
#else
|
||||
# include <net/ethernet.h>
|
||||
@@ -125,7 +135,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
|
||||
/* Async event queue */
|
||||
struct event_desc {
|
||||
int event, data;
|
||||
int event, data, msg_sz;
|
||||
};
|
||||
|
||||
#define EVENT_RELOAD 1
|
||||
@@ -146,6 +156,7 @@ struct event_desc {
|
||||
#define EVENT_DIE 16
|
||||
#define EVENT_LOG_ERR 17
|
||||
#define EVENT_FORK_ERR 18
|
||||
#define EVENT_LUA_ERR 19
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -163,38 +174,47 @@ struct event_desc {
|
||||
*/
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
|
||||
#define OPT_BOGUSPRIV (1u<<0)
|
||||
#define OPT_FILTER (1u<<1)
|
||||
#define OPT_LOG (1u<<2)
|
||||
#define OPT_SELFMX (1u<<3)
|
||||
#define OPT_NO_HOSTS (1u<<4)
|
||||
#define OPT_NO_POLL (1u<<5)
|
||||
#define OPT_DEBUG (1u<<6)
|
||||
#define OPT_ORDER (1u<<7)
|
||||
#define OPT_NO_RESOLV (1u<<8)
|
||||
#define OPT_EXPAND (1u<<9)
|
||||
#define OPT_LOCALMX (1u<<10)
|
||||
#define OPT_NO_NEG (1u<<11)
|
||||
#define OPT_NODOTS_LOCAL (1u<<12)
|
||||
#define OPT_NOWILD (1u<<13)
|
||||
#define OPT_ETHERS (1u<<14)
|
||||
#define OPT_RESOLV_DOMAIN (1u<<15)
|
||||
#define OPT_NO_FORK (1u<<16)
|
||||
#define OPT_AUTHORITATIVE (1u<<17)
|
||||
#define OPT_LOCALISE (1u<<18)
|
||||
#define OPT_DBUS (1u<<19)
|
||||
#define OPT_DHCP_FQDN (1u<<20)
|
||||
#define OPT_NO_PING (1u<<21)
|
||||
#define OPT_LEASE_RO (1u<<22)
|
||||
#define OPT_ALL_SERVERS (1u<<23)
|
||||
#define OPT_RELOAD (1u<<24)
|
||||
#define OPT_LOCAL_REBIND (1u<<25)
|
||||
#define OPT_TFTP_SECURE (1u<<26)
|
||||
#define OPT_TFTP_NOBLOCK (1u<<27)
|
||||
#define OPT_LOG_OPTS (1u<<28)
|
||||
#define OPT_TFTP_APREF (1u<<29)
|
||||
#define OPT_NO_OVERRIDE (1u<<30)
|
||||
#define OPT_NO_REBIND (1u<<31)
|
||||
/* Trust the compiler dead-code eliminator.... */
|
||||
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
||||
|
||||
#define OPT_BOGUSPRIV 0
|
||||
#define OPT_FILTER 1
|
||||
#define OPT_LOG 2
|
||||
#define OPT_SELFMX 3
|
||||
#define OPT_NO_HOSTS 4
|
||||
#define OPT_NO_POLL 5
|
||||
#define OPT_DEBUG 6
|
||||
#define OPT_ORDER 7
|
||||
#define OPT_NO_RESOLV 8
|
||||
#define OPT_EXPAND 9
|
||||
#define OPT_LOCALMX 10
|
||||
#define OPT_NO_NEG 11
|
||||
#define OPT_NODOTS_LOCAL 12
|
||||
#define OPT_NOWILD 13
|
||||
#define OPT_ETHERS 14
|
||||
#define OPT_RESOLV_DOMAIN 15
|
||||
#define OPT_NO_FORK 16
|
||||
#define OPT_AUTHORITATIVE 17
|
||||
#define OPT_LOCALISE 18
|
||||
#define OPT_DBUS 19
|
||||
#define OPT_DHCP_FQDN 20
|
||||
#define OPT_NO_PING 21
|
||||
#define OPT_LEASE_RO 22
|
||||
#define OPT_ALL_SERVERS 23
|
||||
#define OPT_RELOAD 24
|
||||
#define OPT_LOCAL_REBIND 25
|
||||
#define OPT_TFTP_SECURE 26
|
||||
#define OPT_TFTP_NOBLOCK 27
|
||||
#define OPT_LOG_OPTS 28
|
||||
#define OPT_TFTP_APREF 29
|
||||
#define OPT_NO_OVERRIDE 30
|
||||
#define OPT_NO_REBIND 31
|
||||
#define OPT_ADD_MAC 32
|
||||
#define OPT_DNSSEC 33
|
||||
#define OPT_CONSEC_ADDR 34
|
||||
#define OPT_CONNTRACK 35
|
||||
#define OPT_FQDN_UPDATE 36
|
||||
#define OPT_LAST 37
|
||||
|
||||
/* 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. */
|
||||
@@ -235,7 +255,8 @@ struct naptr {
|
||||
};
|
||||
|
||||
struct txt_record {
|
||||
char *name, *txt;
|
||||
char *name;
|
||||
unsigned char *txt;
|
||||
unsigned short class, len;
|
||||
struct txt_record *next;
|
||||
};
|
||||
@@ -280,22 +301,27 @@ struct crec {
|
||||
} name;
|
||||
};
|
||||
|
||||
#define F_IMMORTAL 1
|
||||
#define F_CONFIG 2
|
||||
#define F_REVERSE 4
|
||||
#define F_FORWARD 8
|
||||
#define F_DHCP 16
|
||||
#define F_NEG 32
|
||||
#define F_HOSTS 64
|
||||
#define F_IPV4 128
|
||||
#define F_IPV6 256
|
||||
#define F_BIGNAME 512
|
||||
#define F_UPSTREAM 1024
|
||||
#define F_SERVER 2048
|
||||
#define F_NXDOMAIN 4096
|
||||
#define F_QUERY 8192
|
||||
#define F_CNAME 16384
|
||||
#define F_NOERR 32768
|
||||
#define F_IMMORTAL (1u<<0)
|
||||
#define F_NAMEP (1u<<1)
|
||||
#define F_REVERSE (1u<<2)
|
||||
#define F_FORWARD (1u<<3)
|
||||
#define F_DHCP (1u<<4)
|
||||
#define F_NEG (1u<<5)
|
||||
#define F_HOSTS (1u<<6)
|
||||
#define F_IPV4 (1u<<7)
|
||||
#define F_IPV6 (1u<<8)
|
||||
#define F_BIGNAME (1u<<9)
|
||||
#define F_NXDOMAIN (1u<<10)
|
||||
#define F_CNAME (1u<<11)
|
||||
#define F_NOERR (1u<<12)
|
||||
#define F_CONFIG (1u<<13)
|
||||
/* below here are only valid as args to log_query: cache
|
||||
entries are limited to 16 bits */
|
||||
#define F_UPSTREAM (1u<<16)
|
||||
#define F_RRNAME (1u<<17)
|
||||
#define F_SERVER (1u<<18)
|
||||
#define F_QUERY (1u<<19)
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
@@ -347,7 +373,7 @@ struct server {
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
int tftp_ok, mtu;
|
||||
int tftp_ok, mtu, done, dad;
|
||||
char *name;
|
||||
struct irec *next;
|
||||
};
|
||||
@@ -374,7 +400,7 @@ struct resolvc {
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* adn-hosts parms from command-line */
|
||||
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
|
||||
#define AH_DIR 1
|
||||
#define AH_INACTIVE 2
|
||||
struct hostsfile {
|
||||
@@ -384,6 +410,9 @@ struct hostsfile {
|
||||
int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
struct all_addr dest;
|
||||
@@ -394,7 +423,7 @@ struct frec {
|
||||
#endif
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd, forwardall, norebind;
|
||||
int fd, forwardall, flags;
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
struct frec *next;
|
||||
@@ -406,8 +435,6 @@ struct frec {
|
||||
#define ACTION_OLD 3
|
||||
#define ACTION_ADD 4
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
|
||||
struct dhcp_lease {
|
||||
int clid_len; /* length of client identifier */
|
||||
unsigned char *clid; /* clientid */
|
||||
@@ -427,6 +454,9 @@ struct dhcp_lease {
|
||||
unsigned char *extradata;
|
||||
unsigned int extradata_len, extradata_size;
|
||||
int last_interface;
|
||||
#ifdef HAVE_DHCP6
|
||||
char is_ipv6;
|
||||
#endif
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
|
||||
@@ -501,9 +531,10 @@ struct dhcp_opt {
|
||||
#define DHOPT_HEX 512
|
||||
#define DHOPT_VENDOR_MATCH 1024
|
||||
#define DHOPT_RFC3925 2048
|
||||
#define DHOPT_TAGOK 4096
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
char *file, *sname, *tftp_sname;
|
||||
struct in_addr next_server;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_boot *next;
|
||||
@@ -555,6 +586,10 @@ struct dhcp_context {
|
||||
struct in_addr netmask, broadcast;
|
||||
struct in_addr local, router;
|
||||
struct in_addr start, end; /* range of available addresses */
|
||||
#ifdef HAVE_DHCP6
|
||||
struct in6_addr start6, end6; /* range of available addresses */
|
||||
int prefix;
|
||||
#endif
|
||||
int flags;
|
||||
char *interface;
|
||||
struct dhcp_netid netid, *filter;
|
||||
@@ -565,25 +600,12 @@ struct dhcp_context {
|
||||
#define CONTEXT_NETMASK 2
|
||||
#define CONTEXT_BRDCAST 4
|
||||
#define CONTEXT_PROXY 8
|
||||
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
|
||||
struct dhcp_packet {
|
||||
u8 op, htype, hlen, hops;
|
||||
u32 xid;
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
u8 options[312];
|
||||
};
|
||||
#define CONTEXT_IPV6 16
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
time_t time;
|
||||
unsigned int hash;
|
||||
struct ping_result *next;
|
||||
};
|
||||
|
||||
@@ -601,7 +623,7 @@ struct tftp_transfer {
|
||||
int backoff;
|
||||
unsigned int block, blocksize, expansion;
|
||||
off_t offset;
|
||||
struct sockaddr_in peer;
|
||||
union mysockaddr peer;
|
||||
char opt_blocksize, opt_transize, netascii, carrylf;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *next;
|
||||
@@ -629,7 +651,7 @@ extern struct daemon {
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
|
||||
unsigned int options;
|
||||
unsigned int options, options2;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
time_t last_resolv;
|
||||
struct mx_srv_record *mxnames;
|
||||
@@ -641,6 +663,7 @@ extern struct daemon {
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
char *username, *groupname, *scriptuser;
|
||||
char *luascript;
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
struct cond_domain *cond_domain;
|
||||
@@ -656,7 +679,7 @@ extern struct daemon {
|
||||
int port, query_port, min_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *dhcp_match;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
@@ -669,7 +692,7 @@ extern struct daemon {
|
||||
int enable_pxe;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
char *dhcp_hosts_file, *dhcp_opts_file;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
@@ -712,7 +735,12 @@ extern struct daemon {
|
||||
struct ping_result *ping_results;
|
||||
FILE *lease_stream;
|
||||
struct dhcp_bridge *bridges;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
int duid_len;
|
||||
unsigned char *duid;
|
||||
struct iovec outpacket;
|
||||
int dhcp6fd;
|
||||
#endif
|
||||
/* DBus stuff */
|
||||
/* void * here to avoid depending on dbus headers outside dbus.c */
|
||||
void *dbus;
|
||||
@@ -723,11 +751,14 @@ extern struct daemon {
|
||||
/* TFTP stuff */
|
||||
struct tftp_transfer *tftp_trans;
|
||||
|
||||
/* utility string buffer, hold max sized IP address as string */
|
||||
char *addrbuff;
|
||||
|
||||
} *daemon;
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
void querystr(char *str, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
@@ -741,29 +772,31 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
void cache_reload(void);
|
||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *get_domain(struct in_addr addr);
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned short extract_request(HEADER *header, size_t qlen,
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags,
|
||||
unsigned long local_ttl);
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind);
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind, int checking_disabled);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen,
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
size_t *len, unsigned char **p, int *is_sign);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
|
||||
size_t resize_packet(HEADER *header, size_t plen,
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -779,6 +812,9 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||
int hostname_isequal(char *a, char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
#ifdef HAVE_IPV6
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||
#endif
|
||||
int retry_send(void);
|
||||
void prettyprint_time(char *buf, unsigned int t);
|
||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||
@@ -804,14 +840,19 @@ void flush_log(void);
|
||||
void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(unsigned char opt, int *is_ip, int *is_name);
|
||||
void reread_dhcp(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask);
|
||||
union mysockaddr *local_addr, struct in_addr netmask);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
@@ -821,16 +862,21 @@ void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
struct listener *create_wildcard_listeners(void);
|
||||
struct listener *create_bound_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name);
|
||||
int fix_fd(int fd);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
#ifdef HAVE_IPV6
|
||||
int set_ipv6pktinfo(int fd);
|
||||
#endif
|
||||
|
||||
/* dhcp.c */
|
||||
#ifdef HAVE_DHCP
|
||||
void dhcp_init(void);
|
||||
void dhcp_packet(time_t now, int pxe_fd);
|
||||
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
|
||||
struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
struct in_addr addr,
|
||||
struct dhcp_netid *netids);
|
||||
@@ -862,7 +908,10 @@ char *get_domain(struct in_addr addr);
|
||||
void lease_update_file(time_t now);
|
||||
void lease_update_dns();
|
||||
void lease_init(time_t now);
|
||||
struct dhcp_lease *lease_allocate(struct in_addr addr);
|
||||
struct dhcp_lease *lease_allocate4(struct in_addr addr);
|
||||
#ifdef HAVE_DHCP6
|
||||
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp);
|
||||
#endif
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len);
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
|
||||
@@ -871,6 +920,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface);
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||
unsigned char *clid, int clid_len);
|
||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||
struct in_addr lease_find_max_addr(struct dhcp_context *context);
|
||||
void lease_prune(struct dhcp_lease *target, time_t now);
|
||||
void lease_update_from_configs(void);
|
||||
int do_script_run(time_t now);
|
||||
@@ -880,7 +930,7 @@ void rerun_scripts(void);
|
||||
/* 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);
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback);
|
||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||
int clid_len, unsigned char *clid, int *len_out);
|
||||
#endif
|
||||
@@ -890,7 +940,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||
int make_icmp_sock(void);
|
||||
int icmp_ping(struct in_addr addr);
|
||||
#endif
|
||||
void send_event(int fd, int event, int data);
|
||||
void send_event(int fd, int event, int data, char *msg);
|
||||
void clear_cache_and_reload(time_t now);
|
||||
void poll_resolv(int force, int do_reload, time_t now);
|
||||
|
||||
@@ -908,7 +958,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
#endif
|
||||
|
||||
/* bpf.c or netlink.c */
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
int iface_enumerate(int family, void *parm, int (callback)());
|
||||
|
||||
/* dbus.c */
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -934,3 +984,15 @@ int helper_buf_empty(void);
|
||||
void tftp_request(struct listener *listen, time_t now);
|
||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||
#endif
|
||||
|
||||
/* conntrack.c */
|
||||
#ifdef HAVE_CONNTRACK
|
||||
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
||||
int istcp, unsigned int *markp);
|
||||
#endif
|
||||
|
||||
/* rfc3315.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
void make_duid(time_t now);
|
||||
size_t dhcp6_reply(struct dhcp_context *context, size_t sz);
|
||||
#endif
|
||||
|
||||
322
src/forward.c
322
src/forward.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
|
||||
|
||||
/* Send a UDP packet with its source address set as "source"
|
||||
unless nowild is true, when we just send it with the kernel default */
|
||||
static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface)
|
||||
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
@@ -70,7 +70,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
p.ipi_spec_dst = source->addr.addr4;
|
||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = SOL_IP;
|
||||
cmptr->cmsg_level = IPPROTO_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
#elif defined(IP_SENDSRCADDR)
|
||||
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
||||
@@ -88,10 +88,10 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
cmptr->cmsg_type = daemon->v6pktinfo;
|
||||
cmptr->cmsg_level = IPV6_LEVEL;
|
||||
cmptr->cmsg_level = IPPROTO_IPV6;
|
||||
}
|
||||
#else
|
||||
iface = 0; /* eliminate warning */
|
||||
(void)iface; /* eliminate warning */
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -111,8 +111,8 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain, int *norebind)
|
||||
static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind)
|
||||
|
||||
{
|
||||
/* If the query ends in the domain in one of our servers, set
|
||||
@@ -122,13 +122,13 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned int namelen = strlen(qdomain);
|
||||
unsigned int matchlen = 0;
|
||||
struct server *serv;
|
||||
unsigned short flags = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv=serv->next)
|
||||
/* domain matches take priority over NODOTS matches */
|
||||
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = SERV_FOR_NODOTS;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
@@ -158,39 +158,59 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
{
|
||||
if (serv->flags & SERV_NO_REBIND)
|
||||
*norebind = 1;
|
||||
else if (domainlen >= matchlen)
|
||||
else
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
/* implement priority rules for --address and --server for same domain.
|
||||
--address wins if the address is for the correct AF
|
||||
--server wins otherwise. */
|
||||
if (domainlen != 0 && domainlen == matchlen)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
if ((serv->flags & SERV_LITERAL_ADDRESS))
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
if (!(sflag & qtype) && flags == 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & (F_IPV4 | F_IPV6))
|
||||
continue;
|
||||
}
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
if (domainlen >= matchlen)
|
||||
{
|
||||
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags == 0 && !(qtype & F_BIGNAME) &&
|
||||
(daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward simple names, make exception for NS queries and empty name. */
|
||||
flags = F_NXDOMAIN;
|
||||
if (flags == 0 && !(qtype & F_QUERY) &&
|
||||
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward A or AAAA queries for simple names, except the empty name */
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
||||
flags = F_NOERR;
|
||||
@@ -214,16 +234,19 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
|
||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
||||
struct dns_header *header, size_t plen, time_t now, struct frec *forward)
|
||||
{
|
||||
char *domain = NULL;
|
||||
int type = 0, norebind = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
unsigned short flags = 0;
|
||||
unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned int flags = 0;
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
struct server *start = NULL;
|
||||
|
||||
|
||||
/* RFC 4035: sect 4.6 para 2 */
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
/* may be no servers available. */
|
||||
if (!daemon->servers)
|
||||
forward = NULL;
|
||||
@@ -232,7 +255,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* retry on existing query, send to all available servers */
|
||||
domain = forward->sentto->domain;
|
||||
forward->sentto->failed_queries++;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
if (!option_bool(OPT_ORDER))
|
||||
{
|
||||
forward->forwardall = 1;
|
||||
daemon->last_server = NULL;
|
||||
@@ -261,9 +284,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->fd = udpfd;
|
||||
forward->crc = crc;
|
||||
forward->forwardall = 0;
|
||||
forward->norebind = norebind;
|
||||
header->id = htons(forward->new_id);
|
||||
if (norebind)
|
||||
forward->flags |= FREC_NOREBIND;
|
||||
if (header->hb4 & HB4_CD)
|
||||
forward->flags |= FREC_CHECKING_DISABLED;
|
||||
|
||||
header->id = htons(forward->new_id);
|
||||
|
||||
/* In strict_order mode, always try servers in the order
|
||||
specified in resolv.conf, if a domain is given
|
||||
always try all the available servers,
|
||||
@@ -271,7 +298,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
if (daemon->options & OPT_ORDER)
|
||||
if (option_bool(OPT_ORDER))
|
||||
start = daemon->servers;
|
||||
else if (!(start = daemon->last_server) ||
|
||||
daemon->forwardcount++ > FORWARD_TEST ||
|
||||
@@ -286,7 +313,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
else
|
||||
{
|
||||
start = daemon->servers;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
if (!option_bool(OPT_ORDER))
|
||||
forward->forwardall = 1;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +327,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
{
|
||||
struct server *firstsentto = start;
|
||||
int forwarded = 0;
|
||||
|
||||
|
||||
if (udpaddr && option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* only send to servers dealing with our domain.
|
||||
@@ -336,6 +366,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
daemon->rfd_save = forward->rfd4;
|
||||
fd = forward->rfd4->fd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
/* Copy connection mark of incoming query to outgoing connection. */
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sendto(fd, (char *)header, plen, 0,
|
||||
@@ -389,14 +429,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (udpfd != -1)
|
||||
{
|
||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||
send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t process_reply(HEADER *header, time_t now,
|
||||
struct server *server, size_t n, int check_rebind)
|
||||
static size_t process_reply(struct dns_header *header, time_t now,
|
||||
struct server *server, size_t n, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
int munged = 0, is_sign;
|
||||
@@ -416,29 +456,33 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
}
|
||||
|
||||
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||
/* RFC 4035 sect 4.6 para 3 */
|
||||
if (!is_sign && !option_bool(OPT_DNSSEC))
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
|
||||
return n;
|
||||
|
||||
/* Complain loudly if the upstream server is non-recursive. */
|
||||
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
|
||||
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
|
||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
if (!option_bool(OPT_LOG))
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
|
||||
if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
|
||||
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||
{
|
||||
munged = 1;
|
||||
header->rcode = NXDOMAIN;
|
||||
header->aa = 0;
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
header->hb3 &= ~HB3_AA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (header->rcode == NXDOMAIN &&
|
||||
if (RCODE(header) == NXDOMAIN &&
|
||||
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
check_for_local_domain(daemon->namebuff, now))
|
||||
{
|
||||
@@ -446,11 +490,11 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||
since we know that the domain exists, even if upstream doesn't */
|
||||
munged = 1;
|
||||
header->aa = 1;
|
||||
header->rcode = NOERROR;
|
||||
header->hb3 |= HB3_AA;
|
||||
SET_RCODE(header, NOERROR);
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -478,7 +522,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
{
|
||||
/* packet from peer server, extract data for cache, and send to
|
||||
original requester */
|
||||
HEADER *header;
|
||||
struct dns_header *header;
|
||||
union mysockaddr serveraddr;
|
||||
struct frec *forward;
|
||||
socklen_t addrlen = sizeof(serveraddr);
|
||||
@@ -502,17 +546,17 @@ void reply_query(int fd, int family, time_t now)
|
||||
sockaddr_isequal(&server->addr, &serveraddr))
|
||||
break;
|
||||
|
||||
header = (HEADER *)daemon->packet;
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
|
||||
if (!server ||
|
||||
n < (int)sizeof(HEADER) || !header->qr ||
|
||||
n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
|
||||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
||||
return;
|
||||
|
||||
server = forward->sentto;
|
||||
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
||||
!(daemon->options & OPT_ORDER) &&
|
||||
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
@@ -529,8 +573,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->arcount = htons(0);
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
header->qr = 0;
|
||||
header->tc = 0;
|
||||
header->hb3 &= ~(HB3_QR | HB3_TC);
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
||||
return;
|
||||
}
|
||||
@@ -539,7 +582,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
{
|
||||
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
|
||||
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
|
||||
server = NULL;
|
||||
else
|
||||
{
|
||||
@@ -554,7 +597,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(daemon->options & OPT_ALL_SERVERS))
|
||||
if (!option_bool(OPT_ALL_SERVERS))
|
||||
daemon->last_server = server;
|
||||
}
|
||||
|
||||
@@ -563,18 +606,18 @@ void reply_query(int fd, int family, time_t now)
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
everything is broken */
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
{
|
||||
int check_rebind = !forward->norebind;
|
||||
int check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
|
||||
if (!(daemon->options & OPT_NO_REBIND))
|
||||
if (!option_bool(OPT_NO_REBIND))
|
||||
check_rebind = 0;
|
||||
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind)))
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
free_frec(forward); /* cancel */
|
||||
@@ -584,7 +627,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
HEADER *header = (HEADER *)daemon->packet;
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
union mysockaddr source_addr;
|
||||
unsigned short type;
|
||||
struct all_addr dst_addr;
|
||||
@@ -614,7 +657,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
|
||||
if (listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
@@ -639,9 +682,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
||||
return;
|
||||
|
||||
if (n < (int)sizeof(HEADER) ||
|
||||
if (n < (int)sizeof(struct dns_header) ||
|
||||
(msg.msg_flags & MSG_TRUNC) ||
|
||||
header->qr)
|
||||
(header->hb3 & HB3_QR))
|
||||
return;
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
@@ -649,8 +692,8 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (listen->family == AF_INET6)
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
@@ -660,7 +703,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
@@ -700,7 +743,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
@@ -717,11 +760,11 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/* enforce available interface configuration */
|
||||
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
|
||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (listen->family == AF_INET &&
|
||||
(daemon->options & OPT_LOCALISE) &&
|
||||
option_bool(OPT_LOCALISE) &&
|
||||
ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
|
||||
return;
|
||||
|
||||
@@ -748,7 +791,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
{
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
||||
m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
@@ -764,17 +807,25 @@ void receive_query(struct listener *listen, time_t now)
|
||||
about resources for debug mode, when the fork is suppressed: that's
|
||||
done by the caller. */
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask)
|
||||
union mysockaddr *local_addr, struct in_addr netmask)
|
||||
{
|
||||
int size = 0, norebind = 0;
|
||||
size_t size = 0;
|
||||
int norebind = 0;
|
||||
int checking_disabled;
|
||||
size_t m;
|
||||
unsigned short qtype, gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
HEADER *header;
|
||||
struct dns_header *header;
|
||||
struct server *last_server;
|
||||
struct in_addr dst_addr_4;
|
||||
union mysockaddr peer_addr;
|
||||
socklen_t peer_len = sizeof(union mysockaddr);
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!packet ||
|
||||
@@ -783,51 +834,59 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
!read_write(confd, packet, size, 1))
|
||||
return packet;
|
||||
|
||||
if (size < (int)sizeof(HEADER))
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
header = (HEADER *)packet;
|
||||
header = (struct dns_header *)packet;
|
||||
|
||||
/* save state of "cd" flag in query */
|
||||
checking_disabled = header->hb4 & HB4_CD;
|
||||
|
||||
/* RFC 4035: sect 4.6 para 2 */
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
{
|
||||
union mysockaddr peer_addr;
|
||||
socklen_t peer_len = sizeof(union mysockaddr);
|
||||
char types[20];
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
||||
{
|
||||
char types[20];
|
||||
|
||||
querystr(types, qtype);
|
||||
|
||||
if (peer_addr.sa.sa_family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
||||
querystr(types, qtype);
|
||||
|
||||
if (peer_addr.sa.sa_family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (local_addr->sa.sa_family == AF_INET)
|
||||
dst_addr_4 = local_addr->in.sin_addr;
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
||||
local_addr, netmask, now);
|
||||
dst_addr_4, netmask, now);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(NULL);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
unsigned short flags = 0;
|
||||
unsigned int flags = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = 0;
|
||||
char *domain = NULL;
|
||||
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
else
|
||||
last_server = daemon->last_server;
|
||||
@@ -857,18 +916,38 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (type != (last_server->flags & SERV_TYPE) ||
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||
continue;
|
||||
|
||||
if ((last_server->tcpfd == -1) &&
|
||||
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
|
||||
(!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
|
||||
if (last_server->tcpfd == -1)
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||
continue;
|
||||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
/* Copy connection mark of incoming query to outgoing connection. */
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
struct all_addr local;
|
||||
#ifdef HAVE_IPV6
|
||||
if (local_addr->sa.sa_family == AF_INET6)
|
||||
local.addr.addr6 = local_addr->in6.sin6_addr;
|
||||
else
|
||||
#endif
|
||||
local.addr.addr4 = local_addr->in.sin_addr;
|
||||
|
||||
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
|
||||
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (last_server->tcpfd == -1)
|
||||
continue;
|
||||
|
||||
c1 = size >> 8;
|
||||
c2 = size;
|
||||
@@ -906,7 +985,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(header, now, last_server, (unsigned int)m, (daemon->options & OPT_NO_REBIND) && !norebind );
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -938,6 +1018,7 @@ static struct frec *allocate_frec(time_t now)
|
||||
f->time = now;
|
||||
f->sentto = NULL;
|
||||
f->rfd4 = NULL;
|
||||
f->flags = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
@@ -990,6 +1071,7 @@ static void free_frec(struct frec *f)
|
||||
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
f->flags = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (f->rfd6 && --(f->rfd6->refcount) == 0)
|
||||
|
||||
299
src/helper.c
299
src/helper.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
|
||||
/* This file has code to fork a helper process which recieves data via a pipe
|
||||
shared with the main process and which is responsible for calling a script when
|
||||
DHCP leases change.
|
||||
@@ -28,11 +30,20 @@
|
||||
main process.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
||||
|
||||
static void my_setenv(const char *name, const char *value, int *error);
|
||||
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
lua_State *lua;
|
||||
|
||||
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
|
||||
#endif
|
||||
|
||||
|
||||
struct script_data
|
||||
{
|
||||
unsigned char action, hwaddr_len, hwaddr_type;
|
||||
@@ -61,7 +72,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
then fork our process. */
|
||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||
{
|
||||
send_event(err_fd, EVENT_PIPE_ERR, errno);
|
||||
send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
@@ -79,47 +90,107 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && uid != 0)
|
||||
if (!option_bool(OPT_DEBUG) && uid != 0)
|
||||
{
|
||||
gid_t dummy;
|
||||
if (setgroups(0, &dummy) == -1 ||
|
||||
setgid(gid) == -1 ||
|
||||
setuid(uid) == -1)
|
||||
{
|
||||
if (daemon->options & OPT_NO_FORK)
|
||||
if (option_bool(OPT_NO_FORK))
|
||||
/* send error to daemon process if no-fork */
|
||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
||||
send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||
else
|
||||
{
|
||||
/* kill daemon */
|
||||
send_event(event_fd, EVENT_DIE, 0);
|
||||
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||
/* return error */
|
||||
send_event(err_fd, EVENT_HUSER_ERR, errno);
|
||||
send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
|
||||
main process can return. */
|
||||
/* close all the sockets etc, we don't need them here.
|
||||
Don't close err_fd, in case the lua-init fails.
|
||||
Note that we have to do this before lua init
|
||||
so we don't close any lua fds. */
|
||||
for (max_fd--; max_fd >= 0; max_fd--)
|
||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_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)
|
||||
{
|
||||
const char *lua_err = NULL;
|
||||
lua = lua_open();
|
||||
luaL_openlibs(lua);
|
||||
|
||||
/* get Lua to load our script file */
|
||||
if (luaL_dofile(lua, daemon->luascript) != 0)
|
||||
lua_err = lua_tostring(lua, -1);
|
||||
else
|
||||
{
|
||||
lua_getglobal(lua, "lease");
|
||||
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||
lua_err = _("lease() function missing in Lua script");
|
||||
}
|
||||
|
||||
if (lua_err)
|
||||
{
|
||||
if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
|
||||
/* send error to daemon process if no-fork */
|
||||
send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||
else
|
||||
{
|
||||
/* kill daemon */
|
||||
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||
/* return error */
|
||||
send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
lua_pop(lua, 1); /* remove nil from stack */
|
||||
lua_getglobal(lua, "init");
|
||||
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||
lua_call(lua, 0, 0);
|
||||
else
|
||||
lua_pop(lua, 1); /* remove nil from stack */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* All init done, close our copy of the error pipe, so that main process can return */
|
||||
if (err_fd != -1)
|
||||
close(err_fd);
|
||||
|
||||
/* loop here */
|
||||
while(1)
|
||||
{
|
||||
struct script_data data;
|
||||
char *p, *action_str, *hostname = NULL;
|
||||
char *p, *action_str, *hostname = NULL, *domain = NULL;
|
||||
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
||||
unsigned char *end, *alloc_buff = NULL;
|
||||
unsigned char *end, *extradata, *alloc_buff = NULL;
|
||||
int err = 0;
|
||||
|
||||
free(alloc_buff);
|
||||
|
||||
/* we read zero bytes when pipe closed: this is our signal to exit */
|
||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
||||
_exit(0);
|
||||
|
||||
{
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
if (daemon->luascript)
|
||||
{
|
||||
lua_getglobal(lua, "shutdown");
|
||||
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||
lua_call(lua, 0, 0);
|
||||
}
|
||||
#endif
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (data.action == ACTION_DEL)
|
||||
action_str = "del";
|
||||
else if (data.action == ACTION_ADD)
|
||||
@@ -139,42 +210,142 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
if (i != data.hwaddr_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
|
||||
/* and CLID into packet, avoid overwrite from bad data */
|
||||
if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
|
||||
|
||||
/* expiry or length into dhcp_buff2 */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||
#else
|
||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||
#endif
|
||||
|
||||
/* supplied data may just exceed normal buffer (unlikely) */
|
||||
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
|
||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
|
||||
continue;
|
||||
|
||||
if (!read_write(pipefd[0], buf,
|
||||
data.hostname_len + data.ed_len + data.clid_len, 1))
|
||||
continue;
|
||||
|
||||
/* CLID into packet */
|
||||
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
||||
{
|
||||
p += sprintf(p, "%.2x", buf[i]);
|
||||
if (i != data.clid_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
|
||||
/* and expiry or length into dhcp_buff2 */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||
|
||||
buf += data.clid_len;
|
||||
|
||||
if (data.hostname_len != 0)
|
||||
{
|
||||
char *dot;
|
||||
hostname = (char *)buf;
|
||||
hostname[data.hostname_len - 1] = 0;
|
||||
if (!legal_hostname(hostname))
|
||||
hostname = NULL;
|
||||
else if ((dot = strchr(hostname, '.')))
|
||||
{
|
||||
domain = dot+1;
|
||||
*dot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extradata = buf + data.hostname_len;
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
if (daemon->luascript)
|
||||
{
|
||||
lua_getglobal(lua, "lease"); /* function to call */
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
|
||||
if (data.clid_len != 0)
|
||||
{
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "client_id");
|
||||
}
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
{
|
||||
lua_pushstring(lua, data.interface);
|
||||
lua_setfield(lua, -2, "interface");
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lua_pushnumber(lua, data.length);
|
||||
lua_setfield(lua, -2, "lease_length");
|
||||
#else
|
||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||
lua_pushnumber(lua, data.expires);
|
||||
lua_setfield(lua, -2, "lease_expires");
|
||||
#endif
|
||||
|
||||
if (hostname)
|
||||
{
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "hostname");
|
||||
}
|
||||
|
||||
if (domain)
|
||||
{
|
||||
lua_pushstring(lua, domain);
|
||||
lua_setfield(lua, -2, "domain");
|
||||
}
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||
buf = grab_extradata_lua(buf, end, "tags");
|
||||
|
||||
/* supplied data may just exceed normal buffer (unlikely) */
|
||||
if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
|
||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
lua_pushnumber(lua, data.remaining_time);
|
||||
lua_setfield(lua, -2, "time_remaining");
|
||||
}
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "old_hostname");
|
||||
}
|
||||
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "mac_address");
|
||||
|
||||
lua_pushstring(lua, inet_ntoa(data.addr));
|
||||
lua_setfield(lua, -2, "ip_address");
|
||||
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no script, just lua */
|
||||
if (!daemon->lease_change_command)
|
||||
continue;
|
||||
|
||||
if (!read_write(pipefd[0], buf,
|
||||
data.hostname_len + data.ed_len, 1))
|
||||
continue;
|
||||
|
||||
|
||||
/* possible fork errors are all temporary resource problems */
|
||||
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
||||
sleep(2);
|
||||
|
||||
free(alloc_buff);
|
||||
|
||||
if (pid == -1)
|
||||
continue;
|
||||
|
||||
|
||||
/* wait for child to complete */
|
||||
if (pid != 0)
|
||||
{
|
||||
@@ -188,9 +359,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
{
|
||||
/* On error send event back to main process for logging */
|
||||
if (WIFSIGNALED(status))
|
||||
send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
|
||||
send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
|
||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
|
||||
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -213,22 +384,11 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||
#endif
|
||||
|
||||
if (data.hostname_len != 0)
|
||||
{
|
||||
char *dot;
|
||||
hostname = (char *)buf;
|
||||
hostname[data.hostname_len - 1] = 0;
|
||||
if (!legal_hostname(hostname))
|
||||
hostname = NULL;
|
||||
else if ((dot = strchr(hostname, '.')))
|
||||
{
|
||||
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
|
||||
*dot = 0;
|
||||
}
|
||||
buf += data.hostname_len;
|
||||
}
|
||||
|
||||
end = buf + data.ed_len;
|
||||
if (domain)
|
||||
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||
@@ -245,7 +405,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
if (data.giaddr.s_addr != 0)
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||
|
||||
if (data.action != ACTION_DEL)
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||
@@ -271,7 +431,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
err = errno;
|
||||
}
|
||||
/* failed, send event so the main process logs the problem */
|
||||
send_event(event_fd, EVENT_EXEC_ERR, err);
|
||||
send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
@@ -305,6 +465,28 @@ static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, ch
|
||||
return next + 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
|
||||
{
|
||||
unsigned char *next;
|
||||
|
||||
if (!buf || (buf == end))
|
||||
return NULL;
|
||||
|
||||
for (next = buf; *next != 0; next++)
|
||||
if (next == end)
|
||||
return NULL;
|
||||
|
||||
if (next != buf)
|
||||
{
|
||||
lua_pushstring(lua, (char *)buf);
|
||||
lua_setfield(lua, -2, field);
|
||||
}
|
||||
|
||||
return next + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* pack up lease data into a buffer */
|
||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||
{
|
||||
@@ -358,7 +540,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
#else
|
||||
buf->expires = lease->expires;
|
||||
#endif
|
||||
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
||||
|
||||
if (lease->expires != 0)
|
||||
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
||||
else
|
||||
buf->remaining_time = 0;
|
||||
|
||||
p = (unsigned char *)(buf+1);
|
||||
if (clid_len != 0)
|
||||
@@ -408,3 +594,4 @@ void helper_write(void)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
221
src/lease.c
221
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -24,10 +24,13 @@ static int dns_dirty, file_dirty, leases_left;
|
||||
void lease_init(time_t now)
|
||||
{
|
||||
unsigned long ei;
|
||||
struct in_addr addr;
|
||||
struct all_addr addr;
|
||||
struct dhcp_lease *lease;
|
||||
int clid_len, hw_len, hw_type;
|
||||
FILE *leasestream;
|
||||
#ifdef HAVE_DHCP6
|
||||
int v6pass = 0;
|
||||
#endif
|
||||
|
||||
/* These each hold a DHCP option max size 255
|
||||
and get a terminating zero added */
|
||||
@@ -37,7 +40,7 @@ void lease_init(time_t now)
|
||||
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
if (daemon->options & OPT_LEASE_RO)
|
||||
if (option_bool(OPT_LEASE_RO))
|
||||
{
|
||||
/* run "<lease_change_script> init" once to get the
|
||||
initial state of the database. If leasefile-ro is
|
||||
@@ -70,26 +73,46 @@ void lease_init(time_t now)
|
||||
rewind(leasestream);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
again:
|
||||
#endif
|
||||
|
||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||
borrow DNS packet buffer which is always larger than 1000 bytes */
|
||||
if (leasestream)
|
||||
while (fscanf(leasestream, "%lu %255s %16s %255s %764s",
|
||||
while (fscanf(leasestream, "%lu %255s %64s %255s %764s",
|
||||
&ei, daemon->dhcp_buff2, daemon->namebuff,
|
||||
daemon->dhcp_buff, daemon->packet) == 5)
|
||||
{
|
||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
addr.s_addr = inet_addr(daemon->namebuff);
|
||||
|
||||
/* decode hex in place */
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!v6pass)
|
||||
#endif
|
||||
{
|
||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (v6pass)
|
||||
inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6);
|
||||
else
|
||||
#endif
|
||||
inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4);
|
||||
|
||||
clid_len = 0;
|
||||
if (strcmp(daemon->packet, "*") != 0)
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
|
||||
if (!(lease = lease_allocate(addr)))
|
||||
#ifdef HAVE_DHCP6
|
||||
if (v6pass)
|
||||
lease = lease_allocate6(&addr.addr.addr6);
|
||||
else
|
||||
#endif
|
||||
lease = lease_allocate4(addr.addr.addr4);
|
||||
|
||||
if (!lease)
|
||||
die (_("too many stored leases"), NULL, EC_MISC);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
@@ -103,8 +126,11 @@ void lease_init(time_t now)
|
||||
even when sizeof(time_t) == 8 */
|
||||
lease->expires = (time_t)ei;
|
||||
#endif
|
||||
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!v6pass)
|
||||
#endif
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
||||
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
||||
@@ -113,6 +139,24 @@ void lease_init(time_t now)
|
||||
the startup synthesised SIGHUP. */
|
||||
lease->new = lease->changed = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!v6pass)
|
||||
{
|
||||
if (fscanf(leasestream, "duid %255s", daemon->dhcp_buff) == 1)
|
||||
{
|
||||
daemon->duid_len = parse_hex(daemon->dhcp_buff, (unsigned char *)daemon->dhcp_buff, 130, NULL, NULL);
|
||||
daemon->duid = safe_malloc(daemon->duid_len);
|
||||
memcpy(daemon->duid, daemon->dhcp_buff, daemon->duid_len );
|
||||
v6pass = 1;
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
|
||||
if (daemon->dhcp6)
|
||||
make_duid(now);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (!daemon->lease_stream)
|
||||
@@ -186,11 +230,18 @@ void lease_update_file(time_t now)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
ourprintf(&err, "%u ", lease->length);
|
||||
#else
|
||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||
#endif
|
||||
|
||||
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
||||
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
||||
for (i = 0; i < lease->hwaddr_len; i++)
|
||||
@@ -199,8 +250,10 @@ void lease_update_file(time_t now)
|
||||
if (i != lease->hwaddr_len - 1)
|
||||
ourprintf(&err, ":");
|
||||
}
|
||||
|
||||
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
ourprintf(&err, " %s ", inet_ntoa(lease->addr));
|
||||
ourprintf(&err, " %s ", daemon->addrbuff);
|
||||
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
@@ -213,6 +266,43 @@ void lease_update_file(time_t now)
|
||||
ourprintf(&err, "*\n");
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->duid)
|
||||
{
|
||||
ourprintf(&err, "duid ");
|
||||
for (i = 0; i < daemon->duid_len - 1; i++)
|
||||
ourprintf(&err, "%.2x:", daemon->duid[i]);
|
||||
ourprintf(&err, "%.2x\n", daemon->duid[i]);
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
|
||||
if (!lease->is_ipv6)
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
ourprintf(&err, "%u ", lease->length);
|
||||
#else
|
||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||
#endif
|
||||
|
||||
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
ourprintf(&err, "* %s ", daemon->addrbuff);
|
||||
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
{
|
||||
for (i = 0; i < lease->clid_len - 1; i++)
|
||||
ourprintf(&err, "%.2x:", lease->clid[i]);
|
||||
ourprintf(&err, "%.2x\n", lease->clid[i]);
|
||||
}
|
||||
else
|
||||
ourprintf(&err, "*\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fflush(daemon->lease_stream) != 0 ||
|
||||
fsync(fileno(daemon->lease_stream)) < 0)
|
||||
err = errno;
|
||||
@@ -254,7 +344,7 @@ void lease_update_dns(void)
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
||||
|
||||
if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
|
||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
||||
}
|
||||
|
||||
@@ -275,7 +365,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
||||
if (lease->hostname)
|
||||
dns_dirty = 1;
|
||||
|
||||
*up = lease->next; /* unlink */
|
||||
*up = lease->next; /* unlink */
|
||||
|
||||
/* Put on old_leases list 'till we
|
||||
can run the script */
|
||||
@@ -297,18 +387,30 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
||||
|
||||
if (clid)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->clid && clid_len == lease->clid_len &&
|
||||
memcmp(clid, lease->clid, clid_len) == 0)
|
||||
return lease;
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
continue;
|
||||
#endif
|
||||
if (lease->clid && clid_len == lease->clid_len &&
|
||||
memcmp(clid, lease->clid, clid_len) == 0)
|
||||
return lease;
|
||||
}
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((!lease->clid || !clid) &&
|
||||
hw_len != 0 &&
|
||||
lease->hwaddr_len == hw_len &&
|
||||
lease->hwaddr_type == hw_type &&
|
||||
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
||||
return lease;
|
||||
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
continue;
|
||||
#endif
|
||||
if ((!lease->clid || !clid) &&
|
||||
hw_len != 0 &&
|
||||
lease->hwaddr_len == hw_len &&
|
||||
lease->hwaddr_type == hw_type &&
|
||||
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -317,14 +419,41 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->addr.s_addr == addr.s_addr)
|
||||
return lease;
|
||||
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
continue;
|
||||
#endif
|
||||
if (lease->addr.s_addr == addr.s_addr)
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find largest assigned address in context */
|
||||
struct in_addr lease_find_max_addr(struct dhcp_context *context)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
struct in_addr addr = context->start;
|
||||
|
||||
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (lease->is_ipv6)
|
||||
continue;
|
||||
#endif
|
||||
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
|
||||
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
|
||||
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
|
||||
addr = lease->addr;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
struct dhcp_lease *lease_allocate(struct in_addr addr)
|
||||
static struct dhcp_lease *lease_allocate(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
||||
@@ -332,8 +461,6 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
||||
|
||||
memset(lease, 0, sizeof(struct dhcp_lease));
|
||||
lease->new = 1;
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
lease->expires = 1;
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lease->length = 0xffffffff; /* illegal value */
|
||||
@@ -347,6 +474,26 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
||||
return lease;
|
||||
}
|
||||
|
||||
struct dhcp_lease *lease_allocate4(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->is_ipv6 = 1;
|
||||
|
||||
return lease;
|
||||
}
|
||||
#endif
|
||||
|
||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
||||
{
|
||||
time_t exp = now + (time_t)len;
|
||||
@@ -470,7 +617,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
/* Depending on mode, we check either unqualified name or FQDN. */
|
||||
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
|
||||
{
|
||||
if (daemon->options & OPT_DHCP_FQDN)
|
||||
if (option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
|
||||
continue;
|
||||
@@ -534,7 +681,7 @@ int do_script_run(time_t now)
|
||||
#ifdef HAVE_DBUS
|
||||
/* If we're going to be sending DBus signals, but the connection is not yet up,
|
||||
delay everything until it is. */
|
||||
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -586,7 +733,7 @@ int do_script_run(time_t now)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->new || lease->changed ||
|
||||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
|
||||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
||||
|
||||
75
src/log.c
75
src/log.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <android/log.h>
|
||||
#endif
|
||||
|
||||
/* Implement logging to /dev/log asynchronously. If syslogd is
|
||||
making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
|
||||
syslogd, then the two daemons can deadlock. We get around this
|
||||
@@ -55,12 +59,12 @@ int log_start(struct passwd *ent_pw, int errfd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
echo_stderr = !!(daemon->options & OPT_DEBUG);
|
||||
echo_stderr = option_bool(OPT_DEBUG);
|
||||
|
||||
if (daemon->log_fac != -1)
|
||||
log_fac = daemon->log_fac;
|
||||
#ifdef LOG_LOCAL0
|
||||
else if (daemon->options & OPT_DEBUG)
|
||||
else if (option_bool(OPT_DEBUG))
|
||||
log_fac = LOG_LOCAL0;
|
||||
#endif
|
||||
|
||||
@@ -80,7 +84,7 @@ int log_start(struct passwd *ent_pw, int errfd)
|
||||
|
||||
if (!log_reopen(daemon->log_file))
|
||||
{
|
||||
send_event(errfd, EVENT_LOG_ERR, errno);
|
||||
send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
@@ -117,7 +121,7 @@ int log_reopen(char *log_file)
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
|
||||
/* Solaris logging is "different", /dev/log is not unix-domain socket.
|
||||
Just leave log_fd == -1 and use the vsyslog call for everything.... */
|
||||
# define _PATH_LOG "" /* dummy */
|
||||
@@ -150,6 +154,19 @@ static void log_write(void)
|
||||
|
||||
while (entries)
|
||||
{
|
||||
/* The data in the payoad is written with a terminating zero character
|
||||
and the length reflects this. For a stream connection we need to
|
||||
send the zero as a record terminator, but this isn't done for a
|
||||
datagram connection, so treat the length as one less than reality
|
||||
to elide the zero. If we're logging to a file, turn the zero into
|
||||
a newline, and leave the length alone. */
|
||||
int len_adjust = 0;
|
||||
|
||||
if (log_to_file)
|
||||
entries->payload[entries->offset + entries->length - 1] = '\n';
|
||||
else if (connection_type == SOCK_DGRAM)
|
||||
len_adjust = 1;
|
||||
|
||||
/* Avoid duplicates over a fork() */
|
||||
if (entries->pid != getpid())
|
||||
{
|
||||
@@ -159,11 +176,11 @@ static void log_write(void)
|
||||
|
||||
connection_good = 1;
|
||||
|
||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
|
||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
|
||||
{
|
||||
entries->length -= rc;
|
||||
entries->offset += rc;
|
||||
if (entries->length == 0)
|
||||
if (entries->length == len_adjust)
|
||||
{
|
||||
free_entry();
|
||||
if (entries_lost != 0)
|
||||
@@ -179,7 +196,7 @@ static void log_write(void)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return; /* syslogd busy, go again when select() or poll() says so */
|
||||
|
||||
if (errno == ENOBUFS)
|
||||
@@ -227,7 +244,8 @@ static void log_write(void)
|
||||
errno == ECONNREFUSED ||
|
||||
errno == EISCONN ||
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN)
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)
|
||||
{
|
||||
/* try again on next syslog() call */
|
||||
connection_good = 0;
|
||||
@@ -289,8 +307,28 @@ void my_syslog(int priority, const char *format, ...)
|
||||
|
||||
if (log_fd == -1)
|
||||
{
|
||||
/* fall-back to syslog if we die during startup or fail during running. */
|
||||
#ifdef __ANDROID__
|
||||
/* do android-specific logging.
|
||||
log_fd is always -1 on Android except when logging to a file. */
|
||||
int alog_lvl;
|
||||
|
||||
if (priority <= LOG_ERR)
|
||||
alog_lvl = ANDROID_LOG_ERROR;
|
||||
else if (priority == LOG_WARNING)
|
||||
alog_lvl = ANDROID_LOG_WARN;
|
||||
else if (priority <= LOG_INFO)
|
||||
alog_lvl = ANDROID_LOG_INFO;
|
||||
else
|
||||
alog_lvl = ANDROID_LOG_DEBUG;
|
||||
|
||||
va_start(ap, format);
|
||||
__android_log_vprint(alog_lvl, "dnsmasq", format, ap);
|
||||
va_end(ap);
|
||||
#else
|
||||
/* fall-back to syslog if we die during startup or
|
||||
fail during running (always on Solaris). */
|
||||
static int isopen = 0;
|
||||
|
||||
if (!isopen)
|
||||
{
|
||||
openlog("dnsmasq", LOG_PID, log_fac);
|
||||
@@ -299,6 +337,8 @@ void my_syslog(int priority, const char *format, ...)
|
||||
va_start(ap, format);
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -327,7 +367,11 @@ void my_syslog(int priority, const char *format, ...)
|
||||
if (!log_to_file)
|
||||
p += sprintf(p, "<%d>", priority | log_fac);
|
||||
|
||||
p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int)pid);
|
||||
/* Omit timestamp for default daemontools situation */
|
||||
if (!log_stderr || !option_bool(OPT_NO_FORK))
|
||||
p += sprintf(p, "%.15s ", ctime(&time_now) + 4);
|
||||
|
||||
p += sprintf(p, "dnsmasq%s[%d]: ", func, (int)pid);
|
||||
|
||||
len = p - entry->payload;
|
||||
va_start(ap, format);
|
||||
@@ -336,10 +380,6 @@ void my_syslog(int priority, const char *format, ...)
|
||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||
entry->offset = 0;
|
||||
entry->pid = pid;
|
||||
|
||||
/* replace terminator with \n */
|
||||
if (log_to_file)
|
||||
entry->payload[entry->length - 1] = '\n';
|
||||
}
|
||||
|
||||
/* almost always, logging won't block, so try and write this now,
|
||||
@@ -398,12 +438,13 @@ void check_log_writer(fd_set *set)
|
||||
|
||||
void flush_log(void)
|
||||
{
|
||||
/* write until queue empty */
|
||||
/* write until queue empty, but don't loop forever if there's
|
||||
no connection to the syslog in existance */
|
||||
while (log_fd != -1)
|
||||
{
|
||||
struct timespec waiter;
|
||||
log_write();
|
||||
if (!entries)
|
||||
if (!entries || !connection_good)
|
||||
{
|
||||
close(log_fd);
|
||||
break;
|
||||
|
||||
150
src/netlink.c
150
src/netlink.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,11 @@
|
||||
# include <linux/if_addr.h>
|
||||
#endif
|
||||
|
||||
#ifndef NDA_RTA
|
||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
#endif
|
||||
|
||||
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
@@ -122,13 +127,15 @@ static ssize_t netlink_recv(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
|
||||
/* family = AF_UNSPEC finds ARP table entries.
|
||||
family = AF_LOCAL finds MAC addresses. */
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int family = AF_INET;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -139,10 +146,16 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
addr.nl_pad = 0;
|
||||
addr.nl_groups = 0;
|
||||
addr.nl_pid = 0; /* address to kernel */
|
||||
|
||||
again:
|
||||
if (family == AF_UNSPEC)
|
||||
req.nlh.nlmsg_type = RTM_GETNEIGH;
|
||||
else if (family == AF_LOCAL)
|
||||
req.nlh.nlmsg_type = RTM_GETLINK;
|
||||
else
|
||||
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||
|
||||
again:
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
||||
req.nlh.nlmsg_pid = 0;
|
||||
req.nlh.nlmsg_seq = ++seq;
|
||||
@@ -173,66 +186,109 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
else if (h->nlmsg_type == NLMSG_ERROR)
|
||||
nl_err(h);
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET && ipv6_callback)
|
||||
{
|
||||
family = AF_INET6;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||
return 1;
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
struct rtattr *rta = IFA_RTA(ifa);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
|
||||
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
if (ifa->ifa_family == family)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr)
|
||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr.s_addr && ipv4_callback)
|
||||
if (!((*ipv4_callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addrp = NULL;
|
||||
while (RTA_OK(rta, len1))
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
struct in6_addr *addrp = NULL;
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
if (addrp)
|
||||
if (!((*callback)(addrp, ifa->ifa_prefixlen, ifa->ifa_index,
|
||||
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm)))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
|
||||
{
|
||||
struct ndmsg *neigh = NLMSG_DATA(h);
|
||||
struct rtattr *rta = NDA_RTA(neigh);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
|
||||
size_t maclen = 0;
|
||||
char *inaddr = NULL, *mac = NULL;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == NDA_DST)
|
||||
inaddr = (char *)(rta+1);
|
||||
else if (rta->rta_type == NDA_LLADDR)
|
||||
{
|
||||
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||
mac = (char *)(rta+1);
|
||||
}
|
||||
|
||||
if (addrp && ipv6_callback)
|
||||
if (!((*ipv6_callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
||||
return 0;
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (inaddr && mac)
|
||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
|
||||
{
|
||||
struct ifinfomsg *link = NLMSG_DATA(h);
|
||||
struct rtattr *rta = IFLA_RTA(link);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
|
||||
char *mac = NULL;
|
||||
size_t maclen = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFLA_ADDRESS)
|
||||
{
|
||||
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||
mac = (char *)(rta+1);
|
||||
}
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (mac && !((*callback)(link->ifi_type, link->ifi_flags, mac, maclen, parm)))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void netlink_multicast(void)
|
||||
{
|
||||
ssize_t len;
|
||||
@@ -281,7 +337,7 @@ static void nl_routechange(struct nlmsghdr *h)
|
||||
return;
|
||||
|
||||
/* Force re-reading resolv file right now, for luck. */
|
||||
poll_resolv(1, 1, dnsmasq_time());
|
||||
daemon->last_resolv = 0;
|
||||
|
||||
if (daemon->srv_save)
|
||||
{
|
||||
|
||||
554
src/network.c
554
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -34,6 +34,67 @@ int indextoname(int fd, int index, char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
|
||||
#include <zone.h>
|
||||
#include <alloca.h>
|
||||
#ifndef LIFC_UNDER_IPMP
|
||||
# define LIFC_UNDER_IPMP 0
|
||||
#endif
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
{
|
||||
int64_t lifc_flags;
|
||||
struct lifnum lifn;
|
||||
int numifs, bufsize, i;
|
||||
struct lifconf lifc;
|
||||
struct lifreq *lifrp;
|
||||
|
||||
if (index == 0)
|
||||
return 0;
|
||||
|
||||
if (getzoneid() == GLOBAL_ZONEID)
|
||||
{
|
||||
if (!if_indextoname(index, name))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
|
||||
lifn.lifn_family = AF_UNSPEC;
|
||||
lifn.lifn_flags = lifc_flags;
|
||||
if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0)
|
||||
return 0;
|
||||
|
||||
numifs = lifn.lifn_count;
|
||||
bufsize = numifs * sizeof(struct lifreq);
|
||||
|
||||
lifc.lifc_family = AF_UNSPEC;
|
||||
lifc.lifc_flags = lifc_flags;
|
||||
lifc.lifc_len = bufsize;
|
||||
lifc.lifc_buf = alloca(bufsize);
|
||||
|
||||
if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0)
|
||||
return 0;
|
||||
|
||||
lifrp = lifc.lifc_req;
|
||||
for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)
|
||||
{
|
||||
struct lifreq lifr;
|
||||
strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
|
||||
return 0;
|
||||
|
||||
if (lifr.lifr_index == index) {
|
||||
strncpy(name, lifr.lifr_name, IF_NAMESIZE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
@@ -46,7 +107,7 @@ int indextoname(int fd, int index, char *name)
|
||||
|
||||
#endif
|
||||
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
||||
int iface_check(int family, struct all_addr *addr, char *name)
|
||||
{
|
||||
struct iname *tmp;
|
||||
int ret = 1;
|
||||
@@ -54,7 +115,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
||||
/* Note: have to check all and not bail out early, so that we set the
|
||||
"used" flags. */
|
||||
|
||||
if (daemon->if_names || (addr && daemon->if_addrs))
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
#ifdef HAVE_DHCP
|
||||
struct dhcp_context *range;
|
||||
@@ -73,7 +134,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
||||
ret = tmp->used = 1;
|
||||
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (addr && tmp->addr.sa.sa_family == family)
|
||||
if (tmp->addr.sa.sa_family == family)
|
||||
{
|
||||
if (family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
@@ -90,43 +151,12 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
ret = 0;
|
||||
|
||||
if (indexp)
|
||||
{
|
||||
/* One form of bridging on BSD has the property that packets
|
||||
can be recieved on bridge interfaces which do not have an IP address.
|
||||
We allow these to be treated as aliases of another interface which does have
|
||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (strncmp(name, alias->iface, IF_NAMESIZE) == 0)
|
||||
{
|
||||
int newindex;
|
||||
|
||||
if (!(newindex = if_nametoindex(bridge->iface)))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), name);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*indexp = newindex;
|
||||
strncpy(name, bridge->iface, IF_NAMESIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (alias)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
union mysockaddr *addr, struct in_addr netmask)
|
||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||
{
|
||||
struct irec *iface;
|
||||
int fd, mtu = 0, loopback;
|
||||
@@ -141,8 +171,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
we call this routine multiple times. */
|
||||
for (iface = *irecp; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
return 1;
|
||||
|
||||
{
|
||||
iface->dad = dad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||
@@ -188,19 +221,18 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* implement wierd TFTP service rules */
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, ifr.ifr_name) == 0)
|
||||
{
|
||||
tftp_ok = 1;
|
||||
break;
|
||||
}
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, ifr.ifr_name) == 0)
|
||||
{
|
||||
tftp_ok = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!ir)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, NULL))
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -211,7 +243,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family == AF_INET6 &&
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, NULL))
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
@@ -223,6 +255,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
iface->netmask = netmask;
|
||||
iface->tftp_ok = tftp_ok;
|
||||
iface->mtu = mtu;
|
||||
iface->dad = dad;
|
||||
iface->done = 0;
|
||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
strcpy(iface->name, ifr.ifr_name);
|
||||
iface->next = *irecp;
|
||||
@@ -235,12 +269,13 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int iface_allowed_v6(struct in6_addr *local,
|
||||
int scope, int if_index, void *vparam)
|
||||
static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* dummy */
|
||||
|
||||
(void)prefix; /* warning */
|
||||
netmask.s_addr = 0;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@@ -252,7 +287,7 @@ static int iface_allowed_v6(struct in6_addr *local,
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_scope_id = scope;
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -270,16 +305,17 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
addr.in.sin_addr = local;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||
}
|
||||
|
||||
int enumerate_interfaces(void)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
|
||||
#else
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, NULL);
|
||||
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
|
||||
}
|
||||
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
@@ -294,237 +330,209 @@ int fix_fd(int fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_IPV6)
|
||||
static int create_ipv6_listener(struct listener **link, int port)
|
||||
static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int tcpfd, fd;
|
||||
struct listener *l;
|
||||
int opt = 1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
#endif
|
||||
|
||||
/* No error of the kernel doesn't support IPv6 */
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
return (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL);
|
||||
int family = addr->sa.sa_family;
|
||||
int fd, rc, opt = 1;
|
||||
|
||||
if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||
return 0;
|
||||
if ((fd = socket(family, type, 0)) == -1)
|
||||
{
|
||||
int port;
|
||||
|
||||
/* No error if the kernel just doesn't support this IP flavour */
|
||||
if (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL)
|
||||
return -1;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
!fix_fd(tcpfd) ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return 0;
|
||||
err:
|
||||
if (dienow)
|
||||
{
|
||||
port = prettyprint_addr(addr, daemon->namebuff);
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
sprintf(daemon->namebuff, "port %d", port);
|
||||
die(_("failed to create listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||
goto err;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
|
||||
goto err;
|
||||
|
||||
if (type == SOCK_STREAM)
|
||||
{
|
||||
if (listen(fd, 5) == -1)
|
||||
goto err;
|
||||
}
|
||||
else if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (!set_ipv6pktinfo(fd))
|
||||
goto err;
|
||||
#endif
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
int set_ipv6pktinfo(int fd)
|
||||
{
|
||||
int opt = 1;
|
||||
|
||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||
handle all combinations of headers and kernel.
|
||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||
|
||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||
|
||||
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
# ifdef IPV6_2292PKTINFO
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
|
||||
return 1;
|
||||
# ifdef IPV6_2292PKTINFO
|
||||
else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||
{
|
||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||
else
|
||||
return 0;
|
||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||
return 1;
|
||||
}
|
||||
# else
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
return 0;
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
return 0;
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = -1;
|
||||
l->family = AF_INET6;
|
||||
l->next = NULL;
|
||||
*link = l;
|
||||
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct listener *create_wildcard_listeners(void)
|
||||
|
||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int opt = 1;
|
||||
struct listener *l, *l6 = NULL;
|
||||
int tcpfd = -1, fd = -1, tftpfd = -1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
struct listener *l = NULL;
|
||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
(tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
!fix_fd(tcpfd) ||
|
||||
#ifdef HAVE_IPV6
|
||||
!create_ipv6_listener(&l6, daemon->port) ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
fd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||
tcpfd = make_sock(addr, SOCK_STREAM, dienow);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
|
||||
if (do_tftp)
|
||||
{
|
||||
addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (!fix_fd(tftpfd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(tftpfd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(tftpfd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tftpfd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(tftpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
/* port must be restored to DNS port for TCP code */
|
||||
short save = addr->in.sin_port;
|
||||
addr->in.sin_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||
addr->in.sin_port = save;
|
||||
}
|
||||
# ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
short save = addr->in6.sin6_port;
|
||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||
addr->in6.sin6_port = save;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->family = AF_INET;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->next = l6;
|
||||
|
||||
if (fd != -1 || tcpfd != -1 || tftpfd != -1)
|
||||
{
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->next = NULL;
|
||||
l->family = addr->sa.sa_family;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_bound_listeners(void)
|
||||
void create_wildcard_listeners(void)
|
||||
{
|
||||
struct listener *listeners = NULL;
|
||||
struct irec *iface;
|
||||
int rc, opt = 1;
|
||||
union mysockaddr addr;
|
||||
struct listener *l;
|
||||
int tftp_enabled = daemon->tftp_unlimited || daemon->tftp_interfaces;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(addr.in);
|
||||
#endif
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
l = create_listeners(&addr, tftp_enabled, 1);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int dad_count = 0;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
# ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
# endif
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
|
||||
if (l)
|
||||
l->next = create_listeners(&addr, tftp_enabled, 1);
|
||||
else
|
||||
l = create_listeners(&addr, tftp_enabled, 1);
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
new->tftpfd = -1;
|
||||
new->tcpfd = -1;
|
||||
new->fd = -1;
|
||||
listeners = new;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tcpfd) ||
|
||||
!fix_fd(new->fd))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
if ((rc = bind(new->fd, &iface->addr.sa, sa_len(&iface->addr))) != -1)
|
||||
break;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
||||
before failing. */
|
||||
if (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
||||
dad_count++ < DAD_WAIT)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -1 || bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
{
|
||||
prettyprint_addr(&iface->addr, daemon->namebuff);
|
||||
die(_("failed to bind listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
|
||||
if (listen(new->tcpfd, 5) == -1)
|
||||
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (iface->addr.sa.sa_family == AF_INET && iface->tftp_ok)
|
||||
{
|
||||
short save = iface->addr.in.sin_port;
|
||||
iface->addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((new->tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->tftpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tftpfd) ||
|
||||
bind(new->tftpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
die(_("failed to create TFTP socket: %s"), NULL, EC_BADNET);
|
||||
iface->addr.in.sin_port = save;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return listeners;
|
||||
daemon->listeners = l;
|
||||
}
|
||||
|
||||
void create_bound_listeners(int dienow)
|
||||
{
|
||||
struct listener *new;
|
||||
struct irec *iface;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (!iface->done && !iface->dad &&
|
||||
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int is_dad_listeners(void)
|
||||
{
|
||||
struct irec *iface;
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dad && !iface->done)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||
occupied port nos and reserved ones. */
|
||||
int random_sock(int family)
|
||||
@@ -700,7 +708,7 @@ void pre_allocate_sfds(void)
|
||||
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
!allocate_sfd(&srv->source_addr, srv->interface) &&
|
||||
errno != 0 &&
|
||||
(daemon->options & OPT_NOWILD))
|
||||
option_bool(OPT_NOWILD))
|
||||
{
|
||||
prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
if (srv->interface[0] != 0)
|
||||
@@ -721,7 +729,7 @@ void check_servers(void)
|
||||
int port = 0;
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces();
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
@@ -861,20 +869,38 @@ int reload_servers(char *fname)
|
||||
source_addr.in.sin_port = htons(daemon->query_port);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
|
||||
{
|
||||
else
|
||||
{
|
||||
int scope_index = 0;
|
||||
char *scope_id = strchr(token, '%');
|
||||
|
||||
if (scope_id)
|
||||
{
|
||||
*(scope_id++) = 0;
|
||||
scope_index = if_nametoindex(scope_id);
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
|
||||
{
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
|
||||
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
|
||||
#endif
|
||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||
source_addr.in6.sin6_addr = in6addr_any;
|
||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
||||
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
|
||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||
addr.in6.sin6_scope_id = scope_index;
|
||||
source_addr.in6.sin6_addr = in6addr_any;
|
||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
source_addr.in6.sin6_scope_id = 0;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
#else /* IPV6 */
|
||||
else
|
||||
continue;
|
||||
|
||||
#endif
|
||||
|
||||
if (old_servers)
|
||||
{
|
||||
serv = old_servers;
|
||||
@@ -921,7 +947,9 @@ struct in_addr get_ifaddr(char *intr)
|
||||
|
||||
ret.sin_addr.s_addr = -1;
|
||||
|
||||
for (l = daemon->listeners; l && l->family != AF_INET; l = l->next);
|
||||
for (l = daemon->listeners;
|
||||
l && (l->family != AF_INET || l->fd == -1);
|
||||
l = l->next);
|
||||
|
||||
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
760
src/option.c
760
src/option.c
File diff suppressed because it is too large
Load Diff
313
src/rfc1035.c
313
src/rfc1035.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
||||
static int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type,
|
||||
unsigned short class, char *format, ...);
|
||||
@@ -27,7 +27,7 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1)
|
||||
|
||||
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
||||
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||
@@ -217,7 +217,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
as CNAME targets according to RFC 2317 */
|
||||
char *cp;
|
||||
for (cp = cp1; *cp; cp++)
|
||||
if (!isdigit((int)*cp))
|
||||
if (!isdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
|
||||
addr[3] = addr[2];
|
||||
@@ -244,7 +244,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
if (*name == '\\' && *(name+1) == '[' &&
|
||||
(*(name+2) == 'x' || *(name+2) == 'X'))
|
||||
{
|
||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit((int) *cp1) && j < 32; cp1++, j++)
|
||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
|
||||
{
|
||||
char xdig[2];
|
||||
xdig[0] = *cp1;
|
||||
@@ -262,7 +262,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
{
|
||||
for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
|
||||
{
|
||||
if (*(cp1+1) || !isxdigit((int)*cp1))
|
||||
if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
|
||||
return 0;
|
||||
|
||||
for (j = sizeof(struct all_addr)-1; j>0; j--)
|
||||
@@ -278,7 +278,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
|
||||
static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
@@ -333,7 +333,7 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_questions(HEADER *header, size_t plen)
|
||||
static unsigned char *skip_questions(struct dns_header *header, size_t plen)
|
||||
{
|
||||
int q;
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
@@ -348,7 +348,7 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, size_t plen)
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
|
||||
{
|
||||
int i, rdlen;
|
||||
|
||||
@@ -371,7 +371,7 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
|
||||
than CRC the raw bytes, since replies might be compressed differently.
|
||||
We ignore case in the names for the same reason. Return all-ones
|
||||
if there is not question section. */
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned int crc = 0xffffffff;
|
||||
@@ -413,7 +413,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
||||
}
|
||||
|
||||
|
||||
size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
{
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
|
||||
@@ -437,7 +437,7 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||
also return length of pseudoheader in *len and pointer to the UDP size in *p
|
||||
@@ -453,7 +453,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
{
|
||||
*is_sign = 0;
|
||||
|
||||
if (header->opcode == QUERY)
|
||||
if (OPCODE(header) == QUERY)
|
||||
{
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
@@ -510,8 +510,122 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct macparm {
|
||||
unsigned char *limit;
|
||||
struct dns_header *header;
|
||||
size_t plen;
|
||||
union mysockaddr *l3;
|
||||
};
|
||||
|
||||
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct macparm *parm = parmv;
|
||||
int match = 0;
|
||||
unsigned short rdlen;
|
||||
struct dns_header *header = parm->header;
|
||||
unsigned char *lenp, *datap, *p;
|
||||
|
||||
if (family == parm->l3->sa.sa_family)
|
||||
{
|
||||
if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
match = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
match = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return 1; /* continue */
|
||||
|
||||
if (ntohs(header->arcount) == 0)
|
||||
{
|
||||
/* We are adding the pseudoheader */
|
||||
if (!(p = skip_questions(header, parm->plen)) ||
|
||||
!(p = skip_section(p,
|
||||
ntohs(header->ancount) + ntohs(header->nscount),
|
||||
header, parm->plen)))
|
||||
return 0;
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */
|
||||
PUTLONG(0, p); /* extended RCODE */
|
||||
lenp = p;
|
||||
PUTSHORT(0, p); /* RDLEN */
|
||||
rdlen = 0;
|
||||
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
|
||||
return 0; /* Too big */
|
||||
header->arcount = htons(1);
|
||||
datap = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, is_sign;
|
||||
unsigned short code, len;
|
||||
|
||||
if (ntohs(header->arcount) != 1 ||
|
||||
!(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||
|
||||
is_sign ||
|
||||
(!(p = skip_name(p, header, parm->plen, 10))))
|
||||
return 0;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
lenp = p;
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, parm->plen, rdlen))
|
||||
return 0; /* bad packet */
|
||||
datap = p;
|
||||
|
||||
/* check if option already there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
if (code == EDNS0_OPTION_MAC)
|
||||
return 0;
|
||||
p += len;
|
||||
}
|
||||
|
||||
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
|
||||
return 0; /* Too big */
|
||||
}
|
||||
|
||||
PUTSHORT(EDNS0_OPTION_MAC, p);
|
||||
PUTSHORT(maclen, p);
|
||||
memcpy(p, mac, maclen);
|
||||
p += maclen;
|
||||
|
||||
PUTSHORT(p - datap, lenp);
|
||||
parm->plen = p - (unsigned char *)header;
|
||||
|
||||
return 0; /* done */
|
||||
}
|
||||
|
||||
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
|
||||
{
|
||||
struct macparm parm;
|
||||
|
||||
/* Must have an existing pseudoheader as the only ar-record,
|
||||
or have no ar-records. Must also not be signed */
|
||||
|
||||
if (ntohs(header->arcount) > 1)
|
||||
return plen;
|
||||
|
||||
parm.header = header;
|
||||
parm.limit = (unsigned char *)limit;
|
||||
parm.plen = plen;
|
||||
parm.l3 = l3;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, &parm, filter_mac);
|
||||
|
||||
return parm.plen;
|
||||
}
|
||||
|
||||
|
||||
/* is addr in the non-globally-routed IP space? */
|
||||
static int private_net(struct in_addr addr, int ban_localhost)
|
||||
{
|
||||
@@ -525,14 +639,13 @@ static int private_net(struct in_addr addr, int ban_localhost)
|
||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
||||
}
|
||||
|
||||
static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, size_t qlen, char *name)
|
||||
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
|
||||
{
|
||||
int i, qtype, qclass, rdlen;
|
||||
unsigned long ttl;
|
||||
|
||||
for (i = count; i != 0; i--)
|
||||
{
|
||||
if (name && (daemon->options & OPT_LOG))
|
||||
if (name && option_bool(OPT_LOG))
|
||||
{
|
||||
if (!extract_name(header, qlen, &p, name, 1, 10))
|
||||
return 0;
|
||||
@@ -542,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
GETLONG(ttl, p);
|
||||
p += 4; /* ttl */
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if (qclass == C_IN && qtype == T_A)
|
||||
@@ -570,12 +683,12 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
addr.s_addr &= ~doctor->mask.s_addr;
|
||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||
header->aa = 0;
|
||||
header->hb3 &= ~HB3_AA;
|
||||
memcpy(p, &addr, INADDRSZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (qtype == T_TXT && name && (daemon->options & OPT_LOG))
|
||||
else if (qtype == T_TXT && name && option_bool(OPT_LOG))
|
||||
{
|
||||
unsigned char *p1 = p;
|
||||
if (!CHECK_LEN(header, p1, qlen, rdlen))
|
||||
@@ -592,7 +705,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
p2++;
|
||||
}
|
||||
*p2 = 0;
|
||||
my_syslog(LOG_DEBUG, "reply %s is %s", name, p1);
|
||||
my_syslog(LOG_INFO, "reply %s is %s", name, p1);
|
||||
/* restore */
|
||||
memmove(p1 + 1, p1, len);
|
||||
*p1 = len;
|
||||
@@ -607,7 +720,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
return p;
|
||||
}
|
||||
|
||||
static int find_soa(HEADER *header, size_t qlen, char *name)
|
||||
static int find_soa(struct dns_header *header, size_t qlen, char *name)
|
||||
{
|
||||
unsigned char *p;
|
||||
int qtype, qclass, rdlen;
|
||||
@@ -665,7 +778,8 @@ static int find_soa(HEADER *header, size_t qlen, char *name)
|
||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int is_sign, int check_rebind)
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
int is_sign, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -675,7 +789,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
cache_start_insert();
|
||||
|
||||
/* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
|
||||
if (daemon->doctors || (daemon->options & OPT_LOG))
|
||||
if (daemon->doctors || option_bool(OPT_LOG))
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name);
|
||||
@@ -688,7 +802,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
{
|
||||
int found = 0, cname_count = 5;
|
||||
struct crec *cpp = NULL;
|
||||
int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
unsigned long cttl = ULONG_MAX, attl;
|
||||
|
||||
namep = p;
|
||||
@@ -729,7 +843,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
GETLONG(attl, p1);
|
||||
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
||||
{
|
||||
(p1) -= NS_INT32SZ;
|
||||
(p1) -= 4;
|
||||
PUTLONG(daemon->max_ttl, p1);
|
||||
}
|
||||
GETSHORT(ardlen, p1);
|
||||
@@ -761,7 +875,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
if (!searched_soa)
|
||||
{
|
||||
@@ -809,7 +923,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
GETLONG(attl, p1);
|
||||
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
||||
{
|
||||
(p1) -= NS_INT32SZ;
|
||||
(p1) -= 4;
|
||||
PUTLONG(daemon->max_ttl, p1);
|
||||
}
|
||||
GETSHORT(ardlen, p1);
|
||||
@@ -848,7 +962,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
/* check for returned address in private space */
|
||||
if (check_rebind &&
|
||||
(flags & F_IPV4) &&
|
||||
private_net(addr.addr.addr4, !(daemon->options & OPT_LOCAL_REBIND)))
|
||||
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
|
||||
@@ -867,7 +981,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
if (!searched_soa)
|
||||
{
|
||||
@@ -889,18 +1003,19 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't put stuff from a truncated packet into the cache, but do everything else */
|
||||
if (!header->tc)
|
||||
/* Don't put stuff from a truncated packet into the cache,
|
||||
also don't cache replies where DNSSEC validation was turned off, either
|
||||
the upstream server told us so, or the original query specified it. */
|
||||
if (!(header->hb3 & HB3_TC) && !(header->hb4 & HB4_CD) && !checking_disabled)
|
||||
cache_end_insert();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the packet holds exactly one query
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name.
|
||||
Abuse F_BIGNAME to indicate an NS query - yuck. */
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name */
|
||||
|
||||
unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass;
|
||||
@@ -908,7 +1023,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
|
||||
if (typep)
|
||||
*typep = 0;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
|
||||
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
||||
return 0; /* must be exactly one query. */
|
||||
|
||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||
@@ -928,50 +1043,49 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
|
||||
return F_IPV6;
|
||||
if (qtype == T_ANY)
|
||||
return F_IPV4 | F_IPV6;
|
||||
if (qtype == T_NS || qtype == T_SOA)
|
||||
return F_QUERY | F_BIGNAME;
|
||||
}
|
||||
|
||||
return F_QUERY;
|
||||
}
|
||||
|
||||
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags, unsigned long ttl)
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
||||
{
|
||||
unsigned char *p = skip_questions(header, qlen);
|
||||
|
||||
header->qr = 1; /* response */
|
||||
header->aa = 0; /* authoritive */
|
||||
header->ra = 1; /* recursion if available */
|
||||
header->tc = 0; /* not truncated */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
/* set RA flag */
|
||||
header->hb4 |= HB4_RA;
|
||||
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
header->ancount = htons(0); /* no answers unless changed below */
|
||||
if (flags == F_NEG)
|
||||
header->rcode = SERVFAIL; /* couldn't get memory */
|
||||
SET_RCODE(header, SERVFAIL); /* couldn't get memory */
|
||||
else if (flags == F_NOERR)
|
||||
header->rcode = NOERROR; /* empty domain */
|
||||
SET_RCODE(header, NOERROR); /* empty domain */
|
||||
else if (flags == F_NXDOMAIN)
|
||||
header->rcode = NXDOMAIN;
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else if (p && flags == F_IPV4)
|
||||
{ /* we know the address */
|
||||
header->rcode = NOERROR;
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->aa = 1;
|
||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (p && flags == F_IPV6)
|
||||
{
|
||||
header->rcode = NOERROR;
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->aa = 1;
|
||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
}
|
||||
#endif
|
||||
else /* nowhere to forward to */
|
||||
header->rcode = REFUSED;
|
||||
SET_RCODE(header, REFUSED);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
@@ -984,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now)
|
||||
struct txt_record *txt;
|
||||
struct interface_name *intr;
|
||||
struct ptr_record *ptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
||||
struct naptr *naptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
return 1;
|
||||
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
for (naptr = daemon->naptr; naptr; naptr = naptr->next)
|
||||
if (hostname_isequal(name, naptr->name))
|
||||
return 1;
|
||||
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->name))
|
||||
return 1;
|
||||
|
||||
@@ -1011,7 +1130,7 @@ int check_for_local_domain(char *name, time_t now)
|
||||
/* Is the packet a reply with the answer address equal to addr?
|
||||
If so mung is into an NXDOMAIN reply and also put that information
|
||||
in the cache. */
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *baddr, time_t now)
|
||||
{
|
||||
unsigned char *p;
|
||||
@@ -1058,7 +1177,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
static int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -1168,7 +1287,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
|
||||
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
@@ -1192,11 +1311,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
|
||||
{
|
||||
unsigned short udpsz, ext_rcode, flags;
|
||||
unsigned short udpsz, flags;
|
||||
unsigned char *psave = pheader;
|
||||
|
||||
GETSHORT(udpsz, pheader);
|
||||
GETSHORT(ext_rcode, pheader);
|
||||
pheader += 2; /* ext_rcode */
|
||||
GETSHORT(flags, pheader);
|
||||
|
||||
sec_reqd = flags & 0x8000; /* do bit */
|
||||
@@ -1211,7 +1330,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
dryrun = 1;
|
||||
}
|
||||
|
||||
if (ntohs(header->qdcount) == 0 || header->opcode != QUERY )
|
||||
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
@@ -1249,7 +1368,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
@@ -1300,7 +1419,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<PTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1344,7 +1463,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
else if (is_arpa == F_IPV4 &&
|
||||
(daemon->options & OPT_BOGUSPRIV) &&
|
||||
option_bool(OPT_BOGUSPRIV) &&
|
||||
private_net(addr.addr.addr4, 1))
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
@@ -1380,7 +1499,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
for (cp = name, i = 0, a = 0; *cp; i++)
|
||||
{
|
||||
if (!isdigit(*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||
{
|
||||
i = 5;
|
||||
break;
|
||||
@@ -1442,7 +1561,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
/* See if a putative address is on the network from which we recieved
|
||||
the query, is so we'll filter other answers. */
|
||||
if (local_addr.s_addr != 0 && (daemon->options & OPT_LOCALISE) && flag == F_IPV4)
|
||||
if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
|
||||
{
|
||||
struct crec *save = crecp;
|
||||
do {
|
||||
@@ -1525,7 +1644,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
{
|
||||
@@ -1536,16 +1655,16 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||
if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", 1,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
@@ -1554,7 +1673,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (qtype == T_SRV || qtype == T_ANY)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
@@ -1562,7 +1682,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -1572,9 +1692,27 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
rec->offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlink first SRV record found */
|
||||
if (!move)
|
||||
{
|
||||
move = rec;
|
||||
*up = rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
|
||||
/* put first SRV record back at the end. */
|
||||
if (move)
|
||||
{
|
||||
*up = move;
|
||||
move->next = NULL;
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
@@ -1591,7 +1729,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
@@ -1603,7 +1741,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (qtype == T_MAILB)
|
||||
ans = 1, nxdomain = 1;
|
||||
|
||||
if (qtype == T_SOA && (daemon->options & OPT_FILTER))
|
||||
if (qtype == T_SOA && option_bool(OPT_FILTER))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
@@ -1650,14 +1788,23 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
/* done all questions, set up header and return length of result */
|
||||
header->qr = 1; /* response */
|
||||
header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
|
||||
header->ra = 1; /* recursion if available */
|
||||
header->tc = trunc; /* truncation */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
/* set RA flag */
|
||||
header->hb4 |= HB4_RA;
|
||||
|
||||
/* authoritive - only hosts and DHCP derived names. */
|
||||
if (auth)
|
||||
header->hb3 |= HB3_AA;
|
||||
|
||||
/* truncation */
|
||||
if (trunc)
|
||||
header->hb3 |= HB3_TC;
|
||||
|
||||
if (anscount == 0 && nxdomain)
|
||||
header->rcode = NXDOMAIN;
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else
|
||||
header->rcode = NOERROR; /* no error */
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(addncount);
|
||||
|
||||
496
src/rfc2131.c
496
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,69 +18,6 @@
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
#define BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
|
||||
/* The Linux in-kernel DHCP client silently ignores any packet
|
||||
smaller than this. Sigh........... */
|
||||
#define MIN_PACKETSZ 300
|
||||
|
||||
#define OPTION_PAD 0
|
||||
#define OPTION_NETMASK 1
|
||||
#define OPTION_ROUTER 3
|
||||
#define OPTION_DNSSERVER 6
|
||||
#define OPTION_HOSTNAME 12
|
||||
#define OPTION_DOMAINNAME 15
|
||||
#define OPTION_BROADCAST 28
|
||||
#define OPTION_VENDOR_CLASS_OPT 43
|
||||
#define OPTION_REQUESTED_IP 50
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_SERVER_IDENTIFIER 54
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_MESSAGE 56
|
||||
#define OPTION_MAXMESSAGE 57
|
||||
#define OPTION_T1 58
|
||||
#define OPTION_T2 59
|
||||
#define OPTION_VENDOR_ID 60
|
||||
#define OPTION_CLIENT_ID 61
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_ARCH 93
|
||||
#define OPTION_PXE_UUID 97
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
#define OPTION_VENDOR_IDENT 124
|
||||
#define OPTION_VENDOR_IDENT_OPT 125
|
||||
#define OPTION_END 255
|
||||
|
||||
#define SUBOPT_CIRCUIT_ID 1
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||
#define SUBOPT_PXE_DISCOVERY 6
|
||||
#define SUBOPT_PXE_SERVERS 8
|
||||
#define SUBOPT_PXE_MENU 9
|
||||
#define SUBOPT_PXE_MENU_PROMPT 10
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
#define DHCPREQUEST 3
|
||||
#define DHCPDECLINE 4
|
||||
#define DHCPACK 5
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||
|
||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
||||
@@ -89,6 +26,7 @@
|
||||
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
|
||||
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
|
||||
#endif
|
||||
|
||||
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
static int sanitise(unsigned char *opt, char *buf);
|
||||
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
|
||||
@@ -103,8 +41,8 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
int mac_len, char *interface, char *string, u32 xid);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
||||
unsigned char *agent_id, unsigned char *real_end);
|
||||
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
@@ -113,11 +51,12 @@ static void do_options(struct dhcp_context *context,
|
||||
char *hostname,
|
||||
char *domain, char *config_domain,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags,
|
||||
int null_term, int pxearch,
|
||||
unsigned char *uuid,
|
||||
int vendor_class_len);
|
||||
int vendor_class_len,
|
||||
time_t now);
|
||||
|
||||
|
||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||
@@ -129,7 +68,7 @@ struct dhcp_boot *find_boot(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)
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
|
||||
{
|
||||
unsigned char *opt, *clid = NULL;
|
||||
struct dhcp_lease *ltmp, *lease = NULL;
|
||||
@@ -147,7 +86,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
unsigned int time;
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_netid *netid, *tagif_netid;
|
||||
struct in_addr subnet_addr, fallback, override;
|
||||
struct in_addr subnet_addr, override;
|
||||
unsigned short fuzz = 0;
|
||||
unsigned int mess_type = 0;
|
||||
unsigned char fqdn_flags = 0;
|
||||
@@ -359,17 +298,43 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!context_new)
|
||||
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
||||
if (context_tmp->netmask.s_addr &&
|
||||
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
|
||||
is_same_net(addr, context_tmp->end, context_tmp->netmask))
|
||||
{
|
||||
context_tmp->current = context_new;
|
||||
context_new = context_tmp;
|
||||
}
|
||||
{
|
||||
struct in_addr netmask = context_tmp->netmask;
|
||||
|
||||
/* guess the netmask for relayed networks */
|
||||
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
|
||||
{
|
||||
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
|
||||
netmask.s_addr = htonl(0xff000000);
|
||||
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
|
||||
netmask.s_addr = htonl(0xffff0000);
|
||||
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
|
||||
netmask.s_addr = htonl(0xffffff00);
|
||||
}
|
||||
|
||||
/* This section fills in context mainly when a client which is on a remote (relayed)
|
||||
network renews a lease without using the relay, after dnsmasq has restarted. */
|
||||
if (netmask.s_addr != 0 &&
|
||||
is_same_net(addr, context_tmp->start, netmask) &&
|
||||
is_same_net(addr, context_tmp->end, netmask))
|
||||
{
|
||||
context_tmp->netmask = netmask;
|
||||
if (context_tmp->local.s_addr == 0)
|
||||
context_tmp->local = fallback;
|
||||
if (context_tmp->router.s_addr == 0)
|
||||
context_tmp->router = mess->giaddr;
|
||||
|
||||
/* fill in missing broadcast addresses for relayed ranges */
|
||||
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
|
||||
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
|
||||
|
||||
context_tmp->current = context_new;
|
||||
context_new = context_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (context_new || force)
|
||||
context = context_new;
|
||||
|
||||
context = context_new;
|
||||
}
|
||||
|
||||
if (!context)
|
||||
@@ -380,10 +345,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keep _a_ local address available. */
|
||||
fallback = context->local;
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
struct dhcp_context *context_tmp;
|
||||
for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
|
||||
@@ -503,9 +465,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
if (!message && !nailed)
|
||||
{
|
||||
@@ -518,7 +481,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!message &&
|
||||
!lease &&
|
||||
(!(lease = lease_allocate(mess->yiaddr))))
|
||||
(!(lease = lease_allocate4(mess->yiaddr))))
|
||||
message = _("no leases left");
|
||||
|
||||
if (!message)
|
||||
@@ -536,13 +499,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
domain, tagif_netid, subnet_addr, 0, 0, 0, NULL, 0);
|
||||
domain, netid, subnet_addr, 0, 0, 0, NULL, 0, now);
|
||||
}
|
||||
}
|
||||
|
||||
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
|
||||
|
||||
return message ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
||||
@@ -558,11 +521,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
pp = op;
|
||||
|
||||
/* Always force update, since the client has no way to do it itself. */
|
||||
if (!(fqdn_flags & 0x01))
|
||||
fqdn_flags |= 0x02;
|
||||
|
||||
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
|
||||
fqdn_flags |= 0x03;
|
||||
|
||||
fqdn_flags &= ~0x08;
|
||||
fqdn_flags |= 0x01;
|
||||
|
||||
if (fqdn_flags & 0x04)
|
||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||
@@ -603,7 +565,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
client_hostname = daemon->dhcp_buff;
|
||||
}
|
||||
|
||||
if (client_hostname && daemon->options & OPT_LOG_OPTS)
|
||||
if (client_hostname && option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
@@ -756,7 +718,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
@@ -857,7 +819,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
log_tags(tagif_netid, mess);
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
|
||||
@@ -865,40 +828,52 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
pxearch = option_uint(opt, 0, 2);
|
||||
|
||||
/* proxy DHCP here. */
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)) &&
|
||||
(context->flags & CONTEXT_PROXY))
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
|
||||
{
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
mess->ciaddr.s_addr = 0;
|
||||
mess->flags |= htons(0x8000); /* broadcast */
|
||||
}
|
||||
|
||||
clear_packet(mess, end);
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if ((tmp->flags & CONTEXT_PROXY) &&
|
||||
match_netid(tmp->filter, tagif_netid, 1))
|
||||
break;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
mess->ciaddr.s_addr = 0;
|
||||
mess->flags |= htons(0x8000); /* broadcast */
|
||||
}
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
clear_packet(mess, end);
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
{
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
else if (boot->tftp_sname)
|
||||
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
log_tags(tagif_netid, mess);
|
||||
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1028,15 +1003,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
||||
return 0;
|
||||
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||
@@ -1049,9 +1025,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
||||
}
|
||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
||||
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
case DHCPREQUEST:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
@@ -1082,12 +1058,30 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!context)
|
||||
{
|
||||
/* In auth mode, a REQUEST sent to the wrong server
|
||||
should be faulted, so that the client establishes
|
||||
communication with us, otherwise, silently ignore. */
|
||||
if (!(daemon->options & OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
message = _("wrong server-ID");
|
||||
/* Handle very strange configs where clients have more than one route to the server.
|
||||
If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
|
||||
Have to set override to make sure we echo back the correct server-id */
|
||||
struct irec *intr;
|
||||
|
||||
enumerate_interfaces();
|
||||
|
||||
for (intr = daemon->interfaces; intr; intr = intr->next)
|
||||
if (intr->addr.sa.sa_family == AF_INET &&
|
||||
intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
|
||||
intr->tftp_ok)
|
||||
break;
|
||||
|
||||
if (intr)
|
||||
override = intr->addr.in.sin_addr;
|
||||
else
|
||||
{
|
||||
/* In auth mode, a REQUEST sent to the wrong server
|
||||
should be faulted, so that the client establishes
|
||||
communication with us, otherwise, silently ignore. */
|
||||
if (!option_bool(OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
message = _("wrong server-ID");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1101,7 +1095,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
{
|
||||
/* INIT-REBOOT */
|
||||
if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
|
||||
if (!lease && !option_bool(OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
@@ -1116,8 +1110,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
as long as we can allocate the lease now - checked below.
|
||||
This makes for a smooth recovery from a lost lease DB */
|
||||
if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
|
||||
(!lease && !(daemon->options & OPT_AUTHORITATIVE)))
|
||||
(!lease && !option_bool(OPT_AUTHORITATIVE)))
|
||||
{
|
||||
/* A client rebinding will broadcast the request, so we may see it even
|
||||
if the lease is held by another server. Just ignore it in that case.
|
||||
If the request is unicast to us, then somethings wrong, NAK */
|
||||
if (!unicast_dest)
|
||||
return 0;
|
||||
message = _("lease not found");
|
||||
/* ensure we broadcast NAK */
|
||||
unicast_dest = 0;
|
||||
@@ -1190,7 +1189,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
else if (!lease)
|
||||
{
|
||||
if ((lease = lease_allocate(mess->yiaddr)))
|
||||
if ((lease = lease_allocate4(mess->yiaddr)))
|
||||
do_classes = 1;
|
||||
else
|
||||
message = _("no leases left");
|
||||
@@ -1221,9 +1220,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if( &context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (do_classes && daemon->lease_change_command)
|
||||
@@ -1235,6 +1235,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
lease->changed = 1;
|
||||
free(lease->extradata);
|
||||
lease->extradata = NULL;
|
||||
lease->extradata_size = lease->extradata_len = 0;
|
||||
|
||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
|
||||
@@ -1248,8 +1249,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
add_extradata_opt(lease, NULL);
|
||||
else
|
||||
for (n = tagif_netid; n; n = n->next)
|
||||
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
||||
|
||||
{
|
||||
struct dhcp_netid *n1;
|
||||
/* kill dupes */
|
||||
for (n1 = n->next; n1; n1 = n1->next)
|
||||
if (strcmp(n->net, n1->net) == 0)
|
||||
break;
|
||||
if (!n1)
|
||||
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
@@ -1325,10 +1334,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
||||
}
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
||||
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
}
|
||||
|
||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
case DHCPINFORM:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
@@ -1351,15 +1360,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
||||
domain = get_domain(mess->ciaddr);
|
||||
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||
|
||||
if (context && context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if( &context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||
|
||||
if (lease)
|
||||
{
|
||||
@@ -1384,10 +1394,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
||||
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
*is_inform = 1; /* handle reply differently */
|
||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1479,7 +1489,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
||||
{
|
||||
if (override.s_addr != 0)
|
||||
return override;
|
||||
else if (context)
|
||||
else if (context && context->local.s_addr != 0)
|
||||
return context->local;
|
||||
else
|
||||
return fallback;
|
||||
@@ -1568,7 +1578,7 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
|
||||
print_mac(daemon->namebuff, ext_mac, mac_len);
|
||||
|
||||
if(daemon->options & OPT_LOG_OPTS)
|
||||
if(option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
|
||||
ntohl(xid),
|
||||
type,
|
||||
@@ -1719,30 +1729,16 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
||||
unsigned char *agent_id, unsigned char *real_end)
|
||||
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
|
||||
{
|
||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||
unsigned char *overload;
|
||||
size_t ret;
|
||||
struct dhcp_netid_list *id_list;
|
||||
struct dhcp_netid *n;
|
||||
|
||||
/* move agent_id back down to the end of the packet */
|
||||
if (agent_id)
|
||||
{
|
||||
memmove(p, agent_id, real_end - agent_id);
|
||||
p += real_end - agent_id;
|
||||
memset(p, 0, real_end - p); /* in case of overlap */
|
||||
}
|
||||
|
||||
/* We do logging too */
|
||||
if (netid && (daemon->options & OPT_LOG_OPTS))
|
||||
if (netid && option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
char *s = daemon->namebuff;
|
||||
for (*s = 0; netid; netid = netid->next)
|
||||
{
|
||||
/* kill dupes. */
|
||||
struct dhcp_netid *n;
|
||||
|
||||
for (n = netid->next; n; n = n->next)
|
||||
if (strcmp(netid->net, n->net) == 0)
|
||||
break;
|
||||
@@ -1756,38 +1752,47 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
||||
}
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
|
||||
{
|
||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||
unsigned char *overload;
|
||||
size_t ret;
|
||||
|
||||
/* move agent_id back down to the end of the packet */
|
||||
if (agent_id)
|
||||
{
|
||||
memmove(p, agent_id, real_end - agent_id);
|
||||
p += real_end - agent_id;
|
||||
memset(p, 0, real_end - p); /* in case of overlap */
|
||||
}
|
||||
|
||||
/* add END options to the regions. */
|
||||
overload = find_overload(mess);
|
||||
|
||||
if (overload && (option_uint(overload, 0, 1) & 1))
|
||||
{
|
||||
*dhcp_skip_opts(mess->file) = OPTION_END;
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
log_options(mess->file, mess->xid);
|
||||
}
|
||||
else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
|
||||
else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
|
||||
|
||||
if (overload && (option_uint(overload, 0, 1) & 2))
|
||||
{
|
||||
*dhcp_skip_opts(mess->sname) = OPTION_END;
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
log_options(mess->sname, mess->xid);
|
||||
}
|
||||
else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
|
||||
else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
|
||||
|
||||
|
||||
*p++ = OPTION_END;
|
||||
|
||||
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
||||
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
|
||||
break;
|
||||
if (id_list)
|
||||
mess->flags |= htons(0x8000); /* force broadcast */
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (mess->siaddr.s_addr != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
|
||||
@@ -1936,20 +1941,14 @@ static int in_list(unsigned char *list, int opt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
||||
static struct dhcp_opt *option_find2(int opt)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
||||
if (match_netid(tmp->netid, netid, 0))
|
||||
return tmp;
|
||||
|
||||
/* No match, look for one without a netid */
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
||||
if (match_netid(tmp->netid, netid, 1))
|
||||
return tmp;
|
||||
|
||||
struct dhcp_opt *opts;
|
||||
|
||||
for (opts = daemon->dhcp_opts; opts; opts = opts->next)
|
||||
if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
|
||||
return opts;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2204,7 +2203,8 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char fqdn_flags,
|
||||
int null_term, int pxe_arch,
|
||||
unsigned char *uuid,
|
||||
int vendor_class_len)
|
||||
int vendor_class_len,
|
||||
time_t now)
|
||||
{
|
||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||
struct dhcp_boot *boot;
|
||||
@@ -2213,12 +2213,58 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char f0 = 0, s0 = 0;
|
||||
int done_file = 0, done_server = 0;
|
||||
int done_vendor_class = 0;
|
||||
struct dhcp_netid *tagif;
|
||||
struct dhcp_netid_list *id_list;
|
||||
|
||||
/* flag options which are valid with the current tag set (sans context tags) */
|
||||
tagif = run_tag_if(netid);
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
{
|
||||
opt->flags &= ~DHOPT_TAGOK;
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
|
||||
match_netid(opt->netid, tagif, 0))
|
||||
opt->flags |= DHOPT_TAGOK;
|
||||
}
|
||||
|
||||
/* now flag options which are valid, including the context tags,
|
||||
otherwise valid options are inhibited if we found a higher priotity one above */
|
||||
if (context && context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
tagif = run_tag_if(&context->netid);
|
||||
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
|
||||
match_netid(opt->netid, tagif, 0))
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = config_opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
if (!tmp)
|
||||
opt->flags |= DHOPT_TAGOK;
|
||||
}
|
||||
}
|
||||
|
||||
/* now flag untagged options which are not overridden by tagged ones */
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = config_opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
if (!tmp)
|
||||
opt->flags |= DHOPT_TAGOK;
|
||||
else if (!tmp->netid)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||
}
|
||||
|
||||
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
||||
|
||||
/* logging */
|
||||
if ((daemon->options & OPT_LOG_OPTS) && req_options)
|
||||
if (option_bool(OPT_LOG_OPTS) && req_options)
|
||||
{
|
||||
char *q = daemon->namebuff;
|
||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||
@@ -2238,6 +2284,12 @@ static void do_options(struct dhcp_context *context,
|
||||
}
|
||||
}
|
||||
|
||||
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
||||
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
|
||||
break;
|
||||
if (id_list)
|
||||
mess->flags |= htons(0x8000); /* force broadcast */
|
||||
|
||||
if (context)
|
||||
mess->siaddr = context->local;
|
||||
|
||||
@@ -2247,11 +2299,11 @@ static void do_options(struct dhcp_context *context,
|
||||
provide an manual option to disable it.
|
||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||
names, so we always send those. */
|
||||
if ((boot = find_boot(netid)))
|
||||
if ((boot = find_boot(tagif)))
|
||||
{
|
||||
if (boot->sname)
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
if (!option_bool(OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_SNAME))
|
||||
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
|
||||
@@ -2261,7 +2313,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (boot->file)
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
if (!option_bool(OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_FILENAME))
|
||||
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
|
||||
@@ -2269,8 +2321,10 @@ static void do_options(struct dhcp_context *context,
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
}
|
||||
|
||||
if (boot->next_server.s_addr)
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
else if (boot->tftp_sname)
|
||||
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||
}
|
||||
else
|
||||
/* Use the values of the relevant options if no dhcp-boot given and
|
||||
@@ -2279,20 +2333,20 @@ static void do_options(struct dhcp_context *context,
|
||||
dhcp-optsfile. */
|
||||
{
|
||||
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
||||
(opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
||||
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
||||
{
|
||||
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
||||
done_file = 1;
|
||||
}
|
||||
|
||||
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
||||
(opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
||||
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
||||
{
|
||||
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
||||
done_server = 1;
|
||||
}
|
||||
|
||||
if ((opt = option_find2(netid, config_opts, OPTION_END)))
|
||||
if ((opt = option_find2(OPTION_END)))
|
||||
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
|
||||
}
|
||||
|
||||
@@ -2300,7 +2354,7 @@ static void do_options(struct dhcp_context *context,
|
||||
fields look like they are in use, even when they aren't. This gets restored
|
||||
at the end of this function. */
|
||||
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
if (!req_options || option_bool(OPT_NO_OVERRIDE))
|
||||
{
|
||||
f0 = mess->file[0];
|
||||
mess->file[0] = 1;
|
||||
@@ -2320,36 +2374,36 @@ static void do_options(struct dhcp_context *context,
|
||||
/* replies to DHCPINFORM may not have a valid context */
|
||||
if (context)
|
||||
{
|
||||
if (!option_find2(netid, config_opts, OPTION_NETMASK))
|
||||
if (!option_find2(OPTION_NETMASK))
|
||||
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
||||
|
||||
/* May not have a "guessed" broadcast address if we got no packets via a relay
|
||||
from this net yet (ie just unicast renewals after a restart */
|
||||
if (context->broadcast.s_addr &&
|
||||
!option_find2(netid, config_opts, OPTION_BROADCAST))
|
||||
!option_find2(OPTION_BROADCAST))
|
||||
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
||||
|
||||
/* Same comments as broadcast apply, and also may not be able to get a sensible
|
||||
default when using subnet select. User must configure by steam in that case. */
|
||||
if (context->router.s_addr &&
|
||||
in_list(req_options, OPTION_ROUTER) &&
|
||||
!option_find2(netid, config_opts, OPTION_ROUTER))
|
||||
!option_find2(OPTION_ROUTER))
|
||||
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||
!option_find2(netid, config_opts, OPTION_DNSSERVER))
|
||||
!option_find2(OPTION_DNSSERVER))
|
||||
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
||||
}
|
||||
|
||||
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
|
||||
!option_find2(OPTION_DOMAINNAME))
|
||||
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
|
||||
|
||||
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
||||
if (hostname)
|
||||
{
|
||||
if (in_list(req_options, OPTION_HOSTNAME) &&
|
||||
!option_find2(netid, config_opts, OPTION_HOSTNAME))
|
||||
!option_find2(OPTION_HOSTNAME))
|
||||
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
|
||||
|
||||
if (fqdn_flags != 0)
|
||||
@@ -2398,6 +2452,10 @@ static void do_options(struct dhcp_context *context,
|
||||
{
|
||||
int optno = opt->opt;
|
||||
|
||||
/* netids match and not encapsulated? */
|
||||
if (!(opt->flags & DHOPT_TAGOK))
|
||||
continue;
|
||||
|
||||
/* was it asked for, or are we sending it anyway? */
|
||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
||||
continue;
|
||||
@@ -2416,10 +2474,6 @@ static void do_options(struct dhcp_context *context,
|
||||
if (optno == OPTION_FILENAME && done_file)
|
||||
continue;
|
||||
|
||||
/* netids match and not encapsulated? */
|
||||
if (opt != option_find2(netid, config_opts, optno))
|
||||
continue;
|
||||
|
||||
/* For the options we have default values on
|
||||
dhc-option=<optionno> means "don't include this option"
|
||||
not "include a zero-length option" */
|
||||
@@ -2486,7 +2540,7 @@ static void do_options(struct dhcp_context *context,
|
||||
continue;
|
||||
|
||||
o->flags |= DHOPT_ENCAP_DONE;
|
||||
if (match_netid(o->netid, netid, 1) &&
|
||||
if (match_netid(o->netid, tagif, 1) &&
|
||||
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
|
||||
{
|
||||
o->flags |= DHOPT_ENCAP_MATCH;
|
||||
@@ -2520,12 +2574,12 @@ static void do_options(struct dhcp_context *context,
|
||||
}
|
||||
}
|
||||
|
||||
force_encap = prune_vendor_opts(netid);
|
||||
force_encap = prune_vendor_opts(tagif);
|
||||
|
||||
if (context && pxe_arch != -1)
|
||||
{
|
||||
pxe_misc(mess, end, uuid);
|
||||
config_opts = pxe_opts(pxe_arch, netid, context->local);
|
||||
config_opts = pxe_opts(pxe_arch, tagif, context->local);
|
||||
}
|
||||
|
||||
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
||||
@@ -2537,7 +2591,7 @@ static void do_options(struct dhcp_context *context,
|
||||
memcpy(p, daemon->dhcp_buff3, vendor_class_len);
|
||||
|
||||
/* restore BOOTP anti-overload hack */
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
if (!req_options || option_bool(OPT_NO_OVERRIDE))
|
||||
{
|
||||
mess->file[0] = f0;
|
||||
mess->sname[0] = s0;
|
||||
|
||||
298
src/rfc3315.c
Normal file
298
src/rfc3315.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
static size_t outpacket_counter;
|
||||
|
||||
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
|
||||
size_t maclen, void *parm);
|
||||
|
||||
void make_duid(time_t now)
|
||||
{
|
||||
iface_enumerate(AF_LOCAL, &now, make_duid1);
|
||||
|
||||
if (!daemon->duid)
|
||||
die("Cannot create DHCPv6 server DUID", NULL, EC_MISC);
|
||||
}
|
||||
|
||||
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
|
||||
size_t maclen, void *parm)
|
||||
{
|
||||
/* create DUID as specified in RFC3315. We use the MAC of the
|
||||
first interface we find that isn't loopback or P-to-P */
|
||||
|
||||
unsigned char *p;
|
||||
|
||||
if (flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
|
||||
return 1;
|
||||
|
||||
daemon->duid = p = safe_malloc(maclen + 8);
|
||||
daemon->duid_len = maclen + 8;
|
||||
PUTSHORT(1, p); /* DUID_LLT */
|
||||
PUTSHORT(type, p); /* address type */
|
||||
PUTLONG(*((time_t *)parm), p); /* time */
|
||||
memcpy(p, mac, maclen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
|
||||
{
|
||||
u16 opt, opt_len;
|
||||
void *start;
|
||||
|
||||
if (!opts)
|
||||
return NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (end - opts < 4)
|
||||
return NULL;
|
||||
|
||||
start = opts;
|
||||
GETSHORT(opt, opts);
|
||||
GETSHORT(opt_len, opts);
|
||||
|
||||
if (opt_len > (end - opts))
|
||||
return NULL;
|
||||
|
||||
if (opt == search && (opt_len >= minsize))
|
||||
return start;
|
||||
|
||||
opts += opt_len;
|
||||
}
|
||||
}
|
||||
|
||||
void *opt6_next(void *opts, void *end)
|
||||
{
|
||||
u16 opt_len;
|
||||
|
||||
if (end - opts < 4)
|
||||
return NULL;
|
||||
|
||||
opts += 2;
|
||||
GETSHORT(opt_len, opts);
|
||||
|
||||
if (opt_len >= (end - opts))
|
||||
return NULL;
|
||||
|
||||
return opts + opt_len;
|
||||
}
|
||||
|
||||
|
||||
#define opt6_len(opt) ((int)(((unsigned short *)(opt))[1]))
|
||||
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4u+(unsigned int)(i)]))
|
||||
|
||||
|
||||
static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
|
||||
{
|
||||
/* this worries about unaligned data and byte order */
|
||||
unsigned int ret = 0;
|
||||
int i;
|
||||
unsigned char *p = opt6_ptr(opt, offset);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
ret = (ret << 8) | *p++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
daemon->outpacket_counter = 4; message type and ID
|
||||
|
||||
elapsed time:
|
||||
int o = new_opt(OPTION_ELAPSED_TIME);
|
||||
put_opt_short(o, 100)
|
||||
finalise_opt(o);
|
||||
|
||||
IA_NA
|
||||
|
||||
int o = new_opt(OPTION_IA_NA);
|
||||
put_opt_long(o, IAID);
|
||||
put_opt_long(o, T1);
|
||||
put_opt_long(0, T2);
|
||||
int o1 = new_opt(OPTION_IAADDR);
|
||||
put_opt(o1, &addr, sizeof(addr));
|
||||
put_opt_long(o1, preferred_lifetime);
|
||||
put_opt_long(o1, valid_lifetime);
|
||||
finalise_opt(o1);
|
||||
finalise_opt(o);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void end_opt6(int container)
|
||||
{
|
||||
void *p = daemon->outpacket.iov_base + container + 2;
|
||||
u16 len = outpacket_counter - container - 4 ;
|
||||
|
||||
PUTSHORT(len, p);
|
||||
}
|
||||
|
||||
static void *expand(size_t headroom)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
|
||||
{
|
||||
ret = daemon->outpacket.iov_base + outpacket_counter;
|
||||
outpacket_counter += headroom;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int new_opt6(int opt)
|
||||
{
|
||||
int ret = outpacket_counter;
|
||||
void *p;
|
||||
|
||||
if ((p = expand(4)))
|
||||
{
|
||||
PUTSHORT(opt, p);
|
||||
PUTSHORT(0, p);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void *put_opt6(void *data, size_t len)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (data && (p = expand(len)))
|
||||
memcpy(p, data, len);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void put_opt6_long(unsigned int val)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (( p = expand(4)))
|
||||
PUTLONG(p, val);
|
||||
}
|
||||
|
||||
void put_opt6_short(unsigned int val)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = expand(2)))
|
||||
PUTSHORT(val, p);
|
||||
}
|
||||
|
||||
void put_opt6_byte(unsigned int val)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = expand(1)))
|
||||
*((unsigned char *)p) = val;
|
||||
}
|
||||
|
||||
size_t dhcp6_reply(struct dhcp_context *context, size_t sz)
|
||||
{
|
||||
void *packet_options = ((void *)daemon->dhcp_packet.iov_base) + 4;
|
||||
void *end = ((void *)daemon->dhcp_packet.iov_base) + sz;
|
||||
void *na_option, *na_end;
|
||||
void *opt, *p;
|
||||
int o;
|
||||
|
||||
outpacket_counter = 4; /* skip message type and transaction-id */
|
||||
|
||||
if (!(opt = opt6_find(packet_options, end, OPTION6_CLIENT_ID, 1)))
|
||||
return;
|
||||
|
||||
o = new_opt6(OPTION6_CLIENT_ID);
|
||||
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||
end_opt6(o);
|
||||
|
||||
o = new_opt6(OPTION6_SERVER_ID);
|
||||
put_opt6(daemon->duid, daemon->duid_len);
|
||||
end_opt6(o);
|
||||
|
||||
if ((opt = opt6_find(packet_options, end, OPTION6_IA_NA, 12)))
|
||||
{
|
||||
while (opt = opt6_find(opt, end, OPTION6_IA_NA, 12))
|
||||
{
|
||||
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||
void *ia_option = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_IAADDR, 24);
|
||||
|
||||
unsigned int iaid = opt6_uint(opt, 0, 4);
|
||||
unsigned int t1 = opt6_uint(opt, 4, 4);
|
||||
unsigned int t2 = opt6_uint(opt, 8, 4);
|
||||
|
||||
|
||||
if (ia_option)
|
||||
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
/* do address option */
|
||||
|
||||
ia_option = opt6_next(ia_option, ia_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no preferred address call address allocate */
|
||||
|
||||
}
|
||||
|
||||
opt = opt6_next(opt, end);
|
||||
}
|
||||
}
|
||||
else if ((opt = opt6_find(packet_options, end, OPTION6_IA_TA, 4)))
|
||||
while (opt = opt6_find(opt, end, OPTION6_IA_TA, 4))
|
||||
{
|
||||
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||
void *ia_option = opt6_find(opt6_ptr(opt, 4), ia_end, OPTION6_IAADDR, 24);
|
||||
|
||||
unsigned int iaid = opt6_uint(opt, 0, 4);
|
||||
|
||||
if (ia_option)
|
||||
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
/* do address option */
|
||||
|
||||
ia_option = opt6_next(ia_option, ia_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no preferred address */
|
||||
|
||||
}
|
||||
|
||||
opt = opt6_next(opt, end);
|
||||
}
|
||||
else
|
||||
return; /* no IA_NA and no IA_TA */
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
202
src/tftp.c
202
src/tftp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -43,7 +43,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
ssize_t len;
|
||||
char *packet = daemon->packet;
|
||||
char *filename, *mode, *p, *end, *opt;
|
||||
struct sockaddr_in addr, peer;
|
||||
union mysockaddr addr, peer;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
struct ifreq ifr;
|
||||
@@ -64,6 +64,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#ifdef HAVE_IPV6
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
@@ -90,9 +93,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
addr = listen->iface->addr.in;
|
||||
addr = listen->iface->addr;
|
||||
mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
}
|
||||
@@ -102,59 +105,88 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int check;
|
||||
struct interface_list *ir;
|
||||
|
||||
addr.sin_addr.s_addr = 0;
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
addr.sa.sa_family = listen->family;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
addr.in.sin_addr = p.p->ipi_spec_dst;
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
struct in_addr *a;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
addr.sin_addr = p.p->ipi_spec_dst;
|
||||
if_index = p.p->ipi_ifindex;
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.in.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = *(p.i);
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = *(p.i);
|
||||
}
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = p.s->sdl_index;
|
||||
}
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.in.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = p.s->sdl_index;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in6_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
addr.in6.sin6_addr = p.p->ipi6_addr;
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!indextoname(listen->tftpfd, if_index, namebuff) ||
|
||||
addr.sin_addr.s_addr == 0)
|
||||
if (!indextoname(listen->tftpfd, if_index, namebuff))
|
||||
return;
|
||||
|
||||
name = namebuff;
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name);
|
||||
else
|
||||
#endif
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name);
|
||||
|
||||
/* wierd TFTP service override */
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
@@ -189,16 +221,29 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (strcmp(ir->interface, name) == 0)
|
||||
special = 1;
|
||||
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_family = AF_INET;
|
||||
if (listen->family == AF_INET)
|
||||
{
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.in.sin_len = sizeof(addr.in);
|
||||
#endif
|
||||
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
addr.in6.sin6_port = htons(port);
|
||||
addr.in6.sin6_flowinfo = 0;
|
||||
addr.in6.sin6_scope_id = 0;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
|
||||
return;
|
||||
|
||||
if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
free(transfer);
|
||||
return;
|
||||
@@ -213,13 +258,15 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->file = NULL;
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (1)
|
||||
{
|
||||
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
|
||||
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||
setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||
#endif
|
||||
!fix_fd(transfer->sockfd))
|
||||
{
|
||||
@@ -227,7 +274,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
addr.sin_port = htons(port);
|
||||
if (listen->family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
|
||||
@@ -245,7 +297,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
!(filename = next(&p, end)) ||
|
||||
!(mode = next(&p, end)) ||
|
||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
|
||||
else
|
||||
{
|
||||
if (strcasecmp(mode, "netascii") == 0)
|
||||
@@ -256,7 +308,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (strcasecmp(opt, "blksize") == 0)
|
||||
{
|
||||
if ((opt = next(&p, end)) &&
|
||||
(special || !(daemon->options & OPT_TFTP_NOBLOCK)))
|
||||
(special || !option_bool(OPT_TFTP_NOBLOCK)))
|
||||
{
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
@@ -290,12 +342,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (prefix[strlen(prefix)-1] != '/')
|
||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
if (!special && (daemon->options & OPT_TFTP_APREF))
|
||||
if (!special && option_bool(OPT_TFTP_APREF))
|
||||
{
|
||||
size_t oldlen = strlen(daemon->namebuff);
|
||||
struct stat statbuf;
|
||||
|
||||
strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
/* remove unique-directory if it doesn't exist */
|
||||
@@ -333,7 +385,6 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
free_transfer(transfer);
|
||||
else
|
||||
{
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
|
||||
transfer->next = daemon->tftp_trans;
|
||||
daemon->tftp_trans = transfer;
|
||||
}
|
||||
@@ -376,7 +427,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int spe
|
||||
goto perm;
|
||||
}
|
||||
/* in secure mode, must be owned by user running dnsmasq */
|
||||
else if (!special && (daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
else if (!special && option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
goto perm;
|
||||
|
||||
/* If we're doing many tranfers from the same file, only
|
||||
@@ -440,6 +491,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
|
||||
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
||||
{
|
||||
@@ -456,20 +509,22 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
char *p = daemon->packet + sizeof(struct ack);
|
||||
char *end = daemon->packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
/* Sanitise error message */
|
||||
if (!err)
|
||||
err = "";
|
||||
else
|
||||
{
|
||||
char *q, *r;
|
||||
for (q = r = err; *r; r++)
|
||||
if (isprint((int)*r))
|
||||
unsigned char *q, *r;
|
||||
for (q = r = (unsigned char *)err; *r; r++)
|
||||
if (isprint(*r))
|
||||
*(q++) = *r;
|
||||
*q = 0;
|
||||
}
|
||||
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
||||
(int)ntohs(mess->block), err,
|
||||
inet_ntoa(transfer->peer.sin_addr));
|
||||
daemon->addrbuff);
|
||||
|
||||
/* Got err, ensure we take abort */
|
||||
transfer->timeout = now;
|
||||
@@ -498,9 +553,12 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
if (len != 0)
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
|
||||
len = 0;
|
||||
{
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||
transfer->file->filename, daemon->addrbuff);
|
||||
len = 0;
|
||||
endcon = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
@@ -509,6 +567,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
|
||||
if (endcon || len == 0)
|
||||
{
|
||||
if (!endcon)
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
free_transfer(transfer);
|
||||
@@ -517,7 +577,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
}
|
||||
|
||||
up = &transfer->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_transfer(struct tftp_transfer *transfer)
|
||||
@@ -628,15 +688,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
for (i = 0, newcarrylf = 0; i < size; i++)
|
||||
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
||||
{
|
||||
if (size == transfer->blocksize)
|
||||
{
|
||||
transfer->expansion++;
|
||||
if (i == size - 1)
|
||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||
}
|
||||
else
|
||||
transfer->expansion++;
|
||||
|
||||
if (size != transfer->blocksize)
|
||||
size++; /* room in this block */
|
||||
|
||||
else if (i == size - 1)
|
||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||
|
||||
/* make space and insert CR */
|
||||
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
||||
mess->data[i] = '\r';
|
||||
|
||||
61
src/util.c
61
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||
#include <idna.h>
|
||||
#endif
|
||||
|
||||
@@ -43,11 +43,9 @@ unsigned short rand16(void)
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
typedef unsigned int uint32;
|
||||
|
||||
static uint32 seed[32];
|
||||
static uint32 in[12];
|
||||
static uint32 out[8];
|
||||
static u32 seed[32];
|
||||
static u32 in[12];
|
||||
static u32 out[8];
|
||||
|
||||
void rand_init()
|
||||
{
|
||||
@@ -66,7 +64,7 @@ void rand_init()
|
||||
|
||||
static void surf(void)
|
||||
{
|
||||
uint32 t[12]; uint32 x; uint32 sum = 0;
|
||||
u32 t[12]; u32 x; u32 sum = 0;
|
||||
int r; int i; int loop;
|
||||
|
||||
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
|
||||
@@ -120,11 +118,11 @@ static int check_name(char *in)
|
||||
dotgap = 0;
|
||||
else if (++dotgap > MAXLABEL)
|
||||
return 0;
|
||||
else if (isascii(c) && iscntrl(c))
|
||||
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
#ifndef LOCALEDIR
|
||||
else if (!isascii(c))
|
||||
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||
else if (!isascii((unsigned char)c))
|
||||
return 0;
|
||||
#endif
|
||||
else if (c != ' ')
|
||||
@@ -170,7 +168,7 @@ int legal_hostname(char *name)
|
||||
char *canonicalise(char *in, int *nomem)
|
||||
{
|
||||
char *ret = NULL;
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||
int rc;
|
||||
#endif
|
||||
|
||||
@@ -180,7 +178,7 @@ char *canonicalise(char *in, int *nomem)
|
||||
if (!check_name(in))
|
||||
return NULL;
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
|
||||
{
|
||||
if (ret)
|
||||
@@ -322,6 +320,25 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||
{
|
||||
int pfbytes = prefixlen >> 3;
|
||||
int pfbits = prefixlen & 7;
|
||||
|
||||
if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
|
||||
return 0;
|
||||
|
||||
if (pfbits == 0 ||
|
||||
(a->s6_addr[pfbytes] >> (8 - pfbits) != b->s6_addr[pfbytes] >> (8 - pfbits)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* returns port number from address */
|
||||
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||
{
|
||||
@@ -335,7 +352,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||
}
|
||||
else if (addr->sa.sa_family == AF_INET6)
|
||||
{
|
||||
char name[IF_NAMESIZE];
|
||||
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
|
||||
if (addr->in6.sin6_scope_id != 0 &&
|
||||
if_indextoname(addr->in6.sin6_scope_id, name) &&
|
||||
strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
|
||||
{
|
||||
strcat(buf, "%");
|
||||
strcat(buf, name);
|
||||
}
|
||||
port = ntohs(addr->in6.sin6_port);
|
||||
}
|
||||
#else
|
||||
@@ -365,7 +390,8 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
}
|
||||
|
||||
|
||||
/* in may equal out, when maxlen may be -1 (No max len). */
|
||||
/* in may equal out, when maxlen may be -1 (No max len).
|
||||
Return -1 for extraneous no-hex chars found. */
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type)
|
||||
{
|
||||
@@ -377,7 +403,10 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
|
||||
while (maxlen == -1 || i < maxlen)
|
||||
{
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
|
||||
if (*r != '*' && !isxdigit((unsigned char)*r))
|
||||
return -1;
|
||||
|
||||
if (*r == 0)
|
||||
maxlen = i;
|
||||
|
||||
@@ -473,7 +502,7 @@ void bump_maxfd(int fd, int *max)
|
||||
int retry_send(void)
|
||||
{
|
||||
struct timespec waiter;
|
||||
if (errno == EAGAIN)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
{
|
||||
waiter.tv_sec = 0;
|
||||
waiter.tv_nsec = 10000;
|
||||
|
||||
Reference in New Issue
Block a user