Compare commits
35 Commits
v2.87test2
...
v2.87test5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
553c4c99cc | ||
|
|
4165c1331b | ||
|
|
b2690415bf | ||
|
|
011f8cf1d0 | ||
|
|
2748fb81e2 | ||
|
|
46312909d9 | ||
|
|
41adecad14 | ||
|
|
ea5d8c56a0 | ||
|
|
d242cbffa4 | ||
|
|
1c8855ed10 | ||
|
|
ea33a01303 | ||
|
|
18b1d1424e | ||
|
|
1176cd58c9 | ||
|
|
44a4643b62 | ||
|
|
ed96efd865 | ||
|
|
e3093b532c | ||
|
|
9560658c5b | ||
|
|
37a70d39e0 | ||
|
|
72fac0810c | ||
|
|
c166c07a93 | ||
|
|
39a625ff72 | ||
|
|
ad32ca18a7 | ||
|
|
efea282396 | ||
|
|
33d6a01cd3 | ||
|
|
d290630d31 | ||
|
|
d2ad5dc073 | ||
|
|
68ab5127af | ||
|
|
089a11f340 | ||
|
|
de1d04eb66 | ||
|
|
ed4e7defd7 | ||
|
|
267ab619c4 | ||
|
|
0140454ba2 | ||
|
|
2c60441239 | ||
|
|
cbbd56c965 | ||
|
|
2561f9fe0e |
23
CHANGELOG
23
CHANGELOG
@@ -8,6 +8,29 @@ version 2.87
|
||||
Add --nftset option, like --ipset but for the newer nftables.
|
||||
Thanks to Chen Zhenge for the patch.
|
||||
|
||||
Add --filter-A and --filter-AAAA options, to remove IPv4 or IPv6
|
||||
addresses from DNS answers.
|
||||
|
||||
Fix crash doing netbooting when --port is set to zero
|
||||
to disable the DNS server. Thanks to Drexl Johannes
|
||||
for the bug report.
|
||||
|
||||
Generalise --dhcp-relay. Sending via broadcast/multicast is
|
||||
now supported for both IPv4 and IPv6 and the configuration
|
||||
syntax made easier (but backwards compatible).
|
||||
|
||||
Add snooping of IPv6 prefix-delegations to the DHCP-relay system.
|
||||
|
||||
Finesse parsing of --dhcp-remoteid and --dhcp-subscrid. To be treated
|
||||
as hex, the pattern must consist of only hex digits AND contain
|
||||
at least one ':'. Thanks to Bengt-Erik Sandstrom who tripped
|
||||
over a pattern consisting of a decimal number which was interpreted
|
||||
surprisingly.
|
||||
|
||||
Include client address in TFTP file-not-found error reports.
|
||||
Thanks to Stefan Rink for the initial patch, which has been
|
||||
re-worked by me (srk). All bugs mine.
|
||||
|
||||
|
||||
version 2.86
|
||||
Handle DHCPREBIND requests in the DHCPv6 server code.
|
||||
|
||||
9
Makefile
9
Makefile
@@ -70,8 +70,9 @@ nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CO
|
||||
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --cflags libnftables`
|
||||
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
||||
@@ -91,7 +92,7 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
all : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
|
||||
@@ -116,7 +117,7 @@ all-i18n : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
for f in `cd $(PO); echo *.po`; do \
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
This packaging is now unmaintained in the dnsmasq source: dnsmasq is
|
||||
included in Suse proper, and up-to-date packages are now available
|
||||
from
|
||||
|
||||
ftp://ftp.suse.com/pub/people/ug/
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
|
||||
It fixes the dependency from the dns daemon name 'named'
|
||||
After appending the patch, the SuSEfirewall is again able to autodetect
|
||||
the dnsmasq named service.
|
||||
This is a very old bug in the SuSEfirewall script.
|
||||
The SuSE people think the name of the dns server will always 'named'
|
||||
|
||||
|
||||
--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100
|
||||
+++ /sbin/SuSEfirewall2 2004-01-23 13:31:56.000000000 +0100
|
||||
@@ -764,7 +764,7 @@
|
||||
echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'
|
||||
|
||||
test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
|
||||
- test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
|
||||
+ test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv dnsmasq && {
|
||||
echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
|
||||
You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
|
||||
FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
|
||||
@@ -878,7 +878,7 @@
|
||||
test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
|
||||
# Get ports/IP bindings of NAMED/SQUID
|
||||
test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
|
||||
- $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
|
||||
+ $AWK -F: '/^dnsmasq .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
|
||||
test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
|
||||
$AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`
|
||||
@@ -1,23 +0,0 @@
|
||||
--- man/dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
|
||||
+++ man/dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -69,7 +69,7 @@
|
||||
.TP
|
||||
.B \-g, --group=<groupname>
|
||||
Specify the group which dnsmasq will run
|
||||
-as. The defaults to "dip", if available, to facilitate access to
|
||||
+as. The defaults to "dialout", if available, to facilitate access to
|
||||
/etc/ppp/resolv.conf which is not normally world readable.
|
||||
.TP
|
||||
.B \-v, --version
|
||||
--- src/config.h 2004-08-11 11:39:18.000000000 +0200
|
||||
+++ src/config.h 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
-#define CHGRP "dip"
|
||||
+#define CHGRP "dialout"
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
###############################################################################
|
||||
#
|
||||
# General
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.33
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
Vendor: Simon Kelley
|
||||
Packager: Simon Kelley
|
||||
URL: http://www.thekelleys.org.uk/dnsmasq
|
||||
Provides: dns_daemon
|
||||
Conflicts: bind bind8 bind9
|
||||
PreReq: %fillup_prereq %insserv_prereq
|
||||
Autoreqprov: on
|
||||
Source0: %{name}-%{version}.tar.bz2
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
Summary: A lightweight caching nameserver
|
||||
|
||||
%description
|
||||
Dnsmasq is 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 for network booting of diskless machines.
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Build
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
patch -p0 <rpm/%{name}-SuSE.patch
|
||||
|
||||
%build
|
||||
%{?suse_update_config:%{suse_update_config -f}}
|
||||
make all-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Install
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}/etc/init.d
|
||||
make install-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
|
||||
install -o root -g root -m 755 rpm/rc.dnsmasq-suse $RPM_BUILD_ROOT/etc/init.d/dnsmasq
|
||||
install -o root -g root -m 644 dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
|
||||
strip $RPM_BUILD_ROOT/usr/sbin/dnsmasq
|
||||
ln -sf ../../etc/init.d/dnsmasq $RPM_BUILD_ROOT/usr/sbin/rcdnsmasq
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Post-install scriptlet
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%post
|
||||
%{fillup_and_insserv dnsmasq}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Post-uninstall scriptlet
|
||||
#
|
||||
# The %postun script executes after the package has been removed. It is the
|
||||
# last chance for a package to clean up after itself.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%postun
|
||||
%{insserv_cleanup}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# File list
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
|
||||
%doc contrib
|
||||
%config /etc/init.d/dnsmasq
|
||||
%config /etc/dnsmasq.conf
|
||||
/usr/sbin/rcdnsmasq
|
||||
/usr/sbin/dnsmasq
|
||||
/usr/share/locale/*/LC_MESSAGES/*
|
||||
%doc %{_mandir}/man8/dnsmasq.8.gz
|
||||
%doc %{_mandir}/*/man8/dnsmasq.8.gz
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# init.d/dnsmasq
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: dnsmasq
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop:
|
||||
# Default-Start: 3 5
|
||||
# Default-Stop:
|
||||
# Description: Starts internet name service masq caching server (DNS)
|
||||
### END INIT INFO
|
||||
|
||||
NAMED_BIN=/usr/sbin/dnsmasq
|
||||
NAMED_PID=/var/run/dnsmasq.pid
|
||||
NAMED_CONF=/etc/dnsmasq.conf
|
||||
|
||||
if [ ! -x $NAMED_BIN ] ; then
|
||||
echo -n "dnsmasq not installed ! "
|
||||
exit 5
|
||||
fi
|
||||
|
||||
. /etc/rc.status
|
||||
rc_reset
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo -n "- Warning: dnsmasq already running ! "
|
||||
else
|
||||
[ -e $NAMED_PID ] && echo -n "- Warning: $NAMED_PID exists ! "
|
||||
fi
|
||||
startproc -p $NAMED_PID $NAMED_BIN -u nobody
|
||||
rc_status -v
|
||||
;;
|
||||
stop)
|
||||
echo -n "Shutting name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
|
||||
killproc -p $NAMED_PID -TERM $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
try-restart)
|
||||
$0 stop && $0 start
|
||||
rc_status
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
rc_status
|
||||
;;
|
||||
force-reload)
|
||||
$0 reload
|
||||
rc_status
|
||||
;;
|
||||
reload)
|
||||
echo -n "Reloading name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
|
||||
killproc -p $NAMED_PID -HUP $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
probe)
|
||||
test $NAMED_CONF -nt $NAMED_PID && echo reload
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
rc_exit
|
||||
|
||||
2
debian/changelog
vendored
2
debian/changelog
vendored
@@ -1,6 +1,8 @@
|
||||
dnsmasq (2.87-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Include new NFTset support in the build.
|
||||
* Fix crash on netboot with DNS server disabled. (closes: #996332)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 08 Sep 2021 23:11:25 +0000
|
||||
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@@ -5,7 +5,7 @@ Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
|
||||
pkg-config
|
||||
pkg-config, libnftables-dev
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git
|
||||
|
||||
1
debian/readme
vendored
1
debian/readme
vendored
@@ -60,6 +60,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
nodbus : omit DBus support.
|
||||
noconntrack : omit connection tracking support.
|
||||
noipset : omit IPset support.
|
||||
nonftset : omit nftset 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
|
||||
|
||||
4
debian/rules
vendored
4
debian/rules
vendored
@@ -52,6 +52,10 @@ ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_LIBIDN2
|
||||
endif
|
||||
|
||||
ifeq (,$(filter nonftset, $(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_NFTSET
|
||||
endif
|
||||
|
||||
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
DEB_COPTS += -DHAVE_CONNTRACK
|
||||
|
||||
@@ -348,6 +348,12 @@ the public DNS and can cause problems by triggering dial-on-demand links. This f
|
||||
to filter such requests. The requests blocked are for records of types SOA and SRV, and type ANY where the
|
||||
requested name has underscores, to catch LDAP requests.
|
||||
.TP
|
||||
.B --filter-A
|
||||
Remove A records from answers. No IPv4 addresses will be returned.
|
||||
.TP
|
||||
.B --filter-AAAA
|
||||
Remove AAAA records from answers. No IPv6 addresses will be returned.
|
||||
.TP
|
||||
.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
|
||||
@@ -518,9 +524,7 @@ Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
Queries in the domains are never forwarded and always replied to
|
||||
with the specified IP address which may be IPv4 or IPv6. To give
|
||||
both IPv4 and IPv6 addresses for a domain, use repeated \fB--address\fP flags.
|
||||
To include multiple IP addresses for a single query, use
|
||||
\fB--addn-hosts=<path>\fP instead.
|
||||
multiple addresses or both IPv4 and IPv6 addresses for a domain, use repeated \fB--address\fP flags.
|
||||
Note that /etc/hosts and DHCP leases override this for individual
|
||||
names. A common use of this is to redirect the entire doubleclick.net
|
||||
domain to some friendly local web server to avoid banner ads. The
|
||||
@@ -762,12 +766,13 @@ will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
|
||||
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
|
||||
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
|
||||
.TP
|
||||
.B --umbrella[=deviceid:<deviceid>[,orgid:<orgid>]]
|
||||
.B --umbrella[=[deviceid:<deviceid>][,orgid:<orgid>][,assetid:<id>]]
|
||||
Embeds the requestor's IP address in DNS queries forwarded upstream.
|
||||
If device id or organization id are specified, the information is
|
||||
If device id or, asset id or organization id are specified, the information is
|
||||
included in the forwarded queries and may be able to be used in
|
||||
filtering policies and reporting. The order of the deviceid and orgid
|
||||
attributes is irrelevant, but must be separated by a comma.
|
||||
filtering policies and reporting. The order of the id
|
||||
attributes is irrelevant, but they must be separated by a comma. Deviceid is
|
||||
a sixteen digit hexadecimal number, org and asset ids are decimal numbers.
|
||||
.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. Note: huge cache size impacts performance.
|
||||
@@ -1322,7 +1327,7 @@ DHCP options. This make extra space available in the DHCP packet for
|
||||
options but can, rarely, confuse old or broken clients. This flag
|
||||
forces "simple and safe" behaviour to avoid problems in such a case.
|
||||
.TP
|
||||
.B --dhcp-relay=<local address>,<server address>[,<interface]
|
||||
.B --dhcp-relay=<local address>[,<server address>][,<interface]
|
||||
Configure dnsmasq to do DHCP relay. The local address is an address
|
||||
allocated to an interface on the host running dnsmasq. All DHCP
|
||||
requests arriving on that interface will we relayed to a remote DHCP
|
||||
@@ -1330,10 +1335,9 @@ server at the server address. It is possible to relay from a single local
|
||||
address to multiple remote servers by using multiple \fB--dhcp-relay\fP
|
||||
configs with the same local address and different server
|
||||
addresses. A server address must be an IP literal address, not a
|
||||
domain name. In the case of DHCPv6, the server address may be the
|
||||
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
|
||||
must be given, not be wildcard, and is used to direct the multicast to the
|
||||
correct interface to reach the DHCP server.
|
||||
domain name. If the server address is ommitted, the request will be
|
||||
forwarded by broadcast (IPv4) or multicast (IPv6). In this case the interface
|
||||
must be given and not be wildcard.
|
||||
|
||||
Access control for DHCP clients has the same rules as for the DHCP
|
||||
server, see \fB--interface\fP, \fB--except-interface\fP, etc. The optional
|
||||
@@ -1353,6 +1357,11 @@ supported: the relay function will take precedence.
|
||||
|
||||
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
|
||||
DHCPv4 to a DHCPv6 server or vice-versa.
|
||||
|
||||
The DHCP relay function for IPv6 includes the ability to snoop
|
||||
prefix-delegation from relayed DHCP transactions. See
|
||||
.B --dhcp-script
|
||||
for details.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||
@@ -1763,15 +1772,25 @@ receives a HUP signal, the script will be invoked for existing leases
|
||||
with an "old" event.
|
||||
|
||||
|
||||
There are four further actions which may appear as the first argument
|
||||
to the script, "init", "arp-add", "arp-del" and "tftp". More may be added in the future, so
|
||||
There are five further actions which may appear as the first argument
|
||||
to the script, "init", "arp-add", "arp-del", "relay-snoop" and "tftp".
|
||||
More may be added in the future, so
|
||||
scripts should be written to ignore unknown actions. "init" is
|
||||
described below in
|
||||
.B --leasefile-ro
|
||||
|
||||
The "tftp" action is invoked when a TFTP file transfer completes: the
|
||||
arguments are the file size in bytes, the address to which the file
|
||||
was sent, and the complete pathname of the file.
|
||||
|
||||
|
||||
The "relay-snoop" action is invoked when dnsmasq is configured as a DHCP
|
||||
relay for DHCPv6 and it relays a prefx delegation to a client. The arguments
|
||||
are the name of the interface where the client is conected, its (link-local)
|
||||
address on that interface and the delegated prefix. This information is
|
||||
sufficient to install routes to the delegated prefix of a router. See
|
||||
.B --dhcp-relay
|
||||
for more details on configuring DHCP relay.
|
||||
|
||||
The "arp-add" and "arp-del" actions are only called if enabled with
|
||||
.B --script-arp
|
||||
They are are supplied with a MAC address and IP address as arguments. "arp-add" indicates
|
||||
|
||||
4
po/de.po
4
po/de.po
@@ -2145,8 +2145,8 @@ msgstr "nicht unterstützte Anfrage von %s"
|
||||
|
||||
#: tftp.c:512
|
||||
#, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "Datei %s nicht gefunden"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "Datei %s nicht gefunden für %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
4
po/es.po
4
po/es.po
@@ -2213,8 +2213,8 @@ msgstr "pedido no-soportado desde %s"
|
||||
|
||||
#: tftp.c:512
|
||||
#, fuzzy, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "archivo %s no encontrado"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "archivo %s no encontrado por %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
2
po/fi.po
2
po/fi.po
@@ -2114,7 +2114,7 @@ msgstr ""
|
||||
|
||||
#: tftp.c:512
|
||||
#, c-format
|
||||
msgid "file %s not found"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr ""
|
||||
|
||||
#: tftp.c:602
|
||||
|
||||
4
po/fr.po
4
po/fr.po
@@ -2197,8 +2197,8 @@ msgstr "requ
|
||||
|
||||
#: tftp.c:512
|
||||
#, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "fichier %s non trouvé"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "fichier %s non trouvé pour %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
4
po/id.po
4
po/id.po
@@ -2460,8 +2460,8 @@ msgstr ""
|
||||
# OK
|
||||
#: tftp.c:512
|
||||
#, fuzzy, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "lease tak ditemukan"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "file %s tidak ditemukan untuk %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
2
po/it.po
2
po/it.po
@@ -2114,7 +2114,7 @@ msgstr ""
|
||||
|
||||
#: tftp.c:512
|
||||
#, c-format
|
||||
msgid "file %s not found"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr ""
|
||||
|
||||
#: tftp.c:602
|
||||
|
||||
4
po/no.po
4
po/no.po
@@ -2194,8 +2194,8 @@ msgstr ""
|
||||
|
||||
#: tftp.c:512
|
||||
#, fuzzy, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "leie ikke funnet"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "fil %s ikke funnet for %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
4
po/pl.po
4
po/pl.po
@@ -2149,8 +2149,8 @@ msgstr "nieobsługiwane żądanie od komputera %s"
|
||||
|
||||
#: tftp.c:512
|
||||
#, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "plik %s nie został znaleziony"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "plik %s nie został znaleziony dla %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
@@ -2114,7 +2114,7 @@ msgstr ""
|
||||
|
||||
#: tftp.c:512
|
||||
#, c-format
|
||||
msgid "file %s not found"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr ""
|
||||
|
||||
#: tftp.c:602
|
||||
|
||||
4
po/ro.po
4
po/ro.po
@@ -2195,8 +2195,8 @@ msgstr ""
|
||||
|
||||
#: tftp.c:512
|
||||
#, fuzzy, c-format
|
||||
msgid "file %s not found"
|
||||
msgstr "împrumutul nu a fost găsit"
|
||||
msgid "file %s not found for %s"
|
||||
msgstr "fișier %s nu a fost găsit pentru %s"
|
||||
|
||||
#: tftp.c:602
|
||||
#, c-format
|
||||
|
||||
12
src/cache.c
12
src/cache.c
@@ -413,7 +413,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
|
||||
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
|
||||
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
|
||||
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV | F_NXDOMAIN)) ||
|
||||
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
@@ -1399,10 +1399,12 @@ 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 crecp->addr.addr4;
|
||||
|
||||
/* If no DNS service, cache not initialised. */
|
||||
if (daemon->port != 0)
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
|
||||
if (crecp->flags & F_HOSTS)
|
||||
return crecp->addr.addr4;
|
||||
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
|
||||
|
||||
ret.s_addr = 0;
|
||||
|
||||
@@ -985,11 +985,27 @@ void log_context(int family, struct dhcp_context *context)
|
||||
|
||||
void log_relay(int family, struct dhcp_relay *relay)
|
||||
{
|
||||
int broadcast = relay->server.addr4.s_addr == 0;
|
||||
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
struct in6_addr multicast;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
|
||||
|
||||
if (family == AF_INET6)
|
||||
broadcast = IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast);
|
||||
#endif
|
||||
|
||||
|
||||
if (relay->interface)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||
{
|
||||
if (broadcast)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||
}
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
27
src/dhcp.c
27
src/dhcp.c
@@ -1095,14 +1095,35 @@ static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess,
|
||||
to.sa.sa_family = AF_INET;
|
||||
to.in.sin_addr = relay->server.addr4;
|
||||
to.in.sin_port = htons(daemon->dhcp_server_port);
|
||||
|
||||
|
||||
/* Broadcasting to server. */
|
||||
if (relay->server.addr4.s_addr == 0)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
if (relay->interface)
|
||||
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
|
||||
|
||||
if (!relay->interface || strchr(relay->interface, '*') ||
|
||||
ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s"), relay->interface);
|
||||
return 1;
|
||||
}
|
||||
|
||||
to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
}
|
||||
|
||||
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
|
||||
if (relay->server.addr4.s_addr == 0)
|
||||
snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface);
|
||||
else
|
||||
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
#define OPTION6_RECONF_ACCEPT 20
|
||||
#define OPTION6_DNS_SERVER 23
|
||||
#define OPTION6_DOMAIN_SEARCH 24
|
||||
#define OPTION6_IA_PD 25
|
||||
#define OPTION6_IAPREFIX 26
|
||||
#define OPTION6_REFRESH_TIME 32
|
||||
#define OPTION6_REMOTE_ID 37
|
||||
#define OPTION6_SUBSCRIBER_ID 38
|
||||
|
||||
@@ -135,9 +135,8 @@ void dhcp6_packet(time_t now)
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) != 0)
|
||||
if (relay_reply6(&from, sz, ifr.ifr_name))
|
||||
{
|
||||
from.sin6_port = htons(port);
|
||||
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(-1), 0, (struct sockaddr *)&from,
|
||||
sizeof(from))));
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
/* Declare static char *compiler_opts in config.h */
|
||||
#define DNSMASQ_COMPILE_OPTS
|
||||
|
||||
/* dnsmasq.h has to be included first as it sources config.h */
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
struct daemon *daemon;
|
||||
|
||||
static volatile pid_t pid = 0;
|
||||
@@ -69,8 +74,10 @@ int main (int argc, char **argv)
|
||||
int tftp_prefix_missing = 0;
|
||||
#endif
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
#ifdef LOCALEDIR
|
||||
bindtextdomain("dnsmasq", LOCALEDIR);
|
||||
textdomain("dnsmasq");
|
||||
#endif
|
||||
@@ -727,7 +734,11 @@ int main (int argc, char **argv)
|
||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||
daemon->helperfd = -1;
|
||||
#ifdef HAVE_SCRIPT
|
||||
if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP)) &&
|
||||
if ((daemon->dhcp ||
|
||||
daemon->dhcp6 ||
|
||||
daemon->relay6 ||
|
||||
option_bool(OPT_TFTP) ||
|
||||
option_bool(OPT_SCRIPT_ARP)) &&
|
||||
(daemon->lease_change_command || daemon->luascript))
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
#endif
|
||||
@@ -1132,6 +1143,10 @@ int main (int argc, char **argv)
|
||||
while (helper_buf_empty() && do_tftp_script_run());
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
while (helper_buf_empty() && do_snoop_script_run());
|
||||
# endif
|
||||
|
||||
if (!helper_buf_empty())
|
||||
poll_listen(daemon->helperfd, POLLOUT);
|
||||
#else
|
||||
@@ -1682,6 +1697,11 @@ static void poll_resolv(int force, int do_reload, time_t now)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we're delaying things, we don't call check_servers(), but
|
||||
reload_servers() may have deleted some servers, rendering the server_array
|
||||
invalid, so just rebuild that here. Once reload_servers() succeeds,
|
||||
we call check_servers() above, which calls build_server_array itself. */
|
||||
build_server_array();
|
||||
latest->mtime = 0;
|
||||
if (!warned)
|
||||
{
|
||||
|
||||
@@ -275,7 +275,9 @@ struct event_desc {
|
||||
#define OPT_UMBRELLA_DEVID 64
|
||||
#define OPT_CMARK_ALST_EN 65
|
||||
#define OPT_QUIET_TFTP 66
|
||||
#define OPT_LAST 67
|
||||
#define OPT_FILTER_A 67
|
||||
#define OPT_FILTER_AAAA 68
|
||||
#define OPT_LAST 69
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -776,6 +778,7 @@ struct frec {
|
||||
#define ACTION_TFTP 5
|
||||
#define ACTION_ARP 6
|
||||
#define ACTION_ARP_DEL 7
|
||||
#define ACTION_RELAY_SNOOP 8
|
||||
|
||||
#define LEASE_NEW 1 /* newly created */
|
||||
#define LEASE_CHANGED 2 /* modified */
|
||||
@@ -1074,6 +1077,13 @@ struct dhcp_relay {
|
||||
union all_addr local, server;
|
||||
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
||||
int iface_index; /* working - interface in which requests arrived, for return */
|
||||
#ifdef HAVE_SCRIPT
|
||||
struct snoop_record {
|
||||
struct in6_addr client, prefix;
|
||||
int prefix_len;
|
||||
struct snoop_record *next;
|
||||
} *snoop_records;
|
||||
#endif
|
||||
struct dhcp_relay *current, *next;
|
||||
};
|
||||
|
||||
@@ -1173,9 +1183,12 @@ extern struct daemon {
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
|
||||
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
|
||||
char *workspacename;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
|
||||
int rr_status_sz;
|
||||
int dnssec_no_time_check;
|
||||
@@ -1222,13 +1235,18 @@ extern struct daemon {
|
||||
unsigned char *duid;
|
||||
struct iovec outpacket;
|
||||
int dhcp6fd, icmp6fd;
|
||||
# ifdef HAVE_SCRIPT
|
||||
struct snoop_record *free_snoops;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* DBus stuff */
|
||||
/* void * here to avoid depending on dbus headers outside dbus.c */
|
||||
void *dbus;
|
||||
#ifdef HAVE_DBUS
|
||||
struct watch *watches;
|
||||
#endif
|
||||
|
||||
/* UBus stuff */
|
||||
#ifdef HAVE_UBUS
|
||||
/* void * here to avoid depending on ubus headers outside ubus.c */
|
||||
@@ -1371,6 +1389,7 @@ void safe_pipe(int *fd, int read_noblock);
|
||||
void *whine_malloc(size_t size);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||
int hostname_order(const char *a, const char *b);
|
||||
int hostname_isequal(const char *a, const char *b);
|
||||
int hostname_issubdomain(char *a, char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
@@ -1613,6 +1632,9 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
|
||||
void queue_arp(int action, unsigned char *mac, int maclen,
|
||||
int family, union all_addr *addr);
|
||||
int helper_buf_empty(void);
|
||||
#ifdef HAVE_DHCP6
|
||||
void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* tftp.c */
|
||||
@@ -1658,7 +1680,10 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address,
|
||||
u32 scope_id, time_t now);
|
||||
|
||||
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
||||
int relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
||||
# ifdef HAVE_SCRIPT
|
||||
int do_snoop_script_run(void);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* dhcp-common.c */
|
||||
@@ -1746,7 +1771,11 @@ int do_poll(int timeout);
|
||||
size_t rrfilter(struct dns_header *header, size_t plen, int mode);
|
||||
u16 *rrfilter_desc(int type);
|
||||
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
|
||||
|
||||
/* modes. */
|
||||
#define RRFILTER_EDNS0 0
|
||||
#define RRFILTER_DNSSEC 1
|
||||
#define RRFILTER_A 2
|
||||
#define RRFILTER_AAAA 3
|
||||
/* edns0.c */
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
size_t *len, unsigned char **p, int *is_sign, int *is_last);
|
||||
|
||||
@@ -395,7 +395,7 @@ int is_local_answer(time_t now, int first, char *name)
|
||||
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
|
||||
{
|
||||
int trunc = 0;
|
||||
int trunc = 0, anscount = 0;
|
||||
unsigned char *p;
|
||||
int start;
|
||||
union all_addr addr;
|
||||
@@ -418,9 +418,8 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
else
|
||||
addr.addr4 = srv->addr;
|
||||
|
||||
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||
if (!add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
return 0;
|
||||
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
@@ -434,14 +433,15 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
else
|
||||
addr.addr6 = srv->addr;
|
||||
|
||||
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||
add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr);
|
||||
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
|
||||
anscount++;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (trunc)
|
||||
header->hb3 |= HB3_TC;
|
||||
|
||||
header->ancount = htons(anscount);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ static int order(char *qdomain, size_t qlen, struct server *serv)
|
||||
if (qlen > dlen)
|
||||
return -1;
|
||||
|
||||
return strcmp(qdomain, serv->domain);
|
||||
return hostname_order(qdomain, serv->domain);
|
||||
}
|
||||
|
||||
static int order_servers(struct server *s1, struct server *s2)
|
||||
@@ -542,22 +542,39 @@ static int order_qsort(const void *a, const void *b)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Must be called before add_update_server() to set daemon->servers_tail */
|
||||
void mark_servers(int flag)
|
||||
{
|
||||
struct server *serv;
|
||||
struct server *serv, **up;
|
||||
|
||||
daemon->servers_tail = NULL;
|
||||
|
||||
/* mark everything with argument flag */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
{
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
|
||||
/* --address etc is different: since they are expected to be
|
||||
1) numerous and 2) not reloaded often. We just delete
|
||||
and recreate. */
|
||||
if (flag)
|
||||
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = serv->next)
|
||||
{
|
||||
if (serv->flags & flag)
|
||||
{
|
||||
*up = serv->next;
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup_servers(void)
|
||||
@@ -565,7 +582,7 @@ void cleanup_servers(void)
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
@@ -581,19 +598,6 @@ void cleanup_servers(void)
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
*up = serv->next;
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
int add_update_server(int flags,
|
||||
@@ -626,36 +630,17 @@ int add_update_server(int flags,
|
||||
|
||||
if (!alloc_domain)
|
||||
return 0;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark
|
||||
only do this for forwarding servers, not
|
||||
address or local, to avoid delays on large numbers. */
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_MARK) &&
|
||||
hostname_isequal(alloc_domain, serv->domain))
|
||||
break;
|
||||
|
||||
if (serv)
|
||||
{
|
||||
free(alloc_domain);
|
||||
alloc_domain = serv->domain;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
if (flags & SERV_6ADDR)
|
||||
size = sizeof(struct serv_addr6);
|
||||
else if (flags & SERV_4ADDR)
|
||||
size = sizeof(struct serv_addr4);
|
||||
else
|
||||
size = sizeof(struct serv_local);
|
||||
}
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
size = sizeof(struct serv_addr6);
|
||||
else if (flags & SERV_4ADDR)
|
||||
size = sizeof(struct serv_addr4);
|
||||
else
|
||||
size = sizeof(struct server);
|
||||
size = sizeof(struct serv_local);
|
||||
|
||||
if (!(serv = whine_malloc(size)))
|
||||
{
|
||||
@@ -663,19 +648,53 @@ int add_update_server(int flags,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
serv->next = daemon->local_domains;
|
||||
daemon->local_domains = serv;
|
||||
|
||||
if (flags & SERV_4ADDR)
|
||||
((struct serv_addr4*)serv)->addr = local_addr->addr4;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
((struct serv_addr6*)serv)->addr = local_addr->addr6;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Upstream servers. See if there is a suitable candidate, if so unmark
|
||||
and move to the end of the list, for order. The entry found may already
|
||||
be at the end. */
|
||||
struct server **up, *tmp;
|
||||
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
serv->next = daemon->local_domains;
|
||||
daemon->local_domains = serv;
|
||||
tmp = serv->next;
|
||||
if ((serv->flags & SERV_MARK) &&
|
||||
hostname_isequal(alloc_domain, serv->domain))
|
||||
{
|
||||
/* Need to move down? */
|
||||
if (serv->next)
|
||||
{
|
||||
*up = serv->next;
|
||||
daemon->servers_tail->next = serv;
|
||||
daemon->servers_tail = serv;
|
||||
serv->next = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & SERV_4ADDR)
|
||||
((struct serv_addr4*)serv)->addr = local_addr->addr4;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
((struct serv_addr6*)serv)->addr = local_addr->addr6;
|
||||
if (serv)
|
||||
{
|
||||
free(alloc_domain);
|
||||
alloc_domain = serv->domain;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(serv = whine_malloc(sizeof(struct server))))
|
||||
{
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
/* Add to the end of the chain, for order */
|
||||
@@ -684,20 +703,20 @@ int add_update_server(int flags,
|
||||
else
|
||||
daemon->servers = serv;
|
||||
daemon->servers_tail = serv;
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
|
||||
|
||||
serv->flags = flags;
|
||||
serv->domain = alloc_domain;
|
||||
serv->domain_len = strlen(alloc_domain);
|
||||
|
||||
44
src/edns0.c
44
src/edns0.c
@@ -178,7 +178,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
memcpy(buff, datap, rdlen);
|
||||
|
||||
/* now, delete OPT RR */
|
||||
plen = rrfilter(header, plen, 0);
|
||||
plen = rrfilter(header, plen, RRFILTER_EDNS0);
|
||||
|
||||
/* Now, force addition of a new one */
|
||||
p = NULL;
|
||||
@@ -460,31 +460,33 @@ static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned
|
||||
|
||||
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
|
||||
u8 *u = &opt.fields[0];
|
||||
|
||||
if (daemon->umbrella_org) {
|
||||
PUTSHORT(UMBRELLA_ORG, u);
|
||||
PUTLONG(daemon->umbrella_org, u);
|
||||
}
|
||||
|
||||
int family = source->sa.sa_family;
|
||||
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
|
||||
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
|
||||
|
||||
if (daemon->umbrella_org)
|
||||
{
|
||||
PUTSHORT(UMBRELLA_ORG, u);
|
||||
PUTLONG(daemon->umbrella_org, u);
|
||||
}
|
||||
|
||||
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
|
||||
memcpy(u, get_addrp(source, family), size);
|
||||
u += size;
|
||||
|
||||
if (option_bool(OPT_UMBRELLA_DEVID))
|
||||
{
|
||||
PUTSHORT(UMBRELLA_DEVICE, u);
|
||||
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
|
||||
u += UMBRELLA_DEVICESZ;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_UMBRELLA_DEVID)) {
|
||||
PUTSHORT(UMBRELLA_DEVICE, u);
|
||||
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
|
||||
u += UMBRELLA_DEVICESZ;
|
||||
}
|
||||
|
||||
if (daemon->umbrella_asset) {
|
||||
PUTSHORT(UMBRELLA_ASSET, u);
|
||||
PUTLONG(daemon->umbrella_asset, u);
|
||||
}
|
||||
|
||||
int len = u - &opt.magic[0];
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, len, 0, 1);
|
||||
if (daemon->umbrella_asset)
|
||||
{
|
||||
PUTSHORT(UMBRELLA_ASSET, u);
|
||||
PUTLONG(daemon->umbrella_asset, u);
|
||||
}
|
||||
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
|
||||
}
|
||||
|
||||
/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||
|
||||
@@ -153,11 +153,20 @@ static int domain_no_rebind(char *domain)
|
||||
{
|
||||
struct rebind_domain *rbd;
|
||||
size_t tlen, dlen = strlen(domain);
|
||||
|
||||
char *dots = strchr(domain, '.');
|
||||
|
||||
/* Match whole labels only. Empty domain matches no dots (any single label) */
|
||||
for (rbd = daemon->no_rebind; rbd; rbd = rbd->next)
|
||||
if (dlen >= (tlen = strlen(rbd->domain)) && strcmp(rbd->domain, &domain[dlen - tlen]) == 0)
|
||||
{
|
||||
if (dlen >= (tlen = strlen(rbd->domain)) &&
|
||||
hostname_isequal(rbd->domain, &domain[dlen - tlen]) &&
|
||||
(dlen == tlen || domain[dlen - tlen - 1] == '.'))
|
||||
return 1;
|
||||
|
||||
if (tlen == 0 && !dots)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -170,10 +179,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
unsigned int fwd_flags = 0;
|
||||
int is_dnssec = forward && (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY));
|
||||
struct server *master;
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
int old_src = 0;
|
||||
int old_src = 0, old_reply = 0;
|
||||
int first, last, start = 0;
|
||||
int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
@@ -199,7 +208,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
Similarly FREC_NO_CACHE is never set in flags, so a query which is
|
||||
contigent on a particular source address EDNS0 option will never be matched. */
|
||||
if (forward)
|
||||
old_src = 1;
|
||||
{
|
||||
old_src = 1;
|
||||
old_reply = 1;
|
||||
}
|
||||
else if ((forward = lookup_frec_by_query(hash, fwd_flags,
|
||||
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
|
||||
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
|
||||
@@ -212,7 +224,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
break;
|
||||
|
||||
if (src)
|
||||
old_src = 1;
|
||||
{
|
||||
old_src = 1;
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
src->log_id = daemon->log_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Existing query, but from new source, just add this
|
||||
@@ -283,6 +299,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
goto reply;
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
|
||||
forward->frec_src.log_id = daemon->log_id;
|
||||
forward->frec_src.source = *udpaddr;
|
||||
forward->frec_src.orig_id = ntohs(header->id);
|
||||
forward->frec_src.dest = *dst_addr;
|
||||
@@ -326,7 +343,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* retry on existing query, from original source. Send to all available servers */
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* If we've already got an answer to this query, but we're awaiting keys for validation,
|
||||
there's no point retrying the query, retry the key query instead...... */
|
||||
@@ -337,7 +353,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
while (forward->blocking_query)
|
||||
forward = forward->blocking_query;
|
||||
|
||||
|
||||
/* log_id should match previous DNSSEC query. */
|
||||
daemon->log_display_id = forward->frec_src.log_id;
|
||||
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
/* get query for logging. */
|
||||
@@ -376,9 +395,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* In strict order mode, there must be a server later in the list
|
||||
left to send to, otherwise without the forwardall mechanism,
|
||||
code further on will cycle around the list forwever if they
|
||||
all return REFUSED. If at the last, give up. */
|
||||
all return REFUSED. If at the last, give up.
|
||||
Note that we can get here EITHER because a client retried,
|
||||
or an upstream server returned REFUSED. The above only
|
||||
applied in the later case. For client retries,
|
||||
keep trying the last server.. */
|
||||
if (++start == last)
|
||||
goto reply;
|
||||
{
|
||||
if (old_reply)
|
||||
goto reply;
|
||||
else
|
||||
start--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,9 +418,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->flags |= FREC_TEST_PKTSZ;
|
||||
}
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
forward->frec_src.log_id = daemon->log_id;
|
||||
|
||||
/* We may be resending a DNSSEC query here, for which the below processing is not necessary. */
|
||||
if (!is_dnssec)
|
||||
{
|
||||
@@ -617,7 +642,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
if (added_pheader)
|
||||
{
|
||||
/* client didn't send EDNS0, we added one, strip it off before returning answer. */
|
||||
n = rrfilter(header, n, 0);
|
||||
n = rrfilter(header, n, RRFILTER_EDNS0);
|
||||
pheader = NULL;
|
||||
}
|
||||
else
|
||||
@@ -706,7 +731,17 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
cache_secure = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Before extract_addresses() */
|
||||
if (rcode == NOERROR)
|
||||
{
|
||||
if (option_bool(OPT_FILTER_A))
|
||||
n = rrfilter(header, n, RRFILTER_A);
|
||||
|
||||
if (option_bool(OPT_FILTER_AAAA))
|
||||
n = rrfilter(header, n, RRFILTER_AAAA);
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
@@ -736,7 +771,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
|
||||
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||
if (!do_bit)
|
||||
n = rrfilter(header, n, 1);
|
||||
n = rrfilter(header, n, RRFILTER_DNSSEC);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -760,7 +795,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
u16 swap = htons((u16)ede);
|
||||
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
|
||||
}
|
||||
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
63
src/helper.c
63
src/helper.c
@@ -233,8 +233,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
is6 = (data.flags != AF_INET);
|
||||
data.action = ACTION_ARP;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
else if (data.action == ACTION_RELAY_SNOOP)
|
||||
{
|
||||
is6 = 1;
|
||||
action_str = "relay-snoop";
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
/* stringify MAC into dhcp_buff */
|
||||
p = daemon->dhcp_buff;
|
||||
@@ -286,7 +291,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
char *dot;
|
||||
hostname = (char *)buf;
|
||||
hostname[data.hostname_len - 1] = 0;
|
||||
if (data.action != ACTION_TFTP)
|
||||
if (data.action != ACTION_TFTP && data.action != ACTION_RELAY_SNOOP)
|
||||
{
|
||||
if (!legal_hostname(hostname))
|
||||
hostname = NULL;
|
||||
@@ -332,6 +337,24 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
}
|
||||
else if (data.action == ACTION_RELAY_SNOOP)
|
||||
{
|
||||
lua_getglobal(lua, "snoop");
|
||||
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||
lua_pop(lua, 1); /* tftp function optional */
|
||||
else
|
||||
{
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "client_address");
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "prefix");
|
||||
lua_pushstring(lua, data.interface);
|
||||
lua_setfield(lua, -2, "client_interface");
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
}
|
||||
else if (data.action == ACTION_ARP)
|
||||
{
|
||||
lua_getglobal(lua, "arp");
|
||||
@@ -432,8 +455,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata_lua(buf, end, "relay_address");
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
|
||||
lua_pushstring(lua, daemon->dhcp_buff2);
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
@@ -553,7 +576,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
close(pipeout[1]);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
|
||||
if (data.action != ACTION_TFTP && data.action != ACTION_ARP && data.action != ACTION_RELAY_SNOOP)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
|
||||
@@ -615,7 +638,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
{
|
||||
const char *giaddr = NULL;
|
||||
if (data.giaddr.s_addr != 0)
|
||||
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", giaddr, &err);
|
||||
}
|
||||
|
||||
@@ -640,6 +663,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
||||
close(pipefd[0]);
|
||||
|
||||
if (data.action == ACTION_RELAY_SNOOP)
|
||||
strcpy(daemon->packet, data.interface);
|
||||
|
||||
p = strrchr(daemon->lease_change_command, '/');
|
||||
if (err == 0)
|
||||
{
|
||||
@@ -810,6 +836,29 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
bytes_in_buf = p - (unsigned char *)buf;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len)
|
||||
{
|
||||
/* no script */
|
||||
if (daemon->helperfd == -1)
|
||||
return;
|
||||
|
||||
inet_ntop(AF_INET6, prefix, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
/* 5 for /nnn and zero on the end of the prefix. */
|
||||
buff_alloc(sizeof(struct script_data) + ADDRSTRLEN + 5);
|
||||
memset(buf, 0, sizeof(struct script_data));
|
||||
|
||||
buf->action = ACTION_RELAY_SNOOP;
|
||||
buf->addr6 = *client;
|
||||
buf->hostname_len = sprintf((char *)(buf+1), "%s/%u", daemon->addrbuff, prefix_len) + 1;
|
||||
|
||||
indextoname(daemon->dhcp6fd, if_index, buf->interface);
|
||||
|
||||
bytes_in_buf = sizeof(struct script_data) + buf->hostname_len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* This nastily re-uses DHCP-fields for TFTP stuff */
|
||||
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
|
||||
|
||||
180
src/option.c
180
src/option.c
@@ -175,7 +175,9 @@ struct myoption {
|
||||
#define LOPT_CMARK_ALST 366
|
||||
#define LOPT_QUIET_TFTP 367
|
||||
#define LOPT_NFTSET 368
|
||||
|
||||
#define LOPT_FILTER_A 369
|
||||
#define LOPT_FILTER_AAAA 370
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
#else
|
||||
@@ -212,6 +214,8 @@ static const struct myoption opts[] =
|
||||
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
|
||||
{ "selfmx", 0, 0, 'e' },
|
||||
{ "filterwin2k", 0, 0, 'f' },
|
||||
{ "filter-A", 0, 0, LOPT_FILTER_A },
|
||||
{ "filter-AAAA", 0, 0, LOPT_FILTER_AAAA },
|
||||
{ "pid-file", 2, 0, 'x' },
|
||||
{ "strict-order", 0, 0, 'o' },
|
||||
{ "server", 1, 0, 'S' },
|
||||
@@ -353,7 +357,7 @@ static const struct myoption opts[] =
|
||||
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
|
||||
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
|
||||
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
|
||||
{ "umbrella", 2, 0, LOPT_UMBRELLA },
|
||||
{ "umbrella", 2, 0, LOPT_UMBRELLA },
|
||||
{ "quiet-tftp", 0, 0, LOPT_QUIET_TFTP },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
@@ -382,6 +386,8 @@ static struct {
|
||||
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
|
||||
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
|
||||
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
|
||||
{ LOPT_FILTER_A, OPT_FILTER_A, NULL, gettext_noop("Don't include IPv4 addresses in DNS answers."), NULL },
|
||||
{ LOPT_FILTER_AAAA, OPT_FILTER_AAAA, NULL, gettext_noop("Don't include IPv6 addresses in DNS answers."), NULL },
|
||||
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
|
||||
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
|
||||
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
|
||||
@@ -657,7 +663,7 @@ static char *canonicalise_opt(char *s)
|
||||
return 0;
|
||||
|
||||
if (strlen(s) == 0)
|
||||
return opt_string_alloc("");
|
||||
return opt_malloc(1); /* Heap-allocated empty string */
|
||||
|
||||
unhide_metas(s);
|
||||
if (!(ret = canonicalise(s, &nomem)) && nomem)
|
||||
@@ -963,13 +969,9 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
|
||||
|
||||
if (size > 32 || size < 1)
|
||||
return _("bad IPv4 prefix length");
|
||||
|
||||
for (i = 0; i < addrbytes; i++)
|
||||
if (((u8 *)addr4)[3-i] != 0)
|
||||
break;
|
||||
|
||||
if (i != addrbytes || (((u8 *)addr4)[3-addrbytes] & ((1 << addrbits) - 1)) != 0)
|
||||
return _("address part not zero");
|
||||
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1);
|
||||
|
||||
size = size & ~0x7;
|
||||
|
||||
@@ -1026,13 +1028,9 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
|
||||
|
||||
if (size > 128 || size < 1)
|
||||
return _("bad IPv6 prefix length");
|
||||
|
||||
for (i = 0; i < addrbytes; i++)
|
||||
if (addr6->s6_addr[15-i] != 0)
|
||||
break;
|
||||
|
||||
if (i != addrbytes || (addr6->s6_addr[15-addrbytes] & ((1 << addrbits) - 1)) != 0)
|
||||
return _("address part not zero");
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
addr6->s6_addr[15-addrbytes] &= ~((1 << addrbits) - 1);
|
||||
|
||||
size = size & ~0x3;
|
||||
|
||||
@@ -2235,8 +2233,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
comma = split(arg);
|
||||
|
||||
new = opt_malloc(sizeof(struct auth_zone));
|
||||
new->domain = opt_string_alloc(arg);
|
||||
new->subnet = NULL;
|
||||
new->domain = canonicalise_opt(arg);
|
||||
if (!new->domain)
|
||||
ret_err_free(_("invalid auth-zone"), new);
|
||||
new->subnet = NULL;
|
||||
new->exclude = NULL;
|
||||
new->interface_names = NULL;
|
||||
new->next = daemon->auth_zones;
|
||||
@@ -2519,39 +2519,48 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_UMBRELLA: /* --umbrella */
|
||||
set_option_bool(OPT_UMBRELLA);
|
||||
while (arg) {
|
||||
comma = split(arg);
|
||||
if (strstr(arg, "deviceid:")) {
|
||||
arg += 9;
|
||||
if (strlen(arg) != 16)
|
||||
ret_err(gen_err);
|
||||
for (char *p = arg; *p; p++) {
|
||||
if (!isxdigit((int)*p))
|
||||
ret_err(gen_err);
|
||||
}
|
||||
set_option_bool(OPT_UMBRELLA_DEVID);
|
||||
|
||||
u8 *u = daemon->umbrella_device;
|
||||
char word[3];
|
||||
for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
|
||||
memcpy(word, &(arg[0]), 2);
|
||||
*u++ = strtoul(word, NULL, 16);
|
||||
}
|
||||
}
|
||||
else if (strstr(arg, "orgid:")) {
|
||||
if (!strtoul_check(arg+6, &daemon->umbrella_org)) {
|
||||
ret_err(gen_err);
|
||||
}
|
||||
}
|
||||
else if (strstr(arg, "assetid:")) {
|
||||
if (!strtoul_check(arg+8, &daemon->umbrella_asset)) {
|
||||
ret_err(gen_err);
|
||||
}
|
||||
}
|
||||
arg = comma;
|
||||
}
|
||||
while (arg)
|
||||
{
|
||||
comma = split(arg);
|
||||
if (strstr(arg, "deviceid:"))
|
||||
{
|
||||
char *p;
|
||||
u8 *u = daemon->umbrella_device;
|
||||
char word[3];
|
||||
|
||||
arg += 9;
|
||||
if (strlen(arg) != 16)
|
||||
ret_err(gen_err);
|
||||
|
||||
for (p = arg; *p; p++)
|
||||
if (!isxdigit((int)*p))
|
||||
ret_err(gen_err);
|
||||
|
||||
set_option_bool(OPT_UMBRELLA_DEVID);
|
||||
|
||||
for (i = 0; i < (int)sizeof(daemon->umbrella_device); i++, arg+=2)
|
||||
{
|
||||
memcpy(word, &(arg[0]), 2);
|
||||
*u++ = strtoul(word, NULL, 16);
|
||||
}
|
||||
}
|
||||
else if (strstr(arg, "orgid:"))
|
||||
{
|
||||
if (!strtoul_check(arg+6, &daemon->umbrella_org))
|
||||
ret_err(gen_err);
|
||||
}
|
||||
else if (strstr(arg, "assetid:"))
|
||||
{
|
||||
if (!strtoul_check(arg+8, &daemon->umbrella_asset))
|
||||
ret_err(gen_err);
|
||||
}
|
||||
else
|
||||
ret_err(gen_err);
|
||||
|
||||
arg = comma;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LOPT_ADD_MAC: /* --add-mac */
|
||||
if (!arg)
|
||||
set_option_bool(OPT_ADD_MAC);
|
||||
@@ -2766,7 +2775,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (!arg || !*arg)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if (option != 'S')
|
||||
else if (option == 'A')
|
||||
{
|
||||
/* # as literal address means return zero address for 4 and 6 */
|
||||
if (strcmp(arg, "#") == 0)
|
||||
@@ -2798,7 +2807,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
|
||||
/* address=/#/ matches the same as without domain */
|
||||
if (option != 'S' && domain[0] == '#' && domain[1] == 0)
|
||||
if (option == 'A' && domain[0] == '#' && domain[1] == 0)
|
||||
domain[0] = 0;
|
||||
}
|
||||
|
||||
@@ -4128,7 +4137,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case LOPT_SUBSCR: /* --dhcp-subscrid */
|
||||
{
|
||||
unsigned char *p;
|
||||
int dig = 0;
|
||||
int dig, colon;
|
||||
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
|
||||
|
||||
if (!(comma = split(arg)))
|
||||
@@ -4152,13 +4161,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
comma = arg;
|
||||
|
||||
for (p = (unsigned char *)comma; *p; p++)
|
||||
for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++)
|
||||
if (isxdigit(*p))
|
||||
dig = 1;
|
||||
else if (*p != ':')
|
||||
else if (*p == ':')
|
||||
colon = 1;
|
||||
else
|
||||
break;
|
||||
|
||||
unhide_metas(comma);
|
||||
if (option == 'U' || option == 'j' || *p || !dig)
|
||||
if (option == 'U' || option == 'j' || *p || !dig || !colon)
|
||||
{
|
||||
new->len = strlen(comma);
|
||||
new->data = opt_malloc(new->len);
|
||||
@@ -4281,26 +4293,56 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LOPT_RELAY: /* --dhcp-relay */
|
||||
{
|
||||
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
||||
comma = split(arg);
|
||||
new->interface = opt_string_alloc(split(comma));
|
||||
char *two = split(arg);
|
||||
char *three = split(two);
|
||||
|
||||
new->iface_index = 0;
|
||||
if (comma && inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
|
||||
|
||||
if (two)
|
||||
{
|
||||
new->next = daemon->relay4;
|
||||
daemon->relay4 = new;
|
||||
}
|
||||
if (inet_pton(AF_INET, arg, &new->local))
|
||||
{
|
||||
if (!inet_pton(AF_INET, two, &new->server))
|
||||
{
|
||||
new->server.addr4.s_addr = 0;
|
||||
|
||||
/* Fail for three arg version where there are not two addresses.
|
||||
Also fail when broadcasting to wildcard address. */
|
||||
if (three || strchr(two, '*'))
|
||||
two = NULL;
|
||||
else
|
||||
three = two;
|
||||
}
|
||||
|
||||
new->next = daemon->relay4;
|
||||
daemon->relay4 = new;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (comma && inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay6;
|
||||
daemon->relay6 = new;
|
||||
}
|
||||
else if (inet_pton(AF_INET6, arg, &new->local))
|
||||
{
|
||||
if (!inet_pton(AF_INET6, two, &new->server))
|
||||
{
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &new->server.addr6);
|
||||
/* Fail for three arg version where there are not two addresses.
|
||||
Also fail when multicasting to wildcard address. */
|
||||
if (three || strchr(two, '*'))
|
||||
two = NULL;
|
||||
else
|
||||
three = two;
|
||||
}
|
||||
new->next = daemon->relay6;
|
||||
daemon->relay6 = new;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
|
||||
new->interface = opt_string_alloc(three);
|
||||
}
|
||||
|
||||
if (!two)
|
||||
{
|
||||
free(new->interface);
|
||||
ret_err_free(_("Bad dhcp-relay"), new);
|
||||
|
||||
@@ -129,9 +129,9 @@ int is_valid_dns_name(const char *value)
|
||||
|
||||
size_t num_bytes = 0;
|
||||
size_t num_labels = 0;
|
||||
const char *label = NULL;
|
||||
const char *c, *label = NULL;
|
||||
int is_label_numeric = 1;
|
||||
for (const char *c = value;; c++)
|
||||
for (c = value;; c++)
|
||||
{
|
||||
if (*c &&
|
||||
*c != '-' && *c != '.' &&
|
||||
@@ -242,11 +242,11 @@ int is_valid_dns_name_pattern(const char *value)
|
||||
|
||||
size_t num_bytes = 0;
|
||||
size_t num_labels = 0;
|
||||
const char *label = NULL;
|
||||
const char *c, *label = NULL;
|
||||
int is_label_numeric = 1;
|
||||
size_t num_wildcards = 0;
|
||||
int previous_label_has_wildcard = 1;
|
||||
for (const char *c = value;; c++)
|
||||
for (c = value;; c++)
|
||||
{
|
||||
if (*c &&
|
||||
*c != '*' && /* Wildcard. */
|
||||
|
||||
@@ -2170,7 +2170,10 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
|
||||
if (!relay->interface || strchr(relay->interface, '*') ||
|
||||
(multicast_iface = if_nametoindex(relay->interface)) == 0 ||
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast DHCP relay via interface %s"), relay->interface);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
|
||||
@@ -2178,8 +2181,11 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
|
||||
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
|
||||
snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
|
||||
else
|
||||
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
@@ -2188,7 +2194,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
|
||||
int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
|
||||
{
|
||||
struct dhcp_relay *relay;
|
||||
struct in6_addr link;
|
||||
@@ -2220,11 +2226,76 @@ unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival
|
||||
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
|
||||
peer->sin6_scope_id = relay->iface_index;
|
||||
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
if (encap_type == DHCP6RELAYREPL)
|
||||
{
|
||||
peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
|
||||
{
|
||||
/* decapsulate relayed message */
|
||||
opts = opt6_ptr(opt, 4);
|
||||
end = opt6_ptr(opt, opt6_len(opt));
|
||||
|
||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
||||
if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
|
||||
{
|
||||
void *ia_opts = opt6_ptr(opt, 12);
|
||||
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||
void *ia_opt;
|
||||
|
||||
for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
|
||||
/* valid lifetime must not be zero. */
|
||||
if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
|
||||
{
|
||||
if (daemon->free_snoops ||
|
||||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
|
||||
{
|
||||
struct snoop_record *snoop = daemon->free_snoops;
|
||||
|
||||
daemon->free_snoops = snoop->next;
|
||||
snoop->client = peer->sin6_addr;
|
||||
snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
|
||||
memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
|
||||
snoop->next = relay->snoop_records;
|
||||
relay->snoop_records = snoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
int do_snoop_script_run(void)
|
||||
{
|
||||
struct dhcp_relay *relay;
|
||||
struct snoop_record *snoop;
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
if ((snoop = relay->snoop_records))
|
||||
{
|
||||
relay->snoop_records = snoop->next;
|
||||
snoop->next = daemon->free_snoops;
|
||||
daemon->free_snoops = snoop;
|
||||
|
||||
queue_relay_snoop(&snoop->client, relay->iface_index, &snoop->prefix, snoop->prefix_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -156,7 +156,7 @@ static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, i
|
||||
}
|
||||
|
||||
|
||||
/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
|
||||
/* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section. */
|
||||
size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
{
|
||||
static unsigned char **rrs;
|
||||
@@ -192,20 +192,37 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
return plen;
|
||||
|
||||
/* Don't remove the answer. */
|
||||
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
|
||||
continue;
|
||||
|
||||
if (mode == 0) /* EDNS */
|
||||
if (mode == RRFILTER_EDNS0) /* EDNS */
|
||||
{
|
||||
/* EDNS mode, remove T_OPT from additional section only */
|
||||
if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
|
||||
continue;
|
||||
}
|
||||
else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
|
||||
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
|
||||
continue;
|
||||
|
||||
else if (mode == RRFILTER_DNSSEC)
|
||||
{
|
||||
if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
|
||||
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
|
||||
continue;
|
||||
|
||||
/* Don't remove the answer. */
|
||||
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only looking at answer section now. */
|
||||
if (i >= ntohs(header->ancount))
|
||||
break;
|
||||
|
||||
if (class != C_IN)
|
||||
continue;
|
||||
|
||||
if (mode == RRFILTER_A && type != T_A)
|
||||
continue;
|
||||
|
||||
if (mode == RRFILTER_AAAA && type != T_AAAA)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
|
||||
return plen;
|
||||
|
||||
26
src/tftp.c
26
src/tftp.c
@@ -19,9 +19,9 @@
|
||||
#ifdef HAVE_TFTP
|
||||
|
||||
static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client);
|
||||
static void free_transfer(struct tftp_transfer *transfer);
|
||||
static ssize_t tftp_err(int err, char *packet, char *message, char *file);
|
||||
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2);
|
||||
static ssize_t tftp_err_oops(char *packet, const char *file);
|
||||
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
|
||||
static char *next(char **p, char *end);
|
||||
@@ -362,7 +362,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
!(mode = next(&p, end)) ||
|
||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||
{
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff, NULL);
|
||||
is_err = 1;
|
||||
}
|
||||
else
|
||||
@@ -472,7 +472,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
/* check permissions and open file */
|
||||
if ((transfer->file = check_tftp_fileperm(&len, prefix)))
|
||||
if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
|
||||
{
|
||||
if ((len = get_block(packet, transfer)) == -1)
|
||||
len = tftp_err_oops(packet, daemon->namebuff);
|
||||
@@ -492,7 +492,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client)
|
||||
{
|
||||
char *packet = daemon->packet, *namebuff = daemon->namebuff;
|
||||
struct tftp_file *file;
|
||||
@@ -509,7 +509,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
*len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
|
||||
*len = tftp_err(ERR_FNF, packet, _("file %s not found for %s"), namebuff, client);
|
||||
return NULL;
|
||||
}
|
||||
else if (errno == EACCES)
|
||||
@@ -562,8 +562,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
|
||||
return file;
|
||||
|
||||
perm:
|
||||
errno = EACCES;
|
||||
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
|
||||
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff, strerror(EACCES));
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return NULL;
|
||||
@@ -599,7 +598,7 @@ void check_tftp_listeners(time_t now)
|
||||
{
|
||||
/* Wrong source address. See rfc1350 para 4. */
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
|
||||
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL);
|
||||
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
|
||||
}
|
||||
}
|
||||
@@ -743,22 +742,21 @@ static void sanitise(char *buf)
|
||||
}
|
||||
|
||||
#define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */
|
||||
static ssize_t tftp_err(int err, char *packet, char *message, char *file)
|
||||
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2)
|
||||
{
|
||||
struct errmess {
|
||||
unsigned short op, err;
|
||||
char message[];
|
||||
} *mess = (struct errmess *)packet;
|
||||
ssize_t len, ret = 4;
|
||||
char *errstr = strerror(errno);
|
||||
|
||||
|
||||
memset(packet, 0, daemon->packet_buff_sz);
|
||||
if (file)
|
||||
sanitise(file);
|
||||
|
||||
mess->op = htons(OP_ERR);
|
||||
mess->err = htons(err);
|
||||
len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
|
||||
len = snprintf(mess->message, MAXMESSAGE, message, file, arg2);
|
||||
ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
|
||||
|
||||
if (err != ERR_FNF || !option_bool(OPT_QUIET_TFTP))
|
||||
@@ -772,7 +770,7 @@ static ssize_t tftp_err_oops(char *packet, const char *file)
|
||||
/* May have >1 refs to file, so potentially mangle a copy of the name */
|
||||
if (file != daemon->namebuff)
|
||||
strcpy(daemon->namebuff, file);
|
||||
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
|
||||
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff, strerror(errno));
|
||||
}
|
||||
|
||||
/* return -1 for error, zero for done. */
|
||||
|
||||
27
src/util.c
27
src/util.c
@@ -233,8 +233,6 @@ char *canonicalise(char *in, int *nomem)
|
||||
{
|
||||
# ifdef HAVE_LIBIDN2
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
|
||||
if (rc == IDN2_DISALLOWED)
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
|
||||
# else
|
||||
rc = idna_to_ascii_lz(in, &ret, 0);
|
||||
# endif
|
||||
@@ -369,7 +367,7 @@ int sa_len(union mysockaddr *addr)
|
||||
}
|
||||
|
||||
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
|
||||
int hostname_isequal(const char *a, const char *b)
|
||||
int hostname_order(const char *a, const char *b)
|
||||
{
|
||||
unsigned int c1, c2;
|
||||
|
||||
@@ -382,11 +380,19 @@ int hostname_isequal(const char *a, const char *b)
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
|
||||
if (c1 != c2)
|
||||
return 0;
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
else if (c1 > c2)
|
||||
return 1;
|
||||
|
||||
} while (c1);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hostname_isequal(const char *a, const char *b)
|
||||
{
|
||||
return hostname_order(a, b) == 0;
|
||||
}
|
||||
|
||||
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
|
||||
@@ -430,13 +436,12 @@ int hostname_issubdomain(char *a, char *b)
|
||||
time_t dnsmasq_time(void)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
struct tms dummy;
|
||||
static long tps = 0;
|
||||
struct timespec ts;
|
||||
|
||||
if (tps == 0)
|
||||
tps = sysconf(_SC_CLK_TCK);
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
||||
die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
|
||||
|
||||
return (time_t)(times(&dummy)/tps);
|
||||
return ts.tv_sec;
|
||||
#else
|
||||
return time(NULL);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user