Compare commits
69 Commits
v2.86
...
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 | ||
|
|
47aefca5e4 | ||
|
|
981fb03710 | ||
|
|
ef2f8d70d2 | ||
|
|
d9995a1add | ||
|
|
ea7a05ad43 | ||
|
|
26bbf5a314 | ||
|
|
c147329823 | ||
|
|
eb88eed1fc | ||
|
|
8312a3ba4f | ||
|
|
35f93081dc | ||
|
|
de372d6914 | ||
|
|
4ac517e4ac | ||
|
|
e3651367b3 | ||
|
|
02ea41ddd1 | ||
|
|
51ffae4eab | ||
|
|
afe84f37f8 | ||
|
|
0afeef0e00 | ||
|
|
94a17fd97f | ||
|
|
5b5ec55445 | ||
|
|
1e6565c1a5 | ||
|
|
fc522515b9 | ||
|
|
9881b0736d | ||
|
|
e52b4b1466 | ||
|
|
2f45670951 | ||
|
|
50d75ae514 | ||
|
|
dea69a12aa | ||
|
|
e0ce3c12f2 | ||
|
|
93cf516bf1 | ||
|
|
6f4de018af | ||
|
|
6e91cf3172 | ||
|
|
9cb7f8a655 | ||
|
|
5d8d1ad14b | ||
|
|
c4523639d5 | ||
|
|
1ce1c6beae |
37
CHANGELOG
37
CHANGELOG
@@ -1,3 +1,37 @@
|
||||
version 2.87
|
||||
Allow arbitrary prefix lengths in --rev-server and
|
||||
--domain=....,local
|
||||
|
||||
Replace --address=/#/..... functionality which got
|
||||
missed in the 2.86 domain search rewrite.
|
||||
|
||||
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.
|
||||
Thanks to Aichun Li for spotting this omission, and the initial
|
||||
@@ -92,6 +126,9 @@ version 2.86
|
||||
of filename). Thanks to Ed Wildgoose for the initial patch
|
||||
and motivation for this.
|
||||
|
||||
Allow adding IP address to nftables set in addition to
|
||||
ipset.
|
||||
|
||||
|
||||
version 2.85
|
||||
Fix problem with DNS retries in 2.83/2.84.
|
||||
|
||||
14
Makefile
14
Makefile
@@ -70,7 +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`
|
||||
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 ' '
|
||||
@@ -82,7 +84,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o pattern.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||
metrics.o hash-questions.o domain-match.o
|
||||
metrics.o hash-questions.o domain-match.o nftset.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
@@ -90,8 +92,8 @@ 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_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
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
|
||||
|
||||
mostly_clean :
|
||||
@@ -115,8 +117,8 @@ 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_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
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 \
|
||||
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -280,6 +280,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
|
||||
a DHCP server */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
|
||||
|
||||
@@ -318,6 +318,12 @@ void usage(const char* arg, FILE* stream)
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
}
|
||||
|
||||
static void fail_fatal(const char *errstr, int exitcode)
|
||||
{
|
||||
perror(errstr);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
{
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
@@ -343,18 +349,19 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
|
||||
client_addr.sin6_flowinfo = 0;
|
||||
client_addr.sin6_scope_id =0;
|
||||
inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
|
||||
bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
|
||||
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
|
||||
if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0)
|
||||
perror("bind"); /* continue on bind error */
|
||||
if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
int16_t recv_size = 0;
|
||||
ssize_t recv_size = 0;
|
||||
int result;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
exit(4);
|
||||
}
|
||||
fail_fatal("sendto failed", 4);
|
||||
|
||||
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
|
||||
if (recv_size == -1)
|
||||
@@ -367,16 +374,18 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
else
|
||||
{
|
||||
perror("recvfrom");
|
||||
result = UNSPEC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return result;
|
||||
}
|
||||
|
||||
8
debian/changelog
vendored
8
debian/changelog
vendored
@@ -1,3 +1,11 @@
|
||||
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
|
||||
|
||||
dnsmasq (2.86-1) unstable; urgency=low
|
||||
|
||||
* Fix debian/changelog format error. (closes: #986626)
|
||||
|
||||
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
|
||||
|
||||
@@ -85,6 +85,16 @@
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to netfilters sets, which is equivalent to
|
||||
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
|
||||
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
|
||||
|
||||
# Use netfilters sets for both IPv4 and IPv6:
|
||||
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
|
||||
#nftset=/yahoo.com/4#ip#test#vpn4
|
||||
#nftset=/yahoo.com/6#ip#test#vpn6
|
||||
|
||||
# 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
|
||||
|
||||
@@ -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
|
||||
@@ -505,21 +511,20 @@ source address specified but the port may be specified directly as
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
.TP
|
||||
.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
.B --rev-server=<ip-address>[/<prefix-len>][,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
This is functionally the same as
|
||||
.B --server,
|
||||
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
|
||||
.B --rev-server=1.2.3.0/24,192.168.0.1
|
||||
is exactly equivalent to
|
||||
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
|
||||
Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is omitted, dnsmasq substitutes either 32 (IPv4) or 128 (IPv6).
|
||||
.TP
|
||||
.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
|
||||
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
|
||||
@@ -549,6 +554,15 @@ These IP sets must already exist. See
|
||||
.BR ipset (8)
|
||||
for more details.
|
||||
.TP
|
||||
.B --nftset=/<domain>[/<domain>...]/[(6|4)#[<family>#]<table>#<set>[,[(6|4)#[<family>#]<table>#<set>]...]
|
||||
Similar to the \fB--ipset\fP option, but accepts one or more nftables
|
||||
sets to add IP addresses into.
|
||||
These sets must already exist. See
|
||||
.BR nft (8)
|
||||
for more details. The family, table and set are passed directly to the nft. If the spec starts with 4# or 6# then
|
||||
only A or AAAA records respectively are added to the set. Since an nftset can hold only IPv4 or IPv6 addresses, this
|
||||
avoids errors being logged for addresses of the wrong type.
|
||||
.TP
|
||||
.B --connmark-allowlist-enable[=<mask>]
|
||||
Enables filtering of incoming DNS queries with associated Linux connection track marks
|
||||
according to individual allowlists configured via a series of \fB--connmark-allowlist\fP
|
||||
@@ -752,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.
|
||||
@@ -1036,7 +1051,7 @@ is also included, as described in RFC-3775 section 7.3.
|
||||
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
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
|
||||
@@ -1135,7 +1150,10 @@ ignore requests from unknown machines using
|
||||
If the host matches only a \fB--dhcp-host\fP directive which cannot
|
||||
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
|
||||
|
||||
The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
|
||||
The tag:<tag> construct filters which dhcp-host directives are used; more than
|
||||
one can be provided, in this case the request must match all of them. Tagged
|
||||
directives are used in preference to untagged ones. Note that one of <hwaddr>,
|
||||
<client_id> or <hostname> still needs to be specified (can be a wildcard).
|
||||
|
||||
Ethernet addresses (but not client-ids) may have
|
||||
wildcard bytes, so for example
|
||||
@@ -1309,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
|
||||
@@ -1317,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
|
||||
@@ -1340,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
|
||||
@@ -1750,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
|
||||
@@ -1923,7 +1955,6 @@ additional flag "local" may be supplied which has the effect of adding
|
||||
is identical to
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
.B --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
|
||||
|
||||
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
|
||||
|
||||
50
src/auth.c
50
src/auth.c
@@ -210,7 +210,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (local_query || in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -234,7 +234,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
@@ -243,7 +243,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
@@ -257,7 +257,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL);
|
||||
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
|
||||
found = 1;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -269,7 +269,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -300,7 +300,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
anscount++;
|
||||
@@ -315,7 +315,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -349,7 +349,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -363,7 +363,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -377,7 +377,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
@@ -407,7 +407,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &addrlist->addr))
|
||||
@@ -417,10 +417,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!found && is_name_synthetic(flag, name, &addr) )
|
||||
{
|
||||
found = 1;
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
@@ -433,8 +432,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (qtype == T_SOA)
|
||||
{
|
||||
auth = soa = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
{
|
||||
@@ -469,16 +467,14 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
soa = 1; /* inhibits auth section */
|
||||
ns = 1; /* ensure we include NS records! */
|
||||
axfr = 1;
|
||||
found = 1;
|
||||
axfroffset = nameoffset;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
|
||||
}
|
||||
else if (qtype == T_NS)
|
||||
{
|
||||
auth = 1;
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,9 +492,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
(local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
*cut = 0; /* remove domain part */
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
@@ -518,8 +513,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
@@ -566,7 +560,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (candidate)
|
||||
{
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
|
||||
strcpy(name, candidate->target);
|
||||
if (!strchr(name, '.'))
|
||||
{
|
||||
@@ -584,7 +578,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
else if (cache_find_non_terminal(name, now))
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -614,7 +608,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -627,7 +621,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
sprintf(p, "ip6.arpa");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -892,7 +886,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
header->nscount = htons(0);
|
||||
addr.log.rcode = REFUSED;
|
||||
addr.log.ede = EDE_NOT_AUTH;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL);
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
|
||||
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ void blockdata_init(void)
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
|
||||
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
|
||||
blockdata_count * sizeof(struct blockdata),
|
||||
blockdata_hwm * sizeof(struct blockdata),
|
||||
blockdata_alloced * sizeof(struct blockdata));
|
||||
|
||||
161
src/cache.c
161
src/cache.c
@@ -30,50 +30,100 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
||||
time_t now, unsigned long ttl, unsigned int flags);
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
/* taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml */
|
||||
static const struct {
|
||||
unsigned int type;
|
||||
const char * const name;
|
||||
} typestr[] = {
|
||||
{ 1, "A" },
|
||||
{ 2, "NS" },
|
||||
{ 5, "CNAME" },
|
||||
{ 6, "SOA" },
|
||||
{ 10, "NULL" },
|
||||
{ 11, "WKS" },
|
||||
{ 12, "PTR" },
|
||||
{ 13, "HINFO" },
|
||||
{ 15, "MX" },
|
||||
{ 16, "TXT" },
|
||||
{ 22, "NSAP" },
|
||||
{ 23, "NSAP_PTR" },
|
||||
{ 24, "SIG" },
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 29, "LOC" },
|
||||
{ 33, "SRV" },
|
||||
{ 35, "NAPTR" },
|
||||
{ 36, "KX" },
|
||||
{ 37, "CERT" },
|
||||
{ 38, "A6" },
|
||||
{ 39, "DNAME" },
|
||||
{ 41, "OPT" },
|
||||
{ 43, "DS" },
|
||||
{ 46, "RRSIG" },
|
||||
{ 47, "NSEC" },
|
||||
{ 48, "DNSKEY" },
|
||||
{ 50, "NSEC3" },
|
||||
{ 51, "NSEC3PARAM" },
|
||||
{ 52, "TLSA" },
|
||||
{ 53, "SMIMEA" },
|
||||
{ 55, "HIP" },
|
||||
{ 249, "TKEY" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
{ 252, "AXFR" },
|
||||
{ 253, "MAILB" },
|
||||
{ 254, "MAILA" },
|
||||
{ 255, "ANY" },
|
||||
{ 257, "CAA" }
|
||||
{ 1, "A" }, /* a host address [RFC1035] */
|
||||
{ 2, "NS" }, /* an authoritative name server [RFC1035] */
|
||||
{ 3, "MD" }, /* a mail destination (OBSOLETE - use MX) [RFC1035] */
|
||||
{ 4, "MF" }, /* a mail forwarder (OBSOLETE - use MX) [RFC1035] */
|
||||
{ 5, "CNAME" }, /* the canonical name for an alias [RFC1035] */
|
||||
{ 6, "SOA" }, /* marks the start of a zone of authority [RFC1035] */
|
||||
{ 7, "MB" }, /* a mailbox domain name (EXPERIMENTAL) [RFC1035] */
|
||||
{ 8, "MG" }, /* a mail group member (EXPERIMENTAL) [RFC1035] */
|
||||
{ 9, "MR" }, /* a mail rename domain name (EXPERIMENTAL) [RFC1035] */
|
||||
{ 10, "NULL" }, /* a null RR (EXPERIMENTAL) [RFC1035] */
|
||||
{ 11, "WKS" }, /* a well known service description [RFC1035] */
|
||||
{ 12, "PTR" }, /* a domain name pointer [RFC1035] */
|
||||
{ 13, "HINFO" }, /* host information [RFC1035] */
|
||||
{ 14, "MINFO" }, /* mailbox or mail list information [RFC1035] */
|
||||
{ 15, "MX" }, /* mail exchange [RFC1035] */
|
||||
{ 16, "TXT" }, /* text strings [RFC1035] */
|
||||
{ 17, "RP" }, /* for Responsible Person [RFC1183] */
|
||||
{ 18, "AFSDB" }, /* for AFS Data Base location [RFC1183][RFC5864] */
|
||||
{ 19, "X25" }, /* for X.25 PSDN address [RFC1183] */
|
||||
{ 20, "ISDN" }, /* for ISDN address [RFC1183] */
|
||||
{ 21, "RT" }, /* for Route Through [RFC1183] */
|
||||
{ 22, "NSAP" }, /* for NSAP address, NSAP style A record [RFC1706] */
|
||||
{ 23, "NSAP_PTR" }, /* for domain name pointer, NSAP style [RFC1348][RFC1637][RFC1706] */
|
||||
{ 24, "SIG" }, /* for security signature [RFC2535][RFC2536][RFC2537][RFC2931][RFC3008][RFC3110][RFC3755][RFC4034] */
|
||||
{ 25, "KEY" }, /* for security key [RFC2535][RFC2536][RFC2537][RFC2539][RFC3008][RFC3110][RFC3755][RFC4034] */
|
||||
{ 26, "PX" }, /* X.400 mail mapping information [RFC2163] */
|
||||
{ 27, "GPOS" }, /* Geographical Position [RFC1712] */
|
||||
{ 28, "AAAA" }, /* IP6 Address [RFC3596] */
|
||||
{ 29, "LOC" }, /* Location Information [RFC1876] */
|
||||
{ 30, "NXT" }, /* Next Domain (OBSOLETE) [RFC2535][RFC3755] */
|
||||
{ 31, "EID" }, /* Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
|
||||
{ 32, "NIMLOC" }, /* Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
|
||||
{ 33, "SRV" }, /* Server Selection [1][RFC2782] */
|
||||
{ 34, "ATMA" }, /* ATM Address [ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.] */
|
||||
{ 35, "NAPTR" }, /* Naming Authority Pointer [RFC2168][RFC2915][RFC3403] */
|
||||
{ 36, "KX" }, /* Key Exchanger [RFC2230] */
|
||||
{ 37, "CERT" }, /* CERT [RFC4398] */
|
||||
{ 38, "A6" }, /* A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563] */
|
||||
{ 39, "DNAME" }, /* DNAME [RFC6672] */
|
||||
{ 40, "SINK" }, /* SINK [Donald_E_Eastlake][http://tools.ietf.org/html/draft-eastlake-kitchen-sink] 1997-11*/
|
||||
{ 41, "OPT" }, /* OPT [RFC3225][RFC6891] */
|
||||
{ 42, "APL" }, /* APL [RFC3123] */
|
||||
{ 43, "DS" }, /* Delegation Signer [RFC3658][RFC4034] */
|
||||
{ 44, "SSHFP" }, /* SSH Key Fingerprint [RFC4255] */
|
||||
{ 45, "IPSECKEY" }, /* IPSECKEY [RFC4025] */
|
||||
{ 46, "RRSIG" }, /* RRSIG [RFC3755][RFC4034] */
|
||||
{ 47, "NSEC" }, /* NSEC [RFC3755][RFC4034][RFC9077] */
|
||||
{ 48, "DNSKEY" }, /* DNSKEY [RFC3755][RFC4034] */
|
||||
{ 49, "DHCID" }, /* DHCID [RFC4701] */
|
||||
{ 50, "NSEC3" }, /* NSEC3 [RFC5155][RFC9077] */
|
||||
{ 51, "NSEC3PARAM" }, /* NSEC3PARAM [RFC5155] */
|
||||
{ 52, "TLSA" }, /* TLSA [RFC6698] */
|
||||
{ 53, "SMIMEA" }, /* S/MIME cert association [RFC8162] SMIMEA/smimea-completed-template 2015-12-01*/
|
||||
{ 55, "HIP" }, /* Host Identity Protocol [RFC8005] */
|
||||
{ 56, "NINFO" }, /* NINFO [Jim_Reid] NINFO/ninfo-completed-template 2008-01-21*/
|
||||
{ 57, "RKEY" }, /* RKEY [Jim_Reid] RKEY/rkey-completed-template 2008-01-21*/
|
||||
{ 58, "TALINK" }, /* Trust Anchor LINK [Wouter_Wijngaards] TALINK/talink-completed-template 2010-02-17*/
|
||||
{ 59, "CDS" }, /* Child DS [RFC7344] CDS/cds-completed-template 2011-06-06*/
|
||||
{ 60, "CDNSKEY" }, /* DNSKEY(s) the Child wants reflected in DS [RFC7344] 2014-06-16*/
|
||||
{ 61, "OPENPGPKEY" }, /* OpenPGP Key [RFC7929] OPENPGPKEY/openpgpkey-completed-template 2014-08-12*/
|
||||
{ 62, "CSYNC" }, /* Child-To-Parent Synchronization [RFC7477] 2015-01-27*/
|
||||
{ 63, "ZONEMD" }, /* Message Digest Over Zone Data [RFC8976] ZONEMD/zonemd-completed-template 2018-12-12*/
|
||||
{ 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/
|
||||
{ 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/
|
||||
{ 99, "SPF" }, /* [RFC7208] */
|
||||
{ 100, "UINFO" }, /* [IANA-Reserved] */
|
||||
{ 101, "UID" }, /* [IANA-Reserved] */
|
||||
{ 102, "GID" }, /* [IANA-Reserved] */
|
||||
{ 103, "UNSPEC" }, /* [IANA-Reserved] */
|
||||
{ 104, "NID" }, /* [RFC6742] ILNP/nid-completed-template */
|
||||
{ 105, "L32" }, /* [RFC6742] ILNP/l32-completed-template */
|
||||
{ 106, "L64" }, /* [RFC6742] ILNP/l64-completed-template */
|
||||
{ 107, "LP" }, /* [RFC6742] ILNP/lp-completed-template */
|
||||
{ 108, "EUI48" }, /* an EUI-48 address [RFC7043] EUI48/eui48-completed-template 2013-03-27*/
|
||||
{ 109, "EUI64" }, /* an EUI-64 address [RFC7043] EUI64/eui64-completed-template 2013-03-27*/
|
||||
{ 249, "TKEY" }, /* Transaction Key [RFC2930] */
|
||||
{ 250, "TSIG" }, /* Transaction Signature [RFC8945] */
|
||||
{ 251, "IXFR" }, /* incremental transfer [RFC1995] */
|
||||
{ 252, "AXFR" }, /* transfer of an entire zone [RFC1035][RFC5936] */
|
||||
{ 253, "MAILB" }, /* mailbox-related RRs (MB, MG or MR) [RFC1035] */
|
||||
{ 254, "MAILA" }, /* mail agent RRs (OBSOLETE - see MX) [RFC1035] */
|
||||
{ 255, "ANY" }, /* A request for some or all records the server has available [RFC1035][RFC6895][RFC8482] */
|
||||
{ 256, "URI" }, /* URI [RFC7553] URI/uri-completed-template 2011-02-22*/
|
||||
{ 257, "CAA" }, /* Certification Authority Restriction [RFC8659] CAA/caa-completed-template 2011-04-07*/
|
||||
{ 258, "AVC" }, /* Application Visibility and Control [Wolfgang_Riedel] AVC/avc-completed-template 2016-02-26*/
|
||||
{ 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/
|
||||
{ 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/
|
||||
{ 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/
|
||||
{ 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */
|
||||
};
|
||||
|
||||
static void cache_free(struct crec *crecp);
|
||||
@@ -363,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))
|
||||
@@ -433,7 +483,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
|
||||
(flags & crecp->flags & F_REVERSE) &&
|
||||
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
addr && memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
@@ -1349,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;
|
||||
@@ -1547,7 +1599,8 @@ static void make_non_terminals(struct crec *source)
|
||||
if (crecp)
|
||||
{
|
||||
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
|
||||
crecp->ttd = source->ttd;
|
||||
if (!(crecp->flags & F_IMMORTAL))
|
||||
crecp->ttd = source->ttd;
|
||||
crecp->name.namep = name;
|
||||
|
||||
cache_hash(crecp);
|
||||
@@ -1805,7 +1858,7 @@ char *record_source(unsigned int index)
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
char *querystr(char *desc, unsigned short type)
|
||||
static char *querystr(char *desc, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
int len = 10; /* strlen("type=xxxxx") */
|
||||
@@ -1893,7 +1946,7 @@ static char *edestr(int ede)
|
||||
}
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type)
|
||||
{
|
||||
char *source, *dest = arg;
|
||||
char *verb = "is";
|
||||
@@ -1901,7 +1954,11 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
|
||||
/* build query type string if requested */
|
||||
if(type > 0)
|
||||
arg = querystr(arg, type);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG))
|
||||
extra = " (DNSSEC signed)";
|
||||
@@ -2005,7 +2062,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = "ipset add";
|
||||
source = type ? "ipset add" : "nftset add";
|
||||
dest = name;
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
@@ -2013,7 +2070,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
if (strlen(name) == 0)
|
||||
if (name && !name[0])
|
||||
name = ".";
|
||||
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
|
||||
10
src/config.h
10
src/config.h
@@ -115,6 +115,10 @@ HAVE_IPSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given ipsets.
|
||||
|
||||
HAVE_NFTSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given nftables sets.
|
||||
|
||||
HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
@@ -192,7 +196,7 @@ RESOLVFILE
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_CRYPTOHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
/* #define HAVE_NFTSET */
|
||||
|
||||
/* Default locations for important system files. */
|
||||
|
||||
@@ -420,6 +424,10 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"ipset "
|
||||
#ifndef HAVE_NFTSET
|
||||
"no-"
|
||||
#endif
|
||||
"nftset "
|
||||
#ifndef HAVE_AUTH
|
||||
"no-"
|
||||
#endif
|
||||
|
||||
21
src/dbus.c
21
src/dbus.c
@@ -114,7 +114,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
|
||||
w->next = daemon->watches;
|
||||
daemon->watches = w;
|
||||
|
||||
w = data; /* no warning */
|
||||
(void)data; /* no warning */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -134,16 +134,20 @@ static void remove_watch(DBusWatch *watch, void *data)
|
||||
up = &(w->next);
|
||||
}
|
||||
|
||||
w = data; /* no warning */
|
||||
(void)data; /* no warning */
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
static DBusMessage* dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
union mysockaddr addr, source_addr;
|
||||
char *domain;
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
}
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
@@ -222,6 +226,7 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
cleanup_servers();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
@@ -545,6 +550,10 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
if (hw_len < 0)
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid HW address '%s'", hwaddr);
|
||||
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
@@ -668,7 +677,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
#endif
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
dbus_read_servers(message);
|
||||
reply = dbus_read_servers(message);
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
@@ -719,7 +728,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
if (clear_cache)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
|
||||
method = user_data; /* no warning */
|
||||
(void)user_data; /* no warning */
|
||||
|
||||
/* If no reply or no error, return nothing */
|
||||
if (!reply)
|
||||
|
||||
@@ -88,7 +88,7 @@ int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
const int check_len = strlen(check->net);
|
||||
const int is_wc = (check->net[check_len - 1] == '*');
|
||||
const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
|
||||
|
||||
/* '#' for not is for backwards compat. */
|
||||
if (check->net[0] != '!' && check->net[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))));
|
||||
@@ -292,7 +291,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
|
||||
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
|
||||
break;
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
|
||||
while(retry_send(sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr))));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000; /* 100ms */
|
||||
|
||||
@@ -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;
|
||||
@@ -34,7 +39,6 @@ static void poll_resolv(int force, int do_reload, time_t now);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int bind_fallback = 0;
|
||||
time_t now;
|
||||
struct sigaction sigact;
|
||||
struct iname *if_tmp;
|
||||
@@ -59,6 +63,8 @@ int main (int argc, char **argv)
|
||||
int did_bind = 0;
|
||||
struct server *serv;
|
||||
char *netlink_warn;
|
||||
#else
|
||||
int bind_fallback = 0;
|
||||
#endif
|
||||
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
|
||||
struct dhcp_context *context;
|
||||
@@ -68,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
|
||||
@@ -345,6 +353,16 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (daemon->nftsets)
|
||||
{
|
||||
nftset_init();
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
need_cap_net_admin = 1;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
netlink_warn = netlink_init();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
@@ -377,7 +395,7 @@ int main (int argc, char **argv)
|
||||
bindtodevice(bound_device, daemon->dhcpfd);
|
||||
did_bind = 1;
|
||||
}
|
||||
if (daemon->enable_pxe && bound_device)
|
||||
if (daemon->enable_pxe && bound_device && daemon->pxefd != -1)
|
||||
{
|
||||
bindtodevice(bound_device, daemon->pxefd);
|
||||
did_bind = 1;
|
||||
@@ -716,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
|
||||
@@ -920,8 +942,10 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
|
||||
daemon->log_file, strerror(log_err));
|
||||
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
warn_bound_listeners();
|
||||
@@ -1119,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
|
||||
@@ -1575,7 +1603,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
/* block in writes until all done */
|
||||
if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
|
||||
fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
|
||||
while(retry_send(fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK)));
|
||||
do {
|
||||
helper_write();
|
||||
} while (!helper_buf_empty() || do_script_run(now));
|
||||
@@ -1669,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)
|
||||
{
|
||||
@@ -1984,7 +2017,7 @@ static void check_dns_listeners(time_t now)
|
||||
attribute from the listening socket.
|
||||
Reset that here. */
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
||||
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
|
||||
@@ -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) )
|
||||
@@ -530,23 +532,23 @@ union mysockaddr {
|
||||
|
||||
|
||||
/* The actual values here matter, since we sort on them to get records in the order
|
||||
IPv6 addr, IPv4 addr, all zero return, no-data return, send upstream. */
|
||||
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next three flags */
|
||||
#define SERV_ALL_ZEROS 2 /* return all zeros for A and AAAA */
|
||||
#define SERV_4ADDR 4 /* addr is IPv4 */
|
||||
#define SERV_6ADDR 8 /* addr is IPv6 */
|
||||
#define SERV_HAS_SOURCE 16 /* source address defined */
|
||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||
#define SERV_MARK 256 /* for mark-and-delete and log code */
|
||||
#define SERV_WILDCARD 512 /* domain has leading '*' */
|
||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||
IPv6 addr, IPv4 addr, all zero return, resolvconf servers, upstream server, no-data return */
|
||||
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */
|
||||
#define SERV_USE_RESOLV 2 /* forward this domain in the normal way */
|
||||
#define SERV_ALL_ZEROS 4 /* return all zeros for A and AAAA */
|
||||
#define SERV_4ADDR 8 /* addr is IPv4 */
|
||||
#define SERV_6ADDR 16 /* addr is IPv6 */
|
||||
#define SERV_HAS_SOURCE 32 /* source address defined */
|
||||
#define SERV_FOR_NODOTS 64 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 128 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 256 /* 1 if source is DBus */
|
||||
#define SERV_MARK 512 /* for mark-and-delete and log code */
|
||||
#define SERV_WILDCARD 1024 /* domain has leading '*' */
|
||||
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -609,6 +611,11 @@ struct serv_local {
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
struct rebind_domain {
|
||||
char *domain;
|
||||
struct rebind_domain *next;
|
||||
};
|
||||
|
||||
struct ipsets {
|
||||
char **sets;
|
||||
char *domain;
|
||||
@@ -771,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 */
|
||||
@@ -1069,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;
|
||||
};
|
||||
|
||||
@@ -1105,10 +1120,11 @@ extern struct daemon {
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||
struct bogus_addr *bogus_addr, *ignore_addr;
|
||||
struct server *servers, *local_domains, **serverarray, *no_rebind;
|
||||
struct server *servers, *servers_tail, *local_domains, **serverarray;
|
||||
struct rebind_domain *no_rebind;
|
||||
int server_has_wildcard;
|
||||
int serverarraysz, serverarrayhwm;
|
||||
struct ipsets *ipsets;
|
||||
struct ipsets *ipsets, *nftsets;
|
||||
u32 allowlist_mask;
|
||||
struct allowlist *allowlists;
|
||||
int log_fac; /* log facility */
|
||||
@@ -1167,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;
|
||||
@@ -1216,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 */
|
||||
@@ -1245,9 +1269,8 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void next_uid(struct crec *crecp);
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg);
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
int cache_find_non_terminal(char *name, time_t now);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
union all_addr *addr, time_t now,
|
||||
@@ -1298,8 +1321,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored);
|
||||
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
|
||||
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
||||
#endif
|
||||
@@ -1366,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);
|
||||
@@ -1583,6 +1607,12 @@ void ipset_init(void);
|
||||
int add_to_ipset(const char *setname, const union all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* nftset.c */
|
||||
#ifdef HAVE_NFTSET
|
||||
void nftset_init(void);
|
||||
int add_to_nftset(const char *setpath, const union all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* pattern.c */
|
||||
#ifdef HAVE_CONNTRACK
|
||||
int is_valid_dns_name(const char *value);
|
||||
@@ -1602,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 */
|
||||
@@ -1647,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 */
|
||||
@@ -1735,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);
|
||||
|
||||
23
src/dnssec.c
23
src/dnssec.c
@@ -724,7 +724,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
|
||||
/* namebuff used for workspace above, restore to leave unchanged on exit */
|
||||
p = (unsigned char*)(rrset[0]);
|
||||
extract_name(header, plen, &p, name, 1, 0);
|
||||
if (!extract_name(header, plen, &p, name, 1, 0))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (key)
|
||||
{
|
||||
@@ -954,9 +955,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
a.log.keytag = keytag;
|
||||
a.log.algo = algo;
|
||||
if (algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -973,7 +974,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY", 0);
|
||||
return STAT_BOGUS | failflags;
|
||||
}
|
||||
|
||||
@@ -1012,12 +1013,14 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
extract_name(header, plen, &p, name, 1, 4);
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_BOGUS;
|
||||
|
||||
p += 4; /* qtype, qclass */
|
||||
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
@@ -1025,7 +1028,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
from the DS's zone, and not the parent zone. */
|
||||
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS", 0);
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
@@ -1081,9 +1084,9 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
a.log.algo = algo;
|
||||
a.log.digest = digest;
|
||||
if (ds_digest_name(digest) && algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,7 +1119,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
|
||||
}
|
||||
|
||||
return STAT_OK;
|
||||
|
||||
@@ -207,16 +207,16 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
if (found && filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* We have a match, but it may only be (say) an IPv6 address, and
|
||||
if the query wasn't for an AAAA record, it's no good, and we need
|
||||
to continue generalising */
|
||||
{
|
||||
/* We've matched a setting which says to use servers without a domain.
|
||||
Continue the search with empty query */
|
||||
if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
|
||||
if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
|
||||
crop_query = qlen;
|
||||
else if (filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* We have a match, but it may only be (say) an IPv6 address, and
|
||||
if the query wasn't for an AAAA record, it's no good, and we need
|
||||
to continue generalising */
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,7 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
nlow--;
|
||||
|
||||
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
|
||||
nhigh++;
|
||||
nhigh++;
|
||||
|
||||
nhigh++;
|
||||
|
||||
@@ -293,10 +293,10 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
else
|
||||
{
|
||||
/* Now the servers are on order between low and high, in the order
|
||||
IPv6 addr, IPv4 addr, return zero for both, send upstream, no-data return.
|
||||
IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
|
||||
|
||||
See which of those match our query in that priority order and narrow (low, high) */
|
||||
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
|
||||
|
||||
if (i != nlow && (flags & F_IPV6))
|
||||
@@ -321,32 +321,40 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
/* Short to resolv.conf servers */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing, similarly if were looking only for a server
|
||||
for a particular domain. */
|
||||
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||
nlow = nhigh;
|
||||
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nhigh = i;
|
||||
}
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
|
||||
nhigh = i;
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing, similarly if were looking only for a server
|
||||
for a particular domain. */
|
||||
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||
nlow = nhigh;
|
||||
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nhigh = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
|
||||
nhigh = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*lowout = nlow;
|
||||
*highout = nhigh;
|
||||
|
||||
@@ -387,13 +395,13 @@ 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;
|
||||
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
||||
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
@@ -410,9 +418,9 @@ 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);
|
||||
add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr);
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
if (flags & gotname & F_IPV6)
|
||||
@@ -425,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);
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -485,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)
|
||||
@@ -520,10 +529,10 @@ static int order_qsort(const void *a, const void *b)
|
||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||
in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
|
||||
so the order is IPv6 literal, IPv4 literal, all-zero literal,
|
||||
upstream server, NXDOMAIN literal. */
|
||||
unqualified servers, upstream server, NXDOMAIN literal. */
|
||||
if (rc == 0)
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
|
||||
|
||||
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||
if (rc == 0)
|
||||
@@ -533,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)
|
||||
@@ -556,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)
|
||||
@@ -567,21 +593,11 @@ void cleanup_servers(void)
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
{
|
||||
up = &serv->next;
|
||||
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,
|
||||
@@ -609,82 +625,90 @@ int add_update_server(int flags,
|
||||
|
||||
if (*domain == 0)
|
||||
alloc_domain = whine_malloc(1);
|
||||
else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
|
||||
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
|
||||
alloc_domain = canonicalise((char *)domain, NULL);
|
||||
|
||||
if (!alloc_domain)
|
||||
return 0;
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
serv->next = daemon->local_domains;
|
||||
daemon->local_domains = serv;
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 (serv)
|
||||
{
|
||||
free(alloc_domain);
|
||||
alloc_domain = serv->domain;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct server *s;
|
||||
/* Add to the end of the chain, for order */
|
||||
if (!daemon->servers)
|
||||
daemon->servers = serv;
|
||||
else
|
||||
if (!(serv = whine_malloc(sizeof(struct server))))
|
||||
{
|
||||
for (s = daemon->servers; s->next; s = s->next);
|
||||
s->next = serv;
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
serv->next = NULL;
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
/* Add to the end of the chain, for order */
|
||||
if (daemon->servers_tail)
|
||||
daemon->servers_tail->next = serv;
|
||||
else
|
||||
daemon->servers = serv;
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & SERV_IS_LOCAL))
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
serv->flags = flags;
|
||||
serv->domain = alloc_domain;
|
||||
serv->domain_len = strlen(alloc_domain);
|
||||
|
||||
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 (!(flags & SERV_IS_LOCAL))
|
||||
{
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
@@ -692,7 +716,11 @@ int add_update_server(int flags,
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
|
||||
|
||||
serv->flags = flags;
|
||||
serv->domain = alloc_domain;
|
||||
serv->domain_len = strlen(alloc_domain);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
168
src/forward.c
168
src/forward.c
@@ -119,12 +119,12 @@ static void set_outgoing_mark(struct frec *forward, int fd)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg)
|
||||
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg, unsigned short type)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg);
|
||||
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg, type);
|
||||
else
|
||||
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg);
|
||||
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg, type);
|
||||
}
|
||||
|
||||
static void server_send(struct server *server, int fd,
|
||||
@@ -138,25 +138,35 @@ static void server_send(struct server *server, int fd,
|
||||
#ifdef HAVE_DNSSEC
|
||||
static void server_send_log(struct server *server, int fd,
|
||||
const void *header, size_t plen, int dumpflags,
|
||||
unsigned int logflags, char *name, char *arg)
|
||||
unsigned int logflags, char *name, char *arg,
|
||||
unsigned short type)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
|
||||
#endif
|
||||
log_query_mysockaddr(logflags, name, &server->addr, arg);
|
||||
log_query_mysockaddr(logflags, name, &server->addr, arg, type);
|
||||
server_send(server, fd, header, plen, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int domain_no_rebind(char *domain)
|
||||
{
|
||||
struct server *serv;
|
||||
int dlen = (int)strlen(domain);
|
||||
|
||||
for (serv = daemon->no_rebind; serv; serv = serv->next)
|
||||
if (dlen >= serv->domain_len && strcmp(serv->domain, &domain[dlen - serv->domain_len]) == 0)
|
||||
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)) &&
|
||||
hostname_isequal(rbd->domain, &domain[dlen - tlen]) &&
|
||||
(dlen == tlen || domain[dlen - tlen - 1] == '.'))
|
||||
return 1;
|
||||
|
||||
if (tlen == 0 && !dots)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -169,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;
|
||||
@@ -198,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)))
|
||||
@@ -211,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
|
||||
@@ -282,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;
|
||||
@@ -325,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...... */
|
||||
@@ -336,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. */
|
||||
@@ -375,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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,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)
|
||||
{
|
||||
@@ -494,12 +520,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (!gotname)
|
||||
strcpy(daemon->namebuff, "query");
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
|
||||
&srv->addr, NULL);
|
||||
&srv->addr, NULL, 0);
|
||||
}
|
||||
#ifdef HAVE_DNSSEC
|
||||
else
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, daemon->namebuff, &srv->addr,
|
||||
querystr("dnssec-retry", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS));
|
||||
"dnssec-retry", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS);
|
||||
#endif
|
||||
|
||||
srv->queries++;
|
||||
@@ -555,12 +581,33 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domain) {
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos, *ret = NULL;
|
||||
unsigned int namelen = strlen(domain);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = setlist; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
{
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
const char *matchstart = domain + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen)
|
||||
{
|
||||
matchlen = domainlen;
|
||||
ret = ipset_pos;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
|
||||
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
|
||||
int check_subnet, union mysockaddr *query_source, unsigned char *limit, int ede)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
struct ipsets *ipsets = NULL, *nftsets = NULL;
|
||||
int munged = 0, is_sign;
|
||||
unsigned int rcode = RCODE(header);
|
||||
size_t plen;
|
||||
@@ -571,24 +618,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
{
|
||||
/* Similar algorithm to search_servers. */
|
||||
struct ipsets *ipset_pos;
|
||||
unsigned int namelen = strlen(daemon->namebuff);
|
||||
unsigned int matchlen = 0;
|
||||
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
|
||||
{
|
||||
unsigned int domainlen = strlen(ipset_pos->domain);
|
||||
char *matchstart = daemon->namebuff + namelen - domainlen;
|
||||
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
|
||||
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
|
||||
domainlen >= matchlen)
|
||||
{
|
||||
matchlen = domainlen;
|
||||
sets = ipset_pos->sets;
|
||||
}
|
||||
}
|
||||
}
|
||||
ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (daemon->nftsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
nftsets = domain_find_sets(daemon->nftsets, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
@@ -607,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
|
||||
@@ -653,7 +688,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
union all_addr a;
|
||||
a.log.rcode = rcode;
|
||||
a.log.ede = ede;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL, 0);
|
||||
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
}
|
||||
@@ -696,8 +731,18 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
cache_secure = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
|
||||
|
||||
/* 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);
|
||||
munged = 1;
|
||||
@@ -726,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
|
||||
|
||||
@@ -750,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;
|
||||
}
|
||||
|
||||
@@ -889,7 +934,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
#endif
|
||||
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
|
||||
F_NOEXTRA | F_DNSSEC, daemon->keyname,
|
||||
querystr("dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
"dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||
server->queries++;
|
||||
}
|
||||
|
||||
@@ -1136,7 +1181,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
log_query(F_SECSTAT, domain, &a, result);
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1202,7 +1247,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
{
|
||||
daemon->log_display_id = src->log_id;
|
||||
daemon->log_source_addr = &src->source;
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate");
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1509,10 +1554,8 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#ifdef HAVE_AUTH
|
||||
struct auth_zone *zone;
|
||||
#endif
|
||||
char *types = querystr(auth_dns ? "auth" : "query", type);
|
||||
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&source_addr, types);
|
||||
&source_addr, auth_dns ? "auth" : "query", type);
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
is_single_query = 1;
|
||||
@@ -1808,7 +1851,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
daemon->log_display_id = ++daemon->log_id;
|
||||
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
|
||||
querystr("dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
"dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||
|
||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
||||
|
||||
@@ -1864,7 +1907,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
int first, last;
|
||||
unsigned int flags = 0;
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
@@ -1946,11 +1989,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_AUTH
|
||||
struct auth_zone *zone;
|
||||
#endif
|
||||
char *types = querystr(auth_dns ? "auth" : "query", qtype);
|
||||
|
||||
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, types);
|
||||
|
||||
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
is_single_query = 1;
|
||||
#endif
|
||||
@@ -2089,7 +2131,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
strcpy(daemon->namebuff, "query");
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL);
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (master->flags & SERV_DO_DNSSEC))
|
||||
@@ -2121,7 +2163,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
log_query(F_SECSTAT, domain, &a, result);
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2276,7 +2318,7 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
|
||||
}
|
||||
}
|
||||
|
||||
if (j == daemon->numrrand)
|
||||
if (!rfd) /* should be when j == daemon->numrrand */
|
||||
{
|
||||
struct randfd_list *rfl_poll;
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -148,12 +148,19 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
|
||||
if (!(ah->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
|
||||
if (stat(ah->fname, &buf) == -1)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, _("not a directory"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ah->flags & AH_WD_DONE))
|
||||
{
|
||||
|
||||
@@ -1586,6 +1586,9 @@ void check_servers(int no_loop_check)
|
||||
if (serv->sfd)
|
||||
serv->sfd->used = 1;
|
||||
|
||||
if (count == SERVERS_LOGGED)
|
||||
my_syslog(LOG_INFO, _("more servers are defined but not logged"));
|
||||
|
||||
if (++count > SERVERS_LOGGED)
|
||||
continue;
|
||||
|
||||
@@ -1623,7 +1626,8 @@ void check_servers(int no_loop_check)
|
||||
continue;
|
||||
|
||||
if ((serv->flags & SERV_LITERAL_ADDRESS) &&
|
||||
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)))
|
||||
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)) &&
|
||||
strlen(serv->domain))
|
||||
{
|
||||
count--;
|
||||
if (++locals <= LOCALS_LOGGED)
|
||||
|
||||
94
src/nftset.c
Normal file
94
src/nftset.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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"
|
||||
|
||||
#if defined (HAVE_NFTSET) && defined (HAVE_LINUX_NETWORK)
|
||||
|
||||
#include <nftables/libnftables.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static struct nft_ctx *ctx = NULL;
|
||||
static const char *cmd_add = "add element %s { %s }";
|
||||
static const char *cmd_del = "delete element %s { %s }";
|
||||
|
||||
void nftset_init()
|
||||
{
|
||||
ctx = nft_ctx_new(NFT_CTX_DEFAULT);
|
||||
if (ctx == NULL)
|
||||
die(_("failed to create nftset context"), NULL, EC_MISC);
|
||||
|
||||
/* disable libnftables output */
|
||||
nft_ctx_buffer_error(ctx);
|
||||
}
|
||||
|
||||
int add_to_nftset(const char *setname, const union all_addr *ipaddr, int flags, int remove)
|
||||
{
|
||||
const char *cmd = remove ? cmd_del : cmd_add;
|
||||
int ret, af = (flags & F_IPV4) ? AF_INET : AF_INET6;
|
||||
size_t new_sz;
|
||||
char *new, *err, *nl;
|
||||
static char *cmd_buf = NULL;
|
||||
static size_t cmd_buf_sz = 0;
|
||||
|
||||
inet_ntop(af, ipaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
if (setname[1] == ' ' && (setname[0] == '4' || setname[0] == '6'))
|
||||
{
|
||||
if (setname[0] == '4' && !(flags & F_IPV4))
|
||||
return -1;
|
||||
|
||||
if (setname[0] == '6' && !(flags & F_IPV6))
|
||||
return -1;
|
||||
|
||||
setname += 2;
|
||||
}
|
||||
|
||||
if (cmd_buf_sz == 0)
|
||||
new_sz = 150; /* initial allocation */
|
||||
else
|
||||
new_sz = snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
|
||||
|
||||
if (new_sz > cmd_buf_sz)
|
||||
{
|
||||
if (!(new = whine_malloc(new_sz + 10)))
|
||||
return 0;
|
||||
|
||||
if (cmd_buf)
|
||||
free(cmd_buf);
|
||||
cmd_buf = new;
|
||||
cmd_buf_sz = new_sz + 10;
|
||||
snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
|
||||
}
|
||||
|
||||
ret = nft_run_cmd_from_buffer(ctx, cmd_buf);
|
||||
err = (char *)nft_ctx_get_error_buffer(ctx);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
/* Log only first line of error return. */
|
||||
if ((nl = strchr(err, '\n')))
|
||||
*nl = 0;
|
||||
my_syslog(LOG_ERR, "nftset %s %s", setname, err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
442
src/option.c
442
src/option.c
@@ -174,7 +174,10 @@ struct myoption {
|
||||
#define LOPT_CMARK_ALST_EN 365
|
||||
#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
|
||||
@@ -211,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' },
|
||||
@@ -327,6 +332,7 @@ static const struct myoption opts[] =
|
||||
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
|
||||
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
|
||||
{ "ipset", 1, 0, LOPT_IPSET },
|
||||
{ "nftset", 1, 0, LOPT_NFTSET },
|
||||
{ "connmark-allowlist-enable", 2, 0, LOPT_CMARK_ALST_EN },
|
||||
{ "connmark-allowlist", 1, 0, LOPT_CMARK_ALST },
|
||||
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
||||
@@ -351,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 }
|
||||
};
|
||||
@@ -380,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 },
|
||||
@@ -514,6 +522,7 @@ static struct {
|
||||
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
|
||||
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
|
||||
{ LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
|
||||
{ LOPT_NFTSET, ARG_DUP, "/<domain>[/<domain>...]/<nftset>...", gettext_noop("Specify nftables sets to which matching domains should be added"), NULL },
|
||||
{ LOPT_CMARK_ALST_EN, ARG_ONE, "[=<mask>]", gettext_noop("Enable filtering of DNS queries with connection-track marks."), NULL },
|
||||
{ LOPT_CMARK_ALST, ARG_DUP, "<connmark>[/<mask>][,<pattern>[/<pattern>...]]", gettext_noop("Set allowed DNS patterns for a connection-track mark."), NULL },
|
||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
|
||||
@@ -654,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)
|
||||
@@ -798,7 +807,7 @@ static void do_usage(void)
|
||||
|
||||
if (usage[i].arg)
|
||||
{
|
||||
strcpy(buff, usage[i].arg);
|
||||
safe_strncpy(buff, usage[i].arg, sizeof(buff));
|
||||
for (j = 0; tab[j].handle; j++)
|
||||
if (tab[j].handle == *(usage[i].arg))
|
||||
sprintf(buff, "%d", tab[j].val);
|
||||
@@ -935,52 +944,124 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int domain_rev4(char *domain, struct in_addr addr, int msize)
|
||||
static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int size)
|
||||
{
|
||||
in_addr_t a = ntohl(addr.s_addr);
|
||||
|
||||
*domain = 0;
|
||||
int i, j;
|
||||
char *string;
|
||||
int msize;
|
||||
u16 flags = 0;
|
||||
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
switch (msize)
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
rem = size & 0x7;
|
||||
addrbytes = (32 - size) >> 3;
|
||||
addrbits = (32 - size) & 7;
|
||||
|
||||
if (size > 32 || size < 1)
|
||||
return _("bad IPv4 prefix length");
|
||||
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1);
|
||||
|
||||
size = size & ~0x7;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (8 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
case 32:
|
||||
domain += sprintf(domain, "%u.", a & 0xff);
|
||||
/* fall through */
|
||||
case 24:
|
||||
domain += sprintf(domain, "%d.", (a >> 8) & 0xff);
|
||||
/* fall through */
|
||||
case 16:
|
||||
domain += sprintf(domain, "%d.", (a >> 16) & 0xff);
|
||||
/* fall through */
|
||||
case 8:
|
||||
domain += sprintf(domain, "%d.", (a >> 24) & 0xff);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/8;
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr4)[j];
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
string += sprintf(string, "%d.", dig);
|
||||
}
|
||||
|
||||
sprintf(string, "in-addr.arpa");
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
|
||||
domain += sprintf(domain, "in-addr.arpa");
|
||||
|
||||
return 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int domain_rev6(char *domain, struct in6_addr *addr, int msize)
|
||||
static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, int size)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
char *string;
|
||||
int msize;
|
||||
u16 flags = 0;
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
int count = 1, rem, addrbytes, addrbits;
|
||||
|
||||
if (msize > 128 || msize%4)
|
||||
return 0;
|
||||
if (!server)
|
||||
flags = SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(server, &serv_addr, &source_addr, interface, &flags)))
|
||||
return string;
|
||||
|
||||
if (from_file)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
*domain = 0;
|
||||
rem = size & 0x3;
|
||||
addrbytes = (128 - size) >> 3;
|
||||
addrbits = (128 - size) & 7;
|
||||
|
||||
if (size > 128 || size < 1)
|
||||
return _("bad IPv6 prefix length");
|
||||
|
||||
/* Zero out last address bits according to CIDR mask */
|
||||
addr6->s6_addr[15-addrbytes] &= ~((1 << addrbits) - 1);
|
||||
|
||||
size = size & ~0x3;
|
||||
|
||||
if (rem != 0)
|
||||
count = 1 << (4 - rem);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*domain = 0;
|
||||
string = domain;
|
||||
msize = size/4;
|
||||
|
||||
for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--)
|
||||
{
|
||||
int dig = ((unsigned char *)addr6)[j>>1];
|
||||
|
||||
dig = j & 1 ? dig & 15 : dig >> 4;
|
||||
|
||||
if (j == msize)
|
||||
dig += i;
|
||||
|
||||
string += sprintf(string, "%.1x.", dig);
|
||||
}
|
||||
|
||||
sprintf(string, "ip6.arpa");
|
||||
|
||||
for (i = msize-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)addr)[i>>3];
|
||||
domain += sprintf(domain, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
return _("error");
|
||||
}
|
||||
domain += sprintf(domain, "ip6.arpa");
|
||||
|
||||
return 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -1829,6 +1910,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = li;
|
||||
*up = new;
|
||||
}
|
||||
else
|
||||
free(path);
|
||||
|
||||
}
|
||||
|
||||
@@ -1995,7 +2078,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (!(name = canonicalise_opt(arg)) ||
|
||||
(comma && !(target = canonicalise_opt(comma))))
|
||||
ret_err(_("bad MX name"));
|
||||
{
|
||||
free(name);
|
||||
free(target);
|
||||
ret_err(_("bad MX name"));
|
||||
}
|
||||
|
||||
new = opt_malloc(sizeof(struct mx_srv_record));
|
||||
new->next = daemon->mxnames;
|
||||
@@ -2146,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;
|
||||
@@ -2302,17 +2391,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
|
||||
ret_err_free(_("bad prefix"), new);
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
else if (strcmp(arg, "local") != 0)
|
||||
ret_err_free(gen_err, new);
|
||||
else
|
||||
{
|
||||
char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
|
||||
/* local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
/* domain_rev4 can't fail here, msize checked above. */
|
||||
domain_rev4(domain, new->start, msize);
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
|
||||
|
||||
domain_rev4(0, NULL, &new->start, msize);
|
||||
|
||||
/* local=/<domain>/ */
|
||||
/* d_raw can't failed to canonicalise here, checked above. */
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
|
||||
@@ -2347,16 +2432,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
|
||||
ret_err_free(_("bad prefix"), new);
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
else if (strcmp(arg, "local") != 0)
|
||||
ret_err_free(gen_err, new);
|
||||
else
|
||||
{
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
/* generate the equivalent of
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
domain_rev6(domain, &new->start6, msize);
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, domain, NULL);
|
||||
|
||||
domain_rev6(0, NULL, &new->start6, msize);
|
||||
|
||||
/* local=/<domain>/ */
|
||||
/* d_raw can't failed to canonicalise here, checked above. */
|
||||
add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
|
||||
@@ -2436,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);
|
||||
@@ -2635,7 +2727,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_NO_REBIND: /* --rebind-domain-ok */
|
||||
{
|
||||
struct server *new;
|
||||
struct rebind_domain *new;
|
||||
|
||||
unhide_metas(arg);
|
||||
|
||||
@@ -2644,9 +2736,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
do {
|
||||
comma = split_chr(arg, '/');
|
||||
new = opt_malloc(sizeof(struct serv_local));
|
||||
new->domain = opt_string_alloc(arg);
|
||||
new->domain_len = strlen(arg);
|
||||
new = opt_malloc(sizeof(struct rebind_domain));
|
||||
new->domain = canonicalise_opt(arg);
|
||||
new->next = daemon->no_rebind;
|
||||
daemon->no_rebind = new;
|
||||
arg = comma;
|
||||
@@ -2708,11 +2799,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
while (1)
|
||||
{
|
||||
/* server=//1.2.3.4 is special. */
|
||||
if (strlen(domain) == 0 && lastdomain)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
else
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
if (lastdomain)
|
||||
{
|
||||
if (strlen(domain) == 0)
|
||||
flags |= SERV_FOR_NODOTS;
|
||||
else
|
||||
flags &= ~SERV_FOR_NODOTS;
|
||||
|
||||
/* address=/#/ matches the same as without domain */
|
||||
if (option == 'A' && domain[0] == '#' && domain[1] == 0)
|
||||
domain[0] = 0;
|
||||
}
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, &addr))
|
||||
ret_err(gen_err);
|
||||
|
||||
@@ -2729,57 +2827,62 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
char *string;
|
||||
int size;
|
||||
u16 flags = 0;
|
||||
char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
union mysockaddr serv_addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
|
||||
unhide_metas(arg);
|
||||
if (!arg)
|
||||
ret_err(gen_err);
|
||||
|
||||
comma=split(arg);
|
||||
|
||||
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
size = -1;
|
||||
|
||||
if (inet_pton(AF_INET, arg, &addr4))
|
||||
{
|
||||
if (!domain_rev4(domain, addr4, size))
|
||||
ret_err(_("bad IPv4 prefix"));
|
||||
if (size == -1)
|
||||
size = 32;
|
||||
|
||||
if ((string = domain_rev4(servers_only, comma, &addr4, size)))
|
||||
ret_err(string);
|
||||
}
|
||||
else if (inet_pton(AF_INET6, arg, &addr6))
|
||||
{
|
||||
if (!domain_rev6(domain, &addr6, size))
|
||||
ret_err(_("bad IPv6 prefix"));
|
||||
if (size == -1)
|
||||
size = 128;
|
||||
|
||||
if ((string = domain_rev6(servers_only, comma, &addr6, size)))
|
||||
ret_err(string);
|
||||
}
|
||||
else
|
||||
ret_err(gen_err);
|
||||
|
||||
if (!comma)
|
||||
flags |= SERV_LITERAL_ADDRESS;
|
||||
else if ((string = parse_server(comma, &serv_addr, &source_addr, interface, &flags)))
|
||||
ret_err(string);
|
||||
|
||||
if (servers_only)
|
||||
flags |= SERV_FROM_FILE;
|
||||
|
||||
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
|
||||
ret_err(gen_err);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_IPSET: /* --ipset */
|
||||
case LOPT_NFTSET: /* --nftset */
|
||||
#ifndef HAVE_IPSET
|
||||
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
|
||||
break;
|
||||
#else
|
||||
if (option == LOPT_IPSET)
|
||||
{
|
||||
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifndef HAVE_NFTSET
|
||||
if (option == LOPT_NFTSET)
|
||||
{
|
||||
ret_err(_("recompile with HAVE_NFTSET defined to enable nftset directives"));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
struct ipsets ipsets_head;
|
||||
struct ipsets *ipsets = &ipsets_head;
|
||||
struct ipsets **daemon_sets =
|
||||
(option == LOPT_IPSET) ? &daemon->ipsets : &daemon->nftsets;
|
||||
int size;
|
||||
char *end;
|
||||
char **sets, **sets_pos;
|
||||
@@ -2824,19 +2927,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
sets = sets_pos = opt_malloc(sizeof(char *) * size);
|
||||
|
||||
do {
|
||||
char *p;
|
||||
end = split(arg);
|
||||
*sets_pos++ = opt_string_alloc(arg);
|
||||
*sets_pos = opt_string_alloc(arg);
|
||||
/* Use '#' to delimit table and set */
|
||||
if (option == LOPT_NFTSET)
|
||||
while ((p = strchr(*sets_pos, '#')))
|
||||
*p = ' ';
|
||||
sets_pos++;
|
||||
arg = end;
|
||||
} while (end);
|
||||
*sets_pos = 0;
|
||||
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
|
||||
ipsets->next->sets = sets;
|
||||
ipsets->next = daemon->ipsets;
|
||||
daemon->ipsets = ipsets_head.next;
|
||||
ipsets->next = *daemon_sets;
|
||||
*daemon_sets = ipsets_head.next;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case LOPT_CMARK_ALST_EN: /* --connmark-allowlist-enable */
|
||||
#ifndef HAVE_CONNTRACK
|
||||
@@ -3616,6 +3724,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
inet_ntop(AF_INET, &in, daemon->addrbuff, ADDRSTRLEN);
|
||||
sprintf(errstr, _("duplicate dhcp-host IP address %s"),
|
||||
daemon->addrbuff);
|
||||
dhcp_config_free(new);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -3779,16 +3888,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_NAME_MATCH: /* --dhcp-name-match */
|
||||
{
|
||||
struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
|
||||
struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
|
||||
struct dhcp_match_name *new;
|
||||
ssize_t len;
|
||||
|
||||
if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
|
||||
ret_err(gen_err);
|
||||
|
||||
new = opt_malloc(sizeof(struct dhcp_match_name));
|
||||
new->wildcard = 0;
|
||||
new->netid = id;
|
||||
id->net = opt_string_alloc(set_prefix(arg));
|
||||
new->netid = opt_malloc(sizeof(struct dhcp_netid));
|
||||
new->netid->net = opt_string_alloc(set_prefix(arg));
|
||||
|
||||
if (comma[len-1] == '*')
|
||||
{
|
||||
@@ -3992,6 +4101,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
|
||||
dhcp_netid_free(new->netid);
|
||||
free(new);
|
||||
ret_err(gen_err);
|
||||
}
|
||||
|
||||
@@ -4026,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)))
|
||||
@@ -4050,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);
|
||||
@@ -4179,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);
|
||||
@@ -4367,7 +4511,7 @@ err:
|
||||
case LOPT_CNAME: /* --cname */
|
||||
{
|
||||
struct cname *new;
|
||||
char *alias, *target, *last, *pen;
|
||||
char *alias, *target=NULL, *last, *pen;
|
||||
int ttl = -1;
|
||||
|
||||
for (last = pen = NULL, comma = arg; comma; comma = split(comma))
|
||||
@@ -4382,13 +4526,13 @@ err:
|
||||
if (pen != arg && atoi_check(last, &ttl))
|
||||
last = pen;
|
||||
|
||||
target = canonicalise_opt(last);
|
||||
|
||||
while (arg != last)
|
||||
{
|
||||
int arglen = strlen(arg);
|
||||
alias = canonicalise_opt(arg);
|
||||
|
||||
if (!target)
|
||||
target = canonicalise_opt(last);
|
||||
if (!alias || !target)
|
||||
{
|
||||
free(target);
|
||||
@@ -4691,7 +4835,7 @@ err:
|
||||
struct name_list *nl;
|
||||
if (!canon)
|
||||
{
|
||||
struct name_list *tmp = new->names, *next;
|
||||
struct name_list *tmp, *next;
|
||||
for (tmp = new->names; tmp; tmp = next)
|
||||
{
|
||||
next = tmp->next;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -746,6 +746,8 @@ static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void
|
||||
add 7 to round up */
|
||||
int len = (maclen + 9) >> 3;
|
||||
unsigned char *p = expand(len << 3);
|
||||
if (!p)
|
||||
return 1;
|
||||
memset(p, 0, len << 3);
|
||||
*p++ = ICMP6_OPT_SOURCE_MAC;
|
||||
*p++ = len;
|
||||
|
||||
227
src/rfc1035.c
227
src/rfc1035.c
@@ -526,7 +526,7 @@ static int print_txt(struct dns_header *header, const size_t qlen, char *name,
|
||||
}
|
||||
|
||||
*p3 = 0;
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, (char*)p1);
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, (char*)p1, 0);
|
||||
/* restore */
|
||||
memmove(p1 + 1, p1, i);
|
||||
*p1 = len;
|
||||
@@ -540,8 +540,8 @@ static int print_txt(struct dns_header *header, const size_t qlen, char *name,
|
||||
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(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
|
||||
int secure, int *doctored)
|
||||
struct ipsets *ipsets, struct ipsets *nftsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -551,6 +551,11 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
char **ipsets_cur;
|
||||
#else
|
||||
(void)ipsets; /* unused */
|
||||
#endif
|
||||
#ifdef HAVE_NFTSET
|
||||
char **nftsets_cur;
|
||||
#else
|
||||
(void)nftsets; /* unused */
|
||||
#endif
|
||||
int found = 0, cname_count = CNAME_CHAIN;
|
||||
struct crec *cpp = NULL;
|
||||
@@ -643,7 +648,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
#endif
|
||||
|
||||
if (aqtype == T_CNAME)
|
||||
log_query(secflag | F_CNAME | F_FORWARD | F_UPSTREAM, name, NULL, NULL);
|
||||
log_query(secflag | F_CNAME | F_FORWARD | F_UPSTREAM, name, NULL, NULL, 0);
|
||||
|
||||
if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
return 0;
|
||||
@@ -661,10 +666,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
found = 1;
|
||||
|
||||
if (!name_encoding)
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, querystr(NULL, aqtype));
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, NULL, aqtype);
|
||||
else
|
||||
{
|
||||
log_query(name_encoding | secflag | F_REVERSE | F_UPSTREAM, name, &addr, NULL);
|
||||
log_query(name_encoding | secflag | F_REVERSE | F_UPSTREAM, name, &addr, NULL, 0);
|
||||
if (insert)
|
||||
cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
|
||||
}
|
||||
@@ -691,7 +696,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
cache_insert(NULL, &addr, C_IN, now, ttl, flags);
|
||||
}
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, &addr, NULL);
|
||||
log_query(flags | F_UPSTREAM, name, &addr, NULL, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -762,7 +767,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!cname_count--)
|
||||
return 0; /* looped CNAMES */
|
||||
|
||||
log_query(secflag | F_CNAME | F_FORWARD | F_UPSTREAM, name, NULL, NULL);
|
||||
log_query(secflag | F_CNAME | F_FORWARD | F_UPSTREAM, name, NULL, NULL, 0);
|
||||
|
||||
if (insert)
|
||||
{
|
||||
@@ -787,14 +792,17 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
return 0;
|
||||
|
||||
goto cname_loop1;
|
||||
if (qtype != T_CNAME)
|
||||
goto cname_loop1;
|
||||
|
||||
found = 1;
|
||||
}
|
||||
else if (aqtype != qtype)
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (!option_bool(OPT_DNSSEC_VALID) || aqtype != T_RRSIG)
|
||||
#endif
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, querystr(NULL, aqtype));
|
||||
log_query(secflag | F_FORWARD | F_UPSTREAM, name, NULL, NULL, aqtype);
|
||||
}
|
||||
else if (!(flags & F_NXDOMAIN))
|
||||
{
|
||||
@@ -840,14 +848,15 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
{
|
||||
ipsets_cur = ipsets;
|
||||
while (*ipsets_cur)
|
||||
{
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
}
|
||||
}
|
||||
for (ipsets_cur = ipsets->sets; *ipsets_cur; ipsets_cur++)
|
||||
if (add_to_ipset(*ipsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, ipsets->domain, &addr, *ipsets_cur, 1);
|
||||
#endif
|
||||
#ifdef HAVE_NFTSET
|
||||
if (nftsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
for (nftsets_cur = nftsets->sets; *nftsets_cur; nftsets_cur++)
|
||||
if (add_to_nftset(*nftsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, nftsets->domain, &addr, *nftsets_cur, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -869,7 +878,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
log_query(flags | F_FORWARD | secflag | F_UPSTREAM, name, &addr, querystr(NULL, aqtype));
|
||||
log_query(flags | F_FORWARD | secflag | F_UPSTREAM, name, &addr, NULL, aqtype);
|
||||
}
|
||||
|
||||
p1 = endrr;
|
||||
@@ -877,8 +886,19 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
if (!found && (qtype != T_ANY || (flags & F_NXDOMAIN)))
|
||||
{
|
||||
if (flags & F_NXDOMAIN)
|
||||
{
|
||||
flags &= ~(F_IPV4 | F_IPV6 | F_SRV);
|
||||
|
||||
/* Can store NXDOMAIN reply to CNAME or ANY query. */
|
||||
if (qtype == T_CNAME || qtype == T_ANY)
|
||||
insert = 1;
|
||||
}
|
||||
|
||||
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL, 0);
|
||||
|
||||
if (!searched_soa)
|
||||
{
|
||||
searched_soa = 1;
|
||||
@@ -887,22 +907,17 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
/* If there's no SOA to get the TTL from, but there is a CNAME
|
||||
pointing at this, inherit its TTL */
|
||||
if (ttl || cpp)
|
||||
if (insert && !option_bool(OPT_NO_NEG) && (ttl || cpp))
|
||||
{
|
||||
if (ttl == 0)
|
||||
ttl = cttl;
|
||||
|
||||
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL);
|
||||
|
||||
if (insert)
|
||||
newc = cache_insert(name, NULL, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
newc = cache_insert(name, NULL, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
}
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1080,7 +1095,7 @@ void setup_reply(struct dns_header *header, unsigned int flags, int ede)
|
||||
union all_addr a;
|
||||
a.log.rcode = REFUSED;
|
||||
a.log.ede = ede;
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL, 0);
|
||||
SET_RCODE(header, REFUSED);
|
||||
}
|
||||
}
|
||||
@@ -1440,36 +1455,55 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
ans = 0; /* have we answered this question */
|
||||
|
||||
while (--count != 0 && (crecp = cache_find_by_name(NULL, name, now, F_CNAME)))
|
||||
{
|
||||
char *cname_target = cache_get_cname_target(crecp);
|
||||
if (qclass == C_IN)
|
||||
while (--count != 0 && (crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_NXDOMAIN)))
|
||||
{
|
||||
char *cname_target;
|
||||
|
||||
/* If the client asked for DNSSEC don't use cached data. */
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||
(rd_bit && (!do_bit || cache_validated(crecp))))
|
||||
{
|
||||
if (crecp->flags & F_CONFIG || qtype == T_CNAME)
|
||||
ans = 1;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
{
|
||||
if (qtype == T_CNAME)
|
||||
{
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0);
|
||||
auth = 0;
|
||||
nxdomain = 1;
|
||||
ans = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags, name, NULL, record_source(crecp->uid));
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_CNAME, C_IN, "d", cname_target))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return 0; /* give up if any cached CNAME in chain can't be used for DNSSEC reasons. */
|
||||
|
||||
strcpy(name, cname_target);
|
||||
}
|
||||
|
||||
cname_target = cache_get_cname_target(crecp);
|
||||
|
||||
/* If the client asked for DNSSEC don't use cached data. */
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||
(rd_bit && (!do_bit || cache_validated(crecp))))
|
||||
{
|
||||
if (crecp->flags & F_CONFIG || qtype == T_CNAME)
|
||||
ans = 1;
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_CNAME, C_IN, "d", cname_target))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return 0; /* give up if any cached CNAME in chain can't be used for DNSSEC reasons. */
|
||||
|
||||
if (qtype == T_CNAME)
|
||||
break;
|
||||
|
||||
strcpy(name, cname_target);
|
||||
}
|
||||
|
||||
if (qtype == T_TXT || qtype == T_ANY)
|
||||
{
|
||||
struct txt_record *t;
|
||||
@@ -1493,7 +1527,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
#endif
|
||||
if (ok)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
@@ -1515,7 +1549,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
addr.log.rcode = NOTIMP;
|
||||
log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
|
||||
log_query(F_CONFIG | F_RCODE, name, &addr, NULL, 0);
|
||||
}
|
||||
ans = 1, sec_data = 0;
|
||||
}
|
||||
@@ -1533,7 +1567,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, t->class));
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, t->class);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
t->class, C_IN, "t", t->len, t->txt))
|
||||
@@ -1589,7 +1623,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -1602,7 +1636,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>", 0);
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1612,7 +1646,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
}
|
||||
}
|
||||
else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
else if (is_arpa && (crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
/* Don't use cache when DNSSEC data required, unless we know that
|
||||
the zone is unsigned, which implies that we're doing
|
||||
@@ -1637,7 +1671,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1646,7 +1680,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
record_source(crecp->uid));
|
||||
record_source(crecp->uid), 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), NULL,
|
||||
@@ -1663,7 +1697,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
|
||||
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL, 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
@@ -1681,7 +1715,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
|
||||
name, &addr, NULL);
|
||||
name, &addr, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1736,7 +1770,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
gotit = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN,
|
||||
type == T_A ? "4" : "6", &addrlist->addr))
|
||||
@@ -1746,12 +1780,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
if (!dryrun && !gotit)
|
||||
log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | (dryrun ? F_NO_RR : 0))))
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_NXDOMAIN | (dryrun ? F_NO_RR : 0))))
|
||||
{
|
||||
int localise = 0;
|
||||
|
||||
@@ -1791,7 +1825,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, NULL);
|
||||
log_query(crecp->flags, name, NULL, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1809,7 +1843,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr,
|
||||
record_source(crecp->uid));
|
||||
record_source(crecp->uid), 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), NULL, type, C_IN,
|
||||
@@ -1824,7 +1858,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = 1, sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
@@ -1843,7 +1877,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
int offset;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
{
|
||||
@@ -1861,7 +1895,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", 1,
|
||||
option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
@@ -1883,7 +1917,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
int offset;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
|
||||
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))
|
||||
@@ -1915,27 +1949,31 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | (dryrun ? F_NO_RR : 0))) &&
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | F_NXDOMAIN | (dryrun ? F_NO_RR : 0))) &&
|
||||
rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
|
||||
{
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
auth = 0;
|
||||
found = ans = 1;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases, except for NXDOMAIN */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_NXDOMAIN)))
|
||||
break;
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
auth = 0;
|
||||
found = ans = 1;
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, NULL);
|
||||
log_query(crecp->flags, name, NULL, NULL, 0);
|
||||
}
|
||||
else if (!dryrun)
|
||||
{
|
||||
char *target = blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, NULL);
|
||||
log_query(crecp->flags, name, NULL, 0);
|
||||
log_query(crecp->flags, name, NULL, NULL, 0);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
|
||||
@@ -1945,14 +1983,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_SRV)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, NULL, NULL);
|
||||
log_query(F_CONFIG | F_NEG, name, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1966,7 +2003,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
|
||||
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))
|
||||
@@ -1983,7 +2020,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, NULL);
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
28
src/tftp.c
28
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,8 +598,8 @@ 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);
|
||||
sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
|
||||
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. */
|
||||
|
||||
91
src/util.c
91
src/util.c
@@ -115,7 +115,8 @@ u64 rand64(void)
|
||||
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
|
||||
}
|
||||
|
||||
/* returns 2 if names is OK but contains one or more underscores */
|
||||
/* returns 1 if name is OK and ascii printable
|
||||
* returns 2 if name should be processed by IDN */
|
||||
static int check_name(char *in)
|
||||
{
|
||||
/* remove trailing .
|
||||
@@ -123,7 +124,9 @@ static int check_name(char *in)
|
||||
size_t dotgap = 0, l = strlen(in);
|
||||
char c;
|
||||
int nowhite = 0;
|
||||
int idn_encode = 0;
|
||||
int hasuscore = 0;
|
||||
int hasucase = 0;
|
||||
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
@@ -136,28 +139,49 @@ static int check_name(char *in)
|
||||
for (; (c = *in); in++)
|
||||
{
|
||||
if (c == '.')
|
||||
dotgap = 0;
|
||||
dotgap = 0;
|
||||
else if (++dotgap > MAXLABEL)
|
||||
return 0;
|
||||
return 0;
|
||||
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
else if (!isascii((unsigned char)c))
|
||||
return 0;
|
||||
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
|
||||
return 0;
|
||||
#else
|
||||
idn_encode = 1;
|
||||
#endif
|
||||
else if (c != ' ')
|
||||
{
|
||||
nowhite = 1;
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
}
|
||||
{
|
||||
nowhite = 1;
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
#else
|
||||
(void)hasuscore;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
hasucase = 1;
|
||||
#else
|
||||
(void)hasucase;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!nowhite)
|
||||
return 0;
|
||||
|
||||
return hasuscore ? 2 : 1;
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
/* Older libidn2 strips underscores, so don't do IDN processing
|
||||
if the name has an underscore unless it also has non-ascii characters. */
|
||||
idn_encode = idn_encode || (hasucase && !hasuscore);
|
||||
#else
|
||||
idn_encode = idn_encode || hasucase;
|
||||
#endif
|
||||
|
||||
return (idn_encode) ? 2 : 1;
|
||||
}
|
||||
|
||||
/* Hostnames have a more limited valid charset than domain names
|
||||
@@ -204,17 +228,11 @@ char *canonicalise(char *in, int *nomem)
|
||||
if (!(rc = check_name(in)))
|
||||
return NULL;
|
||||
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
/* older libidn2 strips underscores, so don't do IDN processing
|
||||
if the name has an underscore (check_name() returned 2) */
|
||||
if (rc != 2)
|
||||
#endif
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
if (rc == 2)
|
||||
{
|
||||
# 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
|
||||
@@ -234,12 +252,14 @@ char *canonicalise(char *in, int *nomem)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
(void)rc;
|
||||
#endif
|
||||
|
||||
if ((ret = whine_malloc(strlen(in)+1)))
|
||||
strcpy(ret, in);
|
||||
else if (nomem)
|
||||
*nomem = 1;
|
||||
*nomem = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -347,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;
|
||||
|
||||
@@ -360,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 */
|
||||
@@ -408,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
|
||||
@@ -528,7 +555,7 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&buf[p], "%um", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&buf[p], "%us", x);
|
||||
sprintf(&buf[p], "%us", x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +601,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
int j, bytes = (1 + (r - in))/2;
|
||||
for (j = 0; j < bytes; j++)
|
||||
{
|
||||
char sav = sav;
|
||||
char sav;
|
||||
if (j < bytes - 1)
|
||||
{
|
||||
sav = in[(j+1)*2];
|
||||
|
||||
Reference in New Issue
Block a user