Initial commit
This commit is contained in:
195
package/network/services/dnsmasq/Makefile
Normal file
195
package/network/services/dnsmasq/Makefile
Normal file
@@ -0,0 +1,195 @@
|
||||
#
|
||||
# Copyright (C) 2006-2016 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dnsmasq
|
||||
PKG_UPSTREAM_VERSION:=2.80
|
||||
PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION)))
|
||||
PKG_RELEASE:=16.3
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz
|
||||
PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
|
||||
PKG_HASH:=cdaba2785e92665cf090646cba6f94812760b9d7d8c8d0cfb07ac819377a63bb
|
||||
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
PKG_LICENSE_FILES:=COPYING
|
||||
PKG_CPE_ID:=cpe:/a:thekelleys:dnsmasq
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_UPSTREAM_VERSION)
|
||||
|
||||
PKG_INSTALL:=1
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6 \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc \
|
||||
CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_tftp
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/dnsmasq/Default
|
||||
SECTION:=net
|
||||
CATEGORY:=Base system
|
||||
TITLE:=DNS and DHCP server
|
||||
URL:=http://www.thekelleys.org.uk/dnsmasq/
|
||||
DEPENDS:=+libubus
|
||||
USERID:=dnsmasq=453:dnsmasq=453
|
||||
endef
|
||||
|
||||
define Package/dnsmasq
|
||||
$(call Package/dnsmasq/Default)
|
||||
VARIANT:=nodhcpv6
|
||||
endef
|
||||
|
||||
define Package/dnsmasq-dhcpv6
|
||||
$(call Package/dnsmasq/Default)
|
||||
TITLE += (with DHCPv6 support)
|
||||
DEPENDS+=@IPV6
|
||||
VARIANT:=dhcpv6
|
||||
PROVIDES:=dnsmasq
|
||||
endef
|
||||
|
||||
define Package/dnsmasq-full
|
||||
$(call Package/dnsmasq/Default)
|
||||
TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Conntrack, NO_ID enabled by default)
|
||||
DEPENDS+=+PACKAGE_dnsmasq_full_dnssec:libnettle \
|
||||
+PACKAGE_dnsmasq_full_ipset:kmod-ipt-ipset \
|
||||
+PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack
|
||||
VARIANT:=full
|
||||
PROVIDES:=dnsmasq
|
||||
endef
|
||||
|
||||
define Package/dnsmasq/description
|
||||
It is intended to provide coupled DNS and DHCP service to a LAN.
|
||||
endef
|
||||
|
||||
define Package/dnsmasq-dhcpv6/description
|
||||
$(call Package/dnsmasq/description)
|
||||
|
||||
This is a variant with DHCPv6 support
|
||||
endef
|
||||
|
||||
define Package/dnsmasq-full/description
|
||||
$(call Package/dnsmasq/description)
|
||||
|
||||
This is a fully configurable variant with DHCPv4, DHCPv6, DNSSEC, Authoritative DNS
|
||||
and IPset, Conntrack support & NO_ID enabled by default.
|
||||
endef
|
||||
|
||||
define Package/dnsmasq/conffiles
|
||||
/etc/config/dhcp
|
||||
/etc/dnsmasq.conf
|
||||
endef
|
||||
|
||||
define Package/dnsmasq-full/config
|
||||
if PACKAGE_dnsmasq-full
|
||||
config PACKAGE_dnsmasq_full_dhcp
|
||||
bool "Build with DHCP support."
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_dhcpv6
|
||||
bool "Build with DHCPv6 support."
|
||||
depends on IPV6 && PACKAGE_dnsmasq_full_dhcp
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_dnssec
|
||||
bool "Build with DNSSEC support."
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_auth
|
||||
bool "Build with the facility to act as an authoritative DNS server."
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_ipset
|
||||
bool "Build with IPset support."
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_conntrack
|
||||
bool "Build with Conntrack support."
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_noid
|
||||
bool "Build with NO_ID. (hide *.bind pseudo domain)"
|
||||
default y
|
||||
config PACKAGE_dnsmasq_full_broken_rtc
|
||||
bool "Build with HAVE_BROKEN_RTC."
|
||||
default n
|
||||
config PACKAGE_dnsmasq_full_tftp
|
||||
bool "Build with TFTP server support."
|
||||
default y
|
||||
endif
|
||||
endef
|
||||
|
||||
Package/dnsmasq-dhcpv6/conffiles = $(Package/dnsmasq/conffiles)
|
||||
Package/dnsmasq-full/conffiles = $(Package/dnsmasq/conffiles)
|
||||
|
||||
TARGET_CFLAGS += -ffunction-sections -fdata-sections
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections
|
||||
|
||||
COPTS = -DHAVE_UBUS \
|
||||
$(if $(CONFIG_IPV6),,-DNO_IPV6)
|
||||
|
||||
ifeq ($(BUILD_VARIANT),nodhcpv6)
|
||||
COPTS += -DNO_DHCP6
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_VARIANT),full)
|
||||
COPTS += $(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp),,-DNO_DHCP) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6),,-DNO_DHCP6) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec),-DHAVE_DNSSEC) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth),,-DNO_AUTH) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset),,-DNO_IPSET) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack),-DHAVE_CONNTRACK,) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid),-DNO_ID,) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc),-DHAVE_BROKEN_RTC) \
|
||||
$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_tftp),,-DNO_TFTP)
|
||||
COPTS += $(if $(CONFIG_LIBNETTLE_MINI),-DNO_GMP,)
|
||||
else
|
||||
COPTS += -DNO_AUTH -DNO_IPSET -DNO_ID
|
||||
endif
|
||||
|
||||
MAKE_FLAGS := \
|
||||
$(TARGET_CONFIGURE_OPTS) \
|
||||
CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
|
||||
LDFLAGS="$(TARGET_LDFLAGS)" \
|
||||
COPTS="$(COPTS)" \
|
||||
PREFIX="/usr"
|
||||
|
||||
define Package/dnsmasq/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/dnsmasq $(1)/usr/sbin/
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/dhcp.conf $(1)/etc/config/dhcp
|
||||
$(INSTALL_CONF) ./files/dnsmasq.conf $(1)/etc/dnsmasq.conf
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/dnsmasq.init $(1)/etc/init.d/dnsmasq
|
||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/dhcp
|
||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/neigh
|
||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/ntp
|
||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/tftp
|
||||
$(INSTALL_CONF) ./files/dnsmasqsec.hotplug $(1)/etc/hotplug.d/ntp/25-dnsmasqsec
|
||||
$(INSTALL_DIR) $(1)/usr/share/dnsmasq
|
||||
$(INSTALL_CONF) ./files/dhcpbogushostname.conf $(1)/usr/share/dnsmasq/
|
||||
$(INSTALL_CONF) ./files/rfc6761.conf $(1)/usr/share/dnsmasq/
|
||||
$(INSTALL_DIR) $(1)/usr/lib/dnsmasq
|
||||
$(INSTALL_BIN) ./files/dhcp-script.sh $(1)/usr/lib/dnsmasq/dhcp-script.sh
|
||||
$(INSTALL_DIR) $(1)/usr/share/acl.d
|
||||
$(INSTALL_DATA) ./files/dnsmasq_acl.json $(1)/usr/share/acl.d/
|
||||
endef
|
||||
|
||||
Package/dnsmasq-dhcpv6/install = $(Package/dnsmasq/install)
|
||||
|
||||
define Package/dnsmasq-full/install
|
||||
$(call Package/dnsmasq/install,$(1))
|
||||
ifneq ($(CONFIG_PACKAGE_dnsmasq_full_dnssec),)
|
||||
$(INSTALL_DIR) $(1)/usr/share/dnsmasq
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/trust-anchors.conf $(1)/usr/share/dnsmasq
|
||||
endif
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,dnsmasq))
|
||||
$(eval $(call BuildPackage,dnsmasq-dhcpv6))
|
||||
$(eval $(call BuildPackage,dnsmasq-full))
|
||||
46
package/network/services/dnsmasq/files/dhcp-script.sh
Executable file
46
package/network/services/dnsmasq/files/dhcp-script.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -f "$USER_DHCPSCRIPT" ] && . "$USER_DHCPSCRIPT" "$@"
|
||||
|
||||
case "$1" in
|
||||
add)
|
||||
export ACTION="add"
|
||||
export MACADDR="$2"
|
||||
export IPADDR="$3"
|
||||
export HOSTNAME="$4"
|
||||
exec /sbin/hotplug-call dhcp
|
||||
;;
|
||||
del)
|
||||
export ACTION="remove"
|
||||
export MACADDR="$2"
|
||||
export IPADDR="$3"
|
||||
export HOSTNAME="$4"
|
||||
exec /sbin/hotplug-call dhcp
|
||||
;;
|
||||
old)
|
||||
export ACTION="update"
|
||||
export MACADDR="$2"
|
||||
export IPADDR="$3"
|
||||
export HOSTNAME="$4"
|
||||
exec /sbin/hotplug-call dhcp
|
||||
;;
|
||||
arp-add)
|
||||
export ACTION="add"
|
||||
export MACADDR="$2"
|
||||
export IPADDR="$3"
|
||||
exec /sbin/hotplug-call neigh
|
||||
;;
|
||||
arp-del)
|
||||
export ACTION="remove"
|
||||
export MACADDR="$2"
|
||||
export IPADDR="$3"
|
||||
exec /sbin/hotplug-call neigh
|
||||
;;
|
||||
tftp)
|
||||
export ACTION="add"
|
||||
export TFTP_SIZE="$2"
|
||||
export TFTP_ADDR="$3"
|
||||
export TFTP_PATH="$4"
|
||||
exec /sbin/hotplug-call tftp
|
||||
;;
|
||||
esac
|
||||
32
package/network/services/dnsmasq/files/dhcp.conf
Normal file
32
package/network/services/dnsmasq/files/dhcp.conf
Normal file
@@ -0,0 +1,32 @@
|
||||
config dnsmasq
|
||||
option domainneeded 1
|
||||
option boguspriv 1
|
||||
option filterwin2k 0 # enable for dial on demand
|
||||
option localise_queries 1
|
||||
option rebind_protection 1 # disable if upstream must serve RFC1918 addresses
|
||||
option rebind_localhost 1 # enable for RBL checking and similar services
|
||||
#list rebind_domain example.lan # whitelist RFC1918 responses for domains
|
||||
option local '/lan/'
|
||||
option domain 'lan'
|
||||
option expandhosts 1
|
||||
option nonegcache 0
|
||||
option authoritative 1
|
||||
option readethers 1
|
||||
option leasefile '/tmp/dhcp.leases'
|
||||
option resolvfile '/tmp/resolv.conf.auto'
|
||||
#list server '/mycompany.local/1.2.3.4'
|
||||
option nonwildcard 1 # bind to & keep track of interfaces
|
||||
#list interface br-lan
|
||||
#list notinterface lo
|
||||
#list bogusnxdomain '64.94.110.11'
|
||||
option localservice 1 # disable to allow DNS requests from non-local subnets
|
||||
|
||||
config dhcp lan
|
||||
option interface lan
|
||||
option start 100
|
||||
option limit 150
|
||||
option leasetime 12h
|
||||
|
||||
config dhcp wan
|
||||
option interface wan
|
||||
option ignore 1
|
||||
@@ -0,0 +1,8 @@
|
||||
# dhcpbogushostname.conf included configuration file for dnsmasq
|
||||
#
|
||||
# includes a list of hostnames that should not be associated with dhcp leases
|
||||
# in response to CERT VU#598349
|
||||
# file included by default, option dhcpbogushostname 0 to disable
|
||||
|
||||
dhcp-name-match=set:dhcp_bogus_hostname,localhost
|
||||
dhcp-name-match=set:dhcp_bogus_hostname,wpad
|
||||
37
package/network/services/dnsmasq/files/dnsmasq.conf
Normal file
37
package/network/services/dnsmasq/files/dnsmasq.conf
Normal file
@@ -0,0 +1,37 @@
|
||||
# Change the following lines if you want dnsmasq to serve SRV
|
||||
# records.
|
||||
# You may add multiple srv-host lines.
|
||||
# The fields are <name>,<target>,<port>,<priority>,<weight>
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 289
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
|
||||
|
||||
# Two SRV records for LDAP, each with different priorities
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
|
||||
|
||||
# A SRV record indicating that there is no LDAP server for the domain
|
||||
# example.com
|
||||
#srv-host=_ldap._tcp.example.com
|
||||
|
||||
# The following line shows how to make dnsmasq serve an arbitrary PTR
|
||||
# record. This is useful for DNS-SD.
|
||||
# The fields are <name>,<target>
|
||||
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
|
||||
|
||||
# Change the following lines to enable dnsmasq to serve TXT records.
|
||||
# These are used for things like SPF and zeroconf.
|
||||
# The fields are <name>,<text>,<text>...
|
||||
|
||||
#Example SPF.
|
||||
#txt-record=example.com,"v=spf1 a -all"
|
||||
|
||||
#Example zeroconf
|
||||
#txt-record=_http._tcp.example.com,name=value,paper=A4
|
||||
|
||||
# Provide an alias for a "local" DNS name. Note that this _only_ works
|
||||
# for targets which are names from DHCP or /etc/hosts. Give host
|
||||
# "bert" another name, bertrand
|
||||
# The fields are <cname>,<target>
|
||||
#cname=bertand,bert
|
||||
1172
package/network/services/dnsmasq/files/dnsmasq.init
Normal file
1172
package/network/services/dnsmasq/files/dnsmasq.init
Normal file
File diff suppressed because it is too large
Load Diff
4
package/network/services/dnsmasq/files/dnsmasq_acl.json
Normal file
4
package/network/services/dnsmasq/files/dnsmasq_acl.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"user": "dnsmasq",
|
||||
"publish": [ "dnsmasq" ]
|
||||
}
|
||||
14
package/network/services/dnsmasq/files/dnsmasqsec.hotplug
Normal file
14
package/network/services/dnsmasq/files/dnsmasqsec.hotplug
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /lib/functions/procd.sh
|
||||
|
||||
TIMEVALIDFILE="/var/state/dnsmasqsec"
|
||||
|
||||
[ "$ACTION" = stratum ] || exit 0
|
||||
|
||||
[ -f "$TIMEVALIDFILE" ] || {
|
||||
echo "ntpd says time is valid" >$TIMEVALIDFILE
|
||||
/etc/init.d/dnsmasq enabled && {
|
||||
procd_send_signal dnsmasq '*' INT
|
||||
}
|
||||
}
|
||||
11
package/network/services/dnsmasq/files/rfc6761.conf
Normal file
11
package/network/services/dnsmasq/files/rfc6761.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
# RFC6761 included configuration file for dnsmasq
|
||||
#
|
||||
# includes a list of domains that should not be forwarded to Internet name servers
|
||||
# to reduce burden on them, asking questions that they won't know the answer to.
|
||||
|
||||
server=/bind/
|
||||
server=/invalid/
|
||||
server=/local/
|
||||
server=/localhost/
|
||||
server=/onion/
|
||||
server=/test/
|
||||
@@ -0,0 +1,495 @@
|
||||
From a799ca0c6314ad73a97bc6c89382d2712a9c0b0e Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 18 Oct 2018 19:35:29 +0100
|
||||
Subject: [PATCH 01/32] Impove cache behaviour for TCP connections.
|
||||
|
||||
For ease of implementaion, dnsmasq has always forked a new process to
|
||||
handle each incoming TCP connection. A side-effect of this is that any
|
||||
DNS queries answered from TCP connections are not cached: when TCP
|
||||
connections were rare, this was not a problem. With the coming of
|
||||
DNSSEC, it's now the case that some DNSSEC queries have answers which
|
||||
spill to TCP, and if, for instance, this applies to the keys for the
|
||||
root then those never get cached, and performance is very bad. This
|
||||
fix passes cache entries back from the TCP child process to the main
|
||||
server process, and fixes the problem.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
CHANGELOG | 14 ++++
|
||||
src/blockdata.c | 37 ++++++++-
|
||||
src/cache.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
src/dnsmasq.c | 58 ++++++++++++--
|
||||
src/dnsmasq.h | 5 ++
|
||||
5 files changed, 291 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -1,3 +1,17 @@
|
||||
+version 2.81
|
||||
+ Impove cache behaviour for TCP connections. For ease of
|
||||
+ implementaion, dnsmasq has always forked a new process to handle
|
||||
+ each incoming TCP connection. A side-effect of this is that
|
||||
+ any DNS queries answered from TCP connections are not cached:
|
||||
+ when TCP connections were rare, this was not a problem.
|
||||
+ With the coming of DNSSEC, it's now the case that some
|
||||
+ DNSSEC queries have answers which spill to TCP, and if,
|
||||
+ for instance, this applies to the keys for the root then
|
||||
+ those never get cached, and performance is very bad.
|
||||
+ This fix passes cache entries back from the TCP child process to
|
||||
+ the main server process, and fixes the problem.
|
||||
+
|
||||
+
|
||||
version 2.80
|
||||
Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method
|
||||
for the initial patch and motivation.
|
||||
--- a/src/blockdata.c
|
||||
+++ b/src/blockdata.c
|
||||
@@ -61,7 +61,7 @@ void blockdata_report(void)
|
||||
blockdata_alloced * sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
-struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
+static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
|
||||
{
|
||||
struct blockdata *block, *ret = NULL;
|
||||
struct blockdata **prev = &ret;
|
||||
@@ -89,8 +89,17 @@ struct blockdata *blockdata_alloc(char *
|
||||
blockdata_hwm = blockdata_count;
|
||||
|
||||
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||
- memcpy(block->key, data, blen);
|
||||
- data += blen;
|
||||
+ if (data)
|
||||
+ {
|
||||
+ memcpy(block->key, data, blen);
|
||||
+ data += blen;
|
||||
+ }
|
||||
+ else if (!read_write(fd, block->key, blen, 1))
|
||||
+ {
|
||||
+ /* failed read free partial chain */
|
||||
+ blockdata_free(ret);
|
||||
+ return NULL;
|
||||
+ }
|
||||
len -= blen;
|
||||
*prev = block;
|
||||
prev = &block->next;
|
||||
@@ -100,6 +109,10 @@ struct blockdata *blockdata_alloc(char *
|
||||
return ret;
|
||||
}
|
||||
|
||||
+struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
+{
|
||||
+ return blockdata_alloc_real(0, data, len);
|
||||
+}
|
||||
|
||||
void blockdata_free(struct blockdata *blocks)
|
||||
{
|
||||
@@ -148,5 +161,21 @@ void *blockdata_retrieve(struct blockdat
|
||||
|
||||
return data;
|
||||
}
|
||||
-
|
||||
+
|
||||
+
|
||||
+void blockdata_write(struct blockdata *block, size_t len, int fd)
|
||||
+{
|
||||
+ for (; len > 0 && block; block = block->next)
|
||||
+ {
|
||||
+ size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||
+ read_write(fd, block->key, blen, 0);
|
||||
+ len -= blen;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+struct blockdata *blockdata_read(int fd, size_t len)
|
||||
+{
|
||||
+ return blockdata_alloc_real(fd, NULL, len);
|
||||
+}
|
||||
+
|
||||
#endif
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -26,6 +26,8 @@ static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
|
||||
static void make_non_terminals(struct crec *source);
|
||||
+static struct crec *really_insert(char *name, struct all_addr *addr,
|
||||
+ time_t now, unsigned long ttl, unsigned short flags);
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -464,16 +466,10 @@ void cache_start_insert(void)
|
||||
new_chain = NULL;
|
||||
insert_error = 0;
|
||||
}
|
||||
-
|
||||
+
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags)
|
||||
{
|
||||
- struct crec *new, *target_crec = NULL;
|
||||
- union bigname *big_name = NULL;
|
||||
- int freed_all = flags & F_REVERSE;
|
||||
- int free_avail = 0;
|
||||
- unsigned int target_uid;
|
||||
-
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
|
||||
{
|
||||
@@ -484,7 +480,20 @@ struct crec *cache_insert(char *name, st
|
||||
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
|
||||
ttl = daemon->min_cache_ttl;
|
||||
}
|
||||
+
|
||||
+ return really_insert(name, addr, now, ttl, flags);
|
||||
+}
|
||||
|
||||
+
|
||||
+static struct crec *really_insert(char *name, struct all_addr *addr,
|
||||
+ time_t now, unsigned long ttl, unsigned short flags)
|
||||
+{
|
||||
+ struct crec *new, *target_crec = NULL;
|
||||
+ union bigname *big_name = NULL;
|
||||
+ int freed_all = flags & F_REVERSE;
|
||||
+ int free_avail = 0;
|
||||
+ unsigned int target_uid;
|
||||
+
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return NULL;
|
||||
@@ -645,12 +654,185 @@ void cache_end_insert(void)
|
||||
cache_hash(new_chain);
|
||||
cache_link(new_chain);
|
||||
daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
|
||||
+
|
||||
+ /* If we're a child process, send this cache entry up the pipe to the master.
|
||||
+ The marshalling process is rather nasty. */
|
||||
+ if (daemon->pipe_to_parent != -1)
|
||||
+ {
|
||||
+ char *name = cache_get_name(new_chain);
|
||||
+ ssize_t m = strlen(name);
|
||||
+ unsigned short flags = new_chain->flags;
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ u16 class = new_chain->uid;
|
||||
+#endif
|
||||
+
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
|
||||
+
|
||||
+ if (flags & (F_IPV4 | F_IPV6))
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ else if (flags & F_DNSKEY)
|
||||
+ {
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.algo, sizeof(new_chain->addr.key.algo), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keytag, sizeof(new_chain->addr.key.keytag), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.flags, sizeof(new_chain->addr.key.flags), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keylen, sizeof(new_chain->addr.key.keylen), 0);
|
||||
+ blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
|
||||
+ }
|
||||
+ else if (flags & F_DS)
|
||||
+ {
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
|
||||
+ /* A negative DS entry is possible and has no data, obviously. */
|
||||
+ if (!(flags & F_NEG))
|
||||
+ {
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.algo, sizeof(new_chain->addr.ds.algo), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keytag, sizeof(new_chain->addr.ds.keytag), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.digest, sizeof(new_chain->addr.ds.digest), 0);
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keylen, sizeof(new_chain->addr.ds.keylen), 0);
|
||||
+ blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ }
|
||||
}
|
||||
+
|
||||
new_chain = tmp;
|
||||
}
|
||||
+
|
||||
+ /* signal end of cache insert in master process */
|
||||
+ if (daemon->pipe_to_parent != -1)
|
||||
+ {
|
||||
+ ssize_t m = -1;
|
||||
+ read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
|
||||
+ }
|
||||
+
|
||||
new_chain = NULL;
|
||||
}
|
||||
|
||||
+
|
||||
+/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
|
||||
+int cache_recv_insert(time_t now, int fd)
|
||||
+{
|
||||
+ ssize_t m;
|
||||
+ struct all_addr addr;
|
||||
+ unsigned long ttl;
|
||||
+ time_t ttd;
|
||||
+ unsigned short flags;
|
||||
+ struct crec *crecp = NULL;
|
||||
+
|
||||
+ cache_start_insert();
|
||||
+
|
||||
+ while(1)
|
||||
+ {
|
||||
+
|
||||
+ if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (m == -1)
|
||||
+ {
|
||||
+ cache_end_insert();
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
|
||||
+ return 0;
|
||||
+
|
||||
+ daemon->namebuff[m] = 0;
|
||||
+
|
||||
+ ttl = difftime(ttd, now);
|
||||
+
|
||||
+ if (flags & (F_IPV4 | F_IPV6))
|
||||
+ {
|
||||
+ if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||
+ return 0;
|
||||
+ crecp = really_insert(daemon->namebuff, &addr, now, ttl, flags);
|
||||
+ }
|
||||
+ else if (flags & F_CNAME)
|
||||
+ {
|
||||
+ struct crec *newc = really_insert(daemon->namebuff, NULL, now, ttl, flags);
|
||||
+ /* This relies on the fact the the target of a CNAME immediately preceeds
|
||||
+ it because of the order of extraction in extract_addresses, and
|
||||
+ the order reversal on the new_chain. */
|
||||
+ if (newc)
|
||||
+ {
|
||||
+ if (!crecp)
|
||||
+ {
|
||||
+ newc->addr.cname.target.cache = NULL;
|
||||
+ /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
|
||||
+ newc->addr.cname.uid = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ next_uid(crecp);
|
||||
+ newc->addr.cname.target.cache = crecp;
|
||||
+ newc->addr.cname.uid = crecp->uid;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ else if (flags & (F_DNSKEY | F_DS))
|
||||
+ {
|
||||
+ unsigned short class, keylen, keyflags, keytag;
|
||||
+ unsigned char algo, digest;
|
||||
+ struct blockdata *keydata;
|
||||
+
|
||||
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1))
|
||||
+ return 0;
|
||||
+ /* Cache needs to known class for DNSSEC stuff */
|
||||
+ addr.addr.dnssec.class = class;
|
||||
+
|
||||
+ crecp = really_insert(daemon->namebuff, &addr, now, ttl, flags);
|
||||
+
|
||||
+ if (flags & F_DNSKEY)
|
||||
+ {
|
||||
+ if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&keyflags, sizeof(keyflags), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) ||
|
||||
+ !(keydata = blockdata_read(fd, keylen)))
|
||||
+ return 0;
|
||||
+ }
|
||||
+ else if (!(flags & F_NEG))
|
||||
+ {
|
||||
+ if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&digest, sizeof(digest), 1) ||
|
||||
+ !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) ||
|
||||
+ !(keydata = blockdata_read(fd, keylen)))
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (crecp)
|
||||
+ {
|
||||
+ if (flags & F_DNSKEY)
|
||||
+ {
|
||||
+ crecp->addr.key.algo = algo;
|
||||
+ crecp->addr.key.keytag = keytag;
|
||||
+ crecp->addr.key.flags = flags;
|
||||
+ crecp->addr.key.keylen = keylen;
|
||||
+ crecp->addr.key.keydata = keydata;
|
||||
+ }
|
||||
+ else if (!(flags & F_NEG))
|
||||
+ {
|
||||
+ crecp->addr.ds.algo = algo;
|
||||
+ crecp->addr.ds.keytag = keytag;
|
||||
+ crecp->addr.ds.digest = digest;
|
||||
+ crecp->addr.ds.keylen = keylen;
|
||||
+ crecp->addr.ds.keydata = keydata;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
int cache_find_non_terminal(char *name, time_t now)
|
||||
{
|
||||
struct crec *crecp;
|
||||
--- a/src/dnsmasq.c
|
||||
+++ b/src/dnsmasq.c
|
||||
@@ -930,6 +930,10 @@ int main (int argc, char **argv)
|
||||
check_servers();
|
||||
|
||||
pid = getpid();
|
||||
+
|
||||
+ daemon->pipe_to_parent = -1;
|
||||
+ for (i = 0; i < MAX_PROCS; i++)
|
||||
+ daemon->tcp_pipes[i] = -1;
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
/* Using inotify, have to select a resolv file at startup */
|
||||
@@ -1611,7 +1615,7 @@ static int set_dns_listeners(time_t now)
|
||||
we don't need to explicitly arrange to wake up here */
|
||||
if (listener->tcpfd != -1)
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
- if (daemon->tcp_pids[i] == 0)
|
||||
+ if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
{
|
||||
poll_listen(listener->tcpfd, POLLIN);
|
||||
break;
|
||||
@@ -1624,6 +1628,13 @@ static int set_dns_listeners(time_t now)
|
||||
|
||||
}
|
||||
|
||||
+#ifndef NO_FORK
|
||||
+ if (!option_bool(OPT_DEBUG))
|
||||
+ for (i = 0; i < MAX_PROCS; i++)
|
||||
+ if (daemon->tcp_pipes[i] != -1)
|
||||
+ poll_listen(daemon->tcp_pipes[i], POLLIN);
|
||||
+#endif
|
||||
+
|
||||
return wait;
|
||||
}
|
||||
|
||||
@@ -1632,7 +1643,10 @@ static void check_dns_listeners(time_t n
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
int i;
|
||||
-
|
||||
+#ifndef NO_FORK
|
||||
+ int pipefd[2];
|
||||
+#endif
|
||||
+
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (poll_check(serverfdp->fd, POLLIN))
|
||||
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
|
||||
@@ -1642,7 +1656,26 @@ static void check_dns_listeners(time_t n
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
||||
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
|
||||
-
|
||||
+
|
||||
+#ifndef NO_FORK
|
||||
+ /* Races. The child process can die before we read all of the data from the
|
||||
+ pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
|
||||
+ process, and tcp_pipes to -1 and close the FD when we read the last
|
||||
+ of the data - indicated by cache_recv_insert returning zero.
|
||||
+ The order of these events is indeterminate, and both are needed
|
||||
+ to free the process slot. Once the child process has gone, poll()
|
||||
+ returns POLLHUP, not POLLIN, so have to check for both here. */
|
||||
+ if (!option_bool(OPT_DEBUG))
|
||||
+ for (i = 0; i < MAX_PROCS; i++)
|
||||
+ if (daemon->tcp_pipes[i] != -1 &&
|
||||
+ poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) &&
|
||||
+ !cache_recv_insert(now, daemon->tcp_pipes[i]))
|
||||
+ {
|
||||
+ close(daemon->tcp_pipes[i]);
|
||||
+ daemon->tcp_pipes[i] = -1;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
|
||||
@@ -1736,15 +1769,20 @@ static void check_dns_listeners(time_t n
|
||||
while (retry_send(close(confd)));
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
- else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
|
||||
+ else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0)
|
||||
{
|
||||
- if (p != -1)
|
||||
+ close(pipefd[1]); /* parent needs read pipe end. */
|
||||
+ if (p == -1)
|
||||
+ close(pipefd[0]);
|
||||
+ else
|
||||
{
|
||||
int i;
|
||||
+
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
- if (daemon->tcp_pids[i] == 0)
|
||||
+ if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
{
|
||||
daemon->tcp_pids[i] = p;
|
||||
+ daemon->tcp_pipes[i] = pipefd[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1761,7 +1799,7 @@ static void check_dns_listeners(time_t n
|
||||
int flags;
|
||||
struct in_addr netmask;
|
||||
int auth_dns;
|
||||
-
|
||||
+
|
||||
if (iface)
|
||||
{
|
||||
netmask = iface->netmask;
|
||||
@@ -1777,7 +1815,11 @@ static void check_dns_listeners(time_t n
|
||||
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
- alarm(CHILD_LIFETIME);
|
||||
+ {
|
||||
+ alarm(CHILD_LIFETIME);
|
||||
+ close(pipefd[0]); /* close read end in child. */
|
||||
+ daemon->pipe_to_parent = pipefd[1];
|
||||
+ }
|
||||
#endif
|
||||
|
||||
/* start with no upstream connections. */
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -1091,6 +1091,8 @@ extern struct daemon {
|
||||
size_t packet_len; /* " " */
|
||||
struct randfd *rfd_save; /* " " */
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
+ int tcp_pipes[MAX_PROCS];
|
||||
+ int pipe_to_parent;
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
@@ -1152,6 +1154,7 @@ struct crec *cache_find_by_name(struct c
|
||||
char *name, time_t now, unsigned int prot);
|
||||
void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
+int cache_recv_insert(time_t now, int fd);
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
void cache_reload(void);
|
||||
@@ -1174,6 +1177,8 @@ void blockdata_init(void);
|
||||
void blockdata_report(void);
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len);
|
||||
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data);
|
||||
+struct blockdata *blockdata_read(int fd, size_t len);
|
||||
+void blockdata_write(struct blockdata *block, size_t len, int fd);
|
||||
void blockdata_free(struct blockdata *blocks);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
From a220545c4277cba534be5ef4638b5076fc7d2cf4 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Mon, 22 Oct 2018 18:21:48 +0100
|
||||
Subject: [PATCH 02/32] Ensure that AD bit is reset on answers from
|
||||
--address=/<domain>/<address>.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc1035.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -938,9 +938,9 @@ size_t setup_reply(struct dns_header *he
|
||||
return 0;
|
||||
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
- header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
- /* set RA flag */
|
||||
- header->hb4 |= HB4_RA;
|
||||
+ header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
|
||||
+ /* clear AD flag, set RA flag */
|
||||
+ header->hb4 = (header->hb4 & ~HB4_AD) | HB4_RA;
|
||||
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
From cf5984367bc6a949e3803a576512c5a7bc48ebab Mon Sep 17 00:00:00 2001
|
||||
From: Vladislav Grishenko <themiron@mail.ru>
|
||||
Date: Thu, 18 Oct 2018 04:55:21 +0500
|
||||
Subject: [PATCH 04/32] Don't forward *.bind/*.server queries upstream
|
||||
|
||||
Chaos .bind and .server (RFC4892) zones are local, therefore
|
||||
don't forward queries upstream to avoid mixing with supported
|
||||
locally and false replies with NO_ID enabled.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc1035.c | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1276,7 +1276,7 @@ size_t answer_request(struct dns_header
|
||||
int q, ans, anscount = 0, addncount = 0;
|
||||
int dryrun = 0;
|
||||
struct crec *crecp;
|
||||
- int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
|
||||
+ int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1;
|
||||
struct mx_srv_record *rec;
|
||||
size_t len;
|
||||
|
||||
@@ -1355,6 +1355,17 @@ size_t answer_request(struct dns_header
|
||||
}
|
||||
}
|
||||
|
||||
+ if (qclass == C_CHAOS)
|
||||
+ {
|
||||
+ /* don't forward *.bind and *.server chaos queries */
|
||||
+ if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name))
|
||||
+ {
|
||||
+ if (!ans)
|
||||
+ notimp = 1, auth = 0;
|
||||
+ ans = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (qclass == C_IN)
|
||||
{
|
||||
struct txt_record *t;
|
||||
@@ -1903,6 +1914,8 @@ size_t answer_request(struct dns_header
|
||||
|
||||
if (nxdomain)
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
+ else if (notimp)
|
||||
+ SET_RCODE(header, NOTIMP);
|
||||
else
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
header->ancount = htons(anscount);
|
||||
@@ -0,0 +1,63 @@
|
||||
From cbb5b17ad8e03e08ade62376a4f6a2066e55960d Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 23 Oct 2018 23:45:57 +0100
|
||||
Subject: [PATCH 05/32] Fix logging in cf5984367bc6a949e3803a576512c5a7bc48ebab
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc1035.c | 27 ++++++++++++++++++---------
|
||||
1 file changed, 18 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1335,7 +1335,6 @@ size_t answer_request(struct dns_header
|
||||
{
|
||||
unsigned long ttl = daemon->local_ttl;
|
||||
int ok = 1;
|
||||
- log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
#ifndef NO_ID
|
||||
/* Dynamically generate stat record */
|
||||
if (t->stat != 0)
|
||||
@@ -1345,11 +1344,14 @@ size_t answer_request(struct dns_header
|
||||
ok = 0;
|
||||
}
|
||||
#endif
|
||||
- if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
- ttl, NULL,
|
||||
- T_TXT, t->class, "t", t->len, t->txt))
|
||||
- anscount++;
|
||||
-
|
||||
+ if (ok)
|
||||
+ {
|
||||
+ log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
+ if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
+ ttl, NULL,
|
||||
+ T_TXT, t->class, "t", t->len, t->txt))
|
||||
+ anscount++;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1357,12 +1359,19 @@ size_t answer_request(struct dns_header
|
||||
|
||||
if (qclass == C_CHAOS)
|
||||
{
|
||||
- /* don't forward *.bind and *.server chaos queries */
|
||||
+ /* don't forward *.bind and *.server chaos queries - always reply with NOTIMP */
|
||||
if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name))
|
||||
{
|
||||
if (!ans)
|
||||
- notimp = 1, auth = 0;
|
||||
- ans = 1;
|
||||
+ {
|
||||
+ notimp = 1, auth = 0;
|
||||
+ if (!dryrun)
|
||||
+ {
|
||||
+ addr.addr.rcode.rcode = NOTIMP;
|
||||
+ log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
|
||||
+ }
|
||||
+ ans = 1;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
From 6f7812d97bc8f87004c0a5069c6c94c64af78106 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 23 Oct 2018 23:54:44 +0100
|
||||
Subject: [PATCH 06/32] Fix spurious AD flags in some DNS replies from local
|
||||
config.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc1035.c | 42 ++++++++++++++++++++++++------------------
|
||||
1 file changed, 24 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1330,7 +1330,7 @@ size_t answer_request(struct dns_header
|
||||
{
|
||||
if (t->class == qclass && hostname_isequal(name, t->name))
|
||||
{
|
||||
- ans = 1;
|
||||
+ ans = 1, sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl = daemon->local_ttl;
|
||||
@@ -1370,7 +1370,7 @@ size_t answer_request(struct dns_header
|
||||
addr.addr.rcode.rcode = NOTIMP;
|
||||
log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
|
||||
}
|
||||
- ans = 1;
|
||||
+ ans = 1, sec_data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1725,7 +1725,7 @@ size_t answer_request(struct dns_header
|
||||
}
|
||||
else if (is_name_synthetic(flag, name, &addr))
|
||||
{
|
||||
- ans = 1;
|
||||
+ ans = 1, sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
@@ -1763,25 +1763,27 @@ size_t answer_request(struct dns_header
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (!rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
- ans = found = 1;
|
||||
- if (!dryrun)
|
||||
- {
|
||||
- int offset;
|
||||
- log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
- &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
- {
|
||||
- anscount++;
|
||||
- if (rec->target)
|
||||
- rec->offset = offset;
|
||||
- }
|
||||
- }
|
||||
+ ans = found = 1;
|
||||
+ sec_data = 0;
|
||||
+ if (!dryrun)
|
||||
+ {
|
||||
+ int offset;
|
||||
+ log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
+ if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
+ &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
+ {
|
||||
+ anscount++;
|
||||
+ if (rec->target)
|
||||
+ rec->offset = offset;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
|
||||
{
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
@@ -1802,6 +1804,7 @@ size_t answer_request(struct dns_header
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
found = ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
int offset;
|
||||
@@ -1838,6 +1841,7 @@ size_t answer_request(struct dns_header
|
||||
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);
|
||||
}
|
||||
@@ -1850,6 +1854,7 @@ size_t answer_request(struct dns_header
|
||||
if (hostname_isequal(name, na->name))
|
||||
{
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
@@ -1862,11 +1867,12 @@ size_t answer_request(struct dns_header
|
||||
}
|
||||
|
||||
if (qtype == T_MAILB)
|
||||
- ans = 1, nxdomain = 1;
|
||||
+ ans = 1, nxdomain = 1, sec_data = 0;
|
||||
|
||||
if (qtype == T_SOA && option_bool(OPT_FILTER))
|
||||
{
|
||||
- ans = 1;
|
||||
+ ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, NULL);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
From 24b87607c1353e94689e8a2190571ab3f3b36f31 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
|
||||
Date: Wed, 24 Oct 2018 22:30:18 +0100
|
||||
Subject: [PATCH 07/32] Do not rely on dead code elimination, use array
|
||||
instead. Make options bits derived from size and count. Use size of option
|
||||
bits and last supported bit in computation. No new change would be required
|
||||
when new options are added. Just change OPT_LAST constant.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/dnsmasq.h | 11 +++++++----
|
||||
src/option.c | 10 ++--------
|
||||
2 files changed, 9 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -200,9 +200,6 @@ struct event_desc {
|
||||
#define EC_MISC 5
|
||||
#define EC_INIT_OFFSET 10
|
||||
|
||||
-/* Trust the compiler dead-code eliminator.... */
|
||||
-#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
||||
-
|
||||
#define OPT_BOGUSPRIV 0
|
||||
#define OPT_FILTER 1
|
||||
#define OPT_LOG 2
|
||||
@@ -264,6 +261,12 @@ struct event_desc {
|
||||
#define OPT_UBUS 58
|
||||
#define OPT_LAST 59
|
||||
|
||||
+#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
+#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
+#define option_var(x) (daemon->options[(x) / OPTION_BITS])
|
||||
+#define option_val(x) ((1u) << ((x) % OPTION_BITS))
|
||||
+#define option_bool(x) (option_var(x) & option_val(x))
|
||||
+
|
||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||
#define MS_TFTP LOG_USER
|
||||
@@ -978,7 +981,7 @@ extern struct daemon {
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
|
||||
- unsigned int options, options2;
|
||||
+ unsigned int options[OPTION_SIZE];
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
time_t last_resolv;
|
||||
char *servers_file;
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -1490,18 +1490,12 @@ static int parse_dhcp_opt(char *errstr,
|
||||
|
||||
void set_option_bool(unsigned int opt)
|
||||
{
|
||||
- if (opt < 32)
|
||||
- daemon->options |= 1u << opt;
|
||||
- else
|
||||
- daemon->options2 |= 1u << (opt - 32);
|
||||
+ option_var(opt) |= option_val(opt);
|
||||
}
|
||||
|
||||
void reset_option_bool(unsigned int opt)
|
||||
{
|
||||
- if (opt < 32)
|
||||
- daemon->options &= ~(1u << opt);
|
||||
- else
|
||||
- daemon->options2 &= ~(1u << (opt - 32));
|
||||
+ option_var(opt) &= ~(option_val(opt));
|
||||
}
|
||||
|
||||
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
|
||||
@@ -0,0 +1,63 @@
|
||||
From 3a5a84cdd1488bad118eeac72d09a60299bca744 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 31 Oct 2018 21:30:13 +0000
|
||||
Subject: [PATCH 08/32] Fix Makefile lines generating UBUS linker config.
|
||||
|
||||
If arg2 of pkg-wrapper is "--copy", then arg1 is NOT the name of
|
||||
the package manager (--copy doesn't invoke it) it's a secondary
|
||||
config string that inhibts the copy if found. This patch allows that
|
||||
to be the empty string, for unconditional copy, and modifies the
|
||||
ubus linker config to use it. It worked by coincidence before, because
|
||||
there was no config string called "pkg-config".
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
Makefile | 2 +-
|
||||
bld/pkg-wrapper | 14 ++++++++------
|
||||
2 files changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -53,7 +53,7 @@ top?=$(CURDIR)
|
||||
|
||||
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
-ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS $(PKG_CONFIG) --copy -lubox -lubus`
|
||||
+ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
|
||||
--- a/bld/pkg-wrapper
|
||||
+++ b/bld/pkg-wrapper
|
||||
@@ -11,23 +11,25 @@ in=`cat`
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $search >/dev/null 2>&1; then
|
||||
-# Nasty, nasty, in --copy, arg 2 is another config to search for, use with NO_GMP
|
||||
+# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
- if grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
+ if [ -z "$pkg" ]; then
|
||||
+ pkg="$*"
|
||||
+ elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
+ echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
pkg=""
|
||||
else
|
||||
pkg="$*"
|
||||
fi
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
+ echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
pkg=`$pkg --static $op $*`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
fi
|
||||
-
|
||||
+
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
+ echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
@@ -0,0 +1,41 @@
|
||||
From 122392e0b352507cabb9e982208d35d2e56902e0 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 31 Oct 2018 22:24:02 +0000
|
||||
Subject: [PATCH 09/32] Revert 68f6312d4bae30b78daafcd6f51dc441b8685b1e
|
||||
|
||||
The above is intended to increase robustness, but actually does the
|
||||
opposite. The problem is that by ignoring SERVFAIL messages and hoping
|
||||
for a better answer from another of the servers we've forwarded to,
|
||||
we become vulnerable in the case that one or more of the configured
|
||||
servers is down or not responding.
|
||||
|
||||
Consider the case that a domain is indeed BOGUS, and we've send the
|
||||
query to n servers. With 68f6312d4bae30b78daafcd6f51dc441b8685b1e
|
||||
we ignore the first n-1 SERVFAIL replies, and only return the
|
||||
final n'th answer to the client. Now, if one of the servers we are
|
||||
forwarding to is down, then we won't get all n replies, and the
|
||||
client will never get an answer! This is a far more likely scenario
|
||||
than a temporary SERVFAIL from only one of a set of notionally identical
|
||||
servers, so, on the ground of robustness, we have to believe
|
||||
any SERVFAIL answers we get, and return them to the client.
|
||||
|
||||
The client could be using the same recursive servers we are,
|
||||
so it should, in theory, retry on SERVFAIL anyway.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/forward.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -957,8 +957,7 @@ void reply_query(int fd, int family, tim
|
||||
we get a good reply from another server. Kill it when we've
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
everything is broken */
|
||||
- if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
- (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
+ if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
|
||||
{
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
From 48d12f14c9c0fc8cf943b52774c3892517dd72d4 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 2 Nov 2018 21:55:04 +0000
|
||||
Subject: [PATCH 10/32] Remove the NO_FORK compile-time option, and support for
|
||||
uclinux.
|
||||
|
||||
In an era where everything has an MMU, this looks like
|
||||
an anachronism, and it adds to (Ok, multiplies!) the
|
||||
combinatorial explosion of compile-time options.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
CHANGELOG | 6 ++++++
|
||||
src/config.h | 21 ++-------------------
|
||||
src/dnsmasq.c | 14 --------------
|
||||
src/option.c | 4 +---
|
||||
4 files changed, 9 insertions(+), 36 deletions(-)
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -11,6 +11,12 @@ version 2.81
|
||||
This fix passes cache entries back from the TCP child process to
|
||||
the main server process, and fixes the problem.
|
||||
|
||||
+ Remove the NO_FORK compile-time option, and support for uclinux.
|
||||
+ In an era where everything has an MMU, this looks like
|
||||
+ an anachronism, and it adds to (Ok, multiplies!) the
|
||||
+ combinatorial explosion of compile-time options. Thanks to
|
||||
+ Kevin Darbyshire-Bryant for the patch.
|
||||
+
|
||||
|
||||
version 2.80
|
||||
Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method
|
||||
--- a/src/config.h
|
||||
+++ b/src/config.h
|
||||
@@ -239,27 +239,13 @@ HAVE_SOCKADDR_SA_LEN
|
||||
defined if struct sockaddr has sa_len field (*BSD)
|
||||
*/
|
||||
|
||||
-/* Must precede __linux__ since uClinux defines __linux__ too. */
|
||||
-#if defined(__uClinux__)
|
||||
-#define HAVE_LINUX_NETWORK
|
||||
-#define HAVE_GETOPT_LONG
|
||||
-#undef HAVE_SOCKADDR_SA_LEN
|
||||
-/* Never use fork() on uClinux. Note that this is subtly different from the
|
||||
- --keep-in-foreground option, since it also suppresses forking new
|
||||
- processes for TCP connections and disables the call-a-script on leasechange
|
||||
- system. It's intended for use on MMU-less kernels. */
|
||||
-#define NO_FORK
|
||||
-
|
||||
-#elif defined(__UCLIBC__)
|
||||
+#if defined(__UCLIBC__)
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
|
||||
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
|
||||
# define HAVE_GETOPT_LONG
|
||||
#endif
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
-#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
|
||||
-# define NO_FORK
|
||||
-#endif
|
||||
#if defined(__UCLIBC_HAS_IPV6__)
|
||||
# ifndef IPV6_V6ONLY
|
||||
# define IPV6_V6ONLY 26
|
||||
@@ -328,7 +314,7 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_DHCP
|
||||
#endif
|
||||
|
||||
-#if defined(NO_SCRIPT) || defined(NO_FORK)
|
||||
+#if defined(NO_SCRIPT)
|
||||
#undef HAVE_SCRIPT
|
||||
#undef HAVE_LUASCRIPT
|
||||
#endif
|
||||
@@ -372,9 +358,6 @@ static char *compile_opts =
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
"no-RTC "
|
||||
#endif
|
||||
-#ifdef NO_FORK
|
||||
-"no-MMU "
|
||||
-#endif
|
||||
#ifndef HAVE_DBUS
|
||||
"no-"
|
||||
#endif
|
||||
--- a/src/dnsmasq.c
|
||||
+++ b/src/dnsmasq.c
|
||||
@@ -485,7 +485,6 @@ int main (int argc, char **argv)
|
||||
if (chdir("/") != 0)
|
||||
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
|
||||
|
||||
-#ifndef NO_FORK
|
||||
if (!option_bool(OPT_NO_FORK))
|
||||
{
|
||||
pid_t pid;
|
||||
@@ -525,7 +524,6 @@ int main (int argc, char **argv)
|
||||
if (pid != 0)
|
||||
_exit(0);
|
||||
}
|
||||
-#endif
|
||||
|
||||
/* write pidfile _after_ forking ! */
|
||||
if (daemon->runfile)
|
||||
@@ -1628,12 +1626,10 @@ static int set_dns_listeners(time_t now)
|
||||
|
||||
}
|
||||
|
||||
-#ifndef NO_FORK
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pipes[i] != -1)
|
||||
poll_listen(daemon->tcp_pipes[i], POLLIN);
|
||||
-#endif
|
||||
|
||||
return wait;
|
||||
}
|
||||
@@ -1643,9 +1639,7 @@ static void check_dns_listeners(time_t n
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
int i;
|
||||
-#ifndef NO_FORK
|
||||
int pipefd[2];
|
||||
-#endif
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (poll_check(serverfdp->fd, POLLIN))
|
||||
@@ -1657,7 +1651,6 @@ static void check_dns_listeners(time_t n
|
||||
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
||||
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
|
||||
|
||||
-#ifndef NO_FORK
|
||||
/* Races. The child process can die before we read all of the data from the
|
||||
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
|
||||
process, and tcp_pipes to -1 and close the FD when we read the last
|
||||
@@ -1674,7 +1667,6 @@ static void check_dns_listeners(time_t n
|
||||
close(daemon->tcp_pipes[i]);
|
||||
daemon->tcp_pipes[i] = -1;
|
||||
}
|
||||
-#endif
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
@@ -1768,7 +1760,6 @@ static void check_dns_listeners(time_t n
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
while (retry_send(close(confd)));
|
||||
}
|
||||
-#ifndef NO_FORK
|
||||
else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0)
|
||||
{
|
||||
close(pipefd[1]); /* parent needs read pipe end. */
|
||||
@@ -1791,7 +1782,6 @@ static void check_dns_listeners(time_t n
|
||||
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
|
||||
daemon->log_id += TCP_MAX_QUERIES;
|
||||
}
|
||||
-#endif
|
||||
else
|
||||
{
|
||||
unsigned char *buff;
|
||||
@@ -1811,7 +1801,6 @@ static void check_dns_listeners(time_t n
|
||||
auth_dns = 0;
|
||||
}
|
||||
|
||||
-#ifndef NO_FORK
|
||||
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
@@ -1820,7 +1809,6 @@ static void check_dns_listeners(time_t n
|
||||
close(pipefd[0]); /* close read end in child. */
|
||||
daemon->pipe_to_parent = pipefd[1];
|
||||
}
|
||||
-#endif
|
||||
|
||||
/* start with no upstream connections. */
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
@@ -1846,13 +1834,11 @@ static void check_dns_listeners(time_t n
|
||||
shutdown(s->tcpfd, SHUT_RDWR);
|
||||
while (retry_send(close(s->tcpfd)));
|
||||
}
|
||||
-#ifndef NO_FORK
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
flush_log();
|
||||
_exit(0);
|
||||
}
|
||||
-#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -1828,9 +1828,7 @@ static int one_opt(int option, char *arg
|
||||
/* Sorry about the gross pre-processor abuse */
|
||||
case '6': /* --dhcp-script */
|
||||
case LOPT_LUASCRIPT: /* --dhcp-luascript */
|
||||
-# if defined(NO_FORK)
|
||||
- ret_err(_("cannot run scripts under uClinux"));
|
||||
-# elif !defined(HAVE_SCRIPT)
|
||||
+# if !defined(HAVE_SCRIPT)
|
||||
ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
|
||||
# else
|
||||
if (option == LOPT_LUASCRIPT)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
From 07e25da5bf26d46aad4f1d2eb19b260789182004 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 16 Dec 2018 18:21:58 +0000
|
||||
Subject: [PATCH 13/32] Treat DS and DNSKEY queries being forwarded the same as
|
||||
those locally originated.
|
||||
|
||||
The queries will not be forwarded to a server for a domain, unless
|
||||
there's a trust anchor provided for that domain. This allows, especially,
|
||||
suitable proof of non-existance for DS records to come from
|
||||
the parent domain for domains which are not signed.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc1035.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -916,6 +916,13 @@ unsigned int extract_request(struct dns_
|
||||
if (qtype == T_ANY)
|
||||
return F_IPV4 | F_IPV6;
|
||||
}
|
||||
+
|
||||
+ /* F_DNSSECOK as agument to search_servers() inhibits forwarding
|
||||
+ to servers for domains without a trust anchor. This make the
|
||||
+ behaviour for DS and DNSKEY queries we forward the same
|
||||
+ as for DS and DNSKEY queries we originate. */
|
||||
+ if (qtype == T_DS || qtype == T_DNSKEY)
|
||||
+ return F_DNSSECOK;
|
||||
|
||||
return F_QUERY;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
From 137e9f878fafb38369eab7d9dfe84e4228ff5f89 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
|
||||
Date: Sun, 16 Dec 2018 21:25:29 +0000
|
||||
Subject: [PATCH 14/32] Fix option parsing errors introduced in
|
||||
59e470381f84f2fdf0640c7bc67827f3f0c64784
|
||||
|
||||
Thanks to Kevin Darbyshire-Bryant for spotting this.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/option.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -3432,7 +3432,7 @@ static int one_opt(int option, char *arg
|
||||
{
|
||||
struct dhcp_netid *id = dhcp_tags(&arg);
|
||||
|
||||
- if (!id)
|
||||
+ if (!arg)
|
||||
{
|
||||
ret_err(gen_err);
|
||||
}
|
||||
@@ -3483,7 +3483,7 @@ static int one_opt(int option, char *arg
|
||||
{
|
||||
struct dhcp_netid *id = dhcp_tags(&arg);
|
||||
|
||||
- if (!id)
|
||||
+ if (!arg)
|
||||
{
|
||||
ret_err(gen_err);
|
||||
}
|
||||
@@ -3513,7 +3513,7 @@ static int one_opt(int option, char *arg
|
||||
new->opt = 10; /* PXE_MENU_PROMPT */
|
||||
new->netid = dhcp_tags(&arg);
|
||||
|
||||
- if (!new->netid)
|
||||
+ if (!arg)
|
||||
{
|
||||
dhcp_opt_free(new);
|
||||
ret_err(gen_err);
|
||||
@@ -0,0 +1,45 @@
|
||||
From 3becf468bad699bfdcb2d18d553bc72d4c79e23c Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
|
||||
Date: Wed, 12 Dec 2018 12:00:19 +0000
|
||||
Subject: [PATCH 15/32] fix ipv6 ipset bug in master
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Hi Simon,
|
||||
|
||||
Another one fallen out of the openwrt tree shake :-)
|
||||
|
||||
ipv6 ipset addresses weren’t being set correctly. patch attached
|
||||
|
||||
Cheers,
|
||||
|
||||
Kevin D-B
|
||||
|
||||
012C ACB2 28C6 C53E 9775 9123 B3A2 389B 9DE2 334A
|
||||
From b50fc0491e374186f982b019f293379955afd203 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Date: Wed, 12 Dec 2018 11:35:12 +0000
|
||||
Subject: [PATCH] ipset fix ternary order swap
|
||||
|
||||
ee87504 Remove ability to compile without IPv6 support introduced a
|
||||
ternary operator for ip address size. Unfortunately the true/false
|
||||
order was incorrect which meant ipv6 ipset addresses were added
|
||||
incorrectly.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/ipset.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/src/ipset.c
|
||||
+++ b/src/ipset.c
|
||||
@@ -120,7 +120,7 @@ static int new_add_to_ipset(const char *
|
||||
struct my_nfgenmsg *nfg;
|
||||
struct my_nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
- int addrsz = (af == AF_INET6) ? INADDRSZ : IN6ADDRSZ;
|
||||
+ int addrsz = (af == AF_INET6) ? IN6ADDRSZ : INADDRSZ;
|
||||
|
||||
if (strlen(setname) >= IPSET_MAXNAMELEN)
|
||||
{
|
||||
@@ -0,0 +1,50 @@
|
||||
From b683cf37f9f3dd3dc5d95d621ee75850d559b2e4 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
|
||||
Date: Mon, 10 Dec 2018 10:34:35 +0000
|
||||
Subject: [PATCH 16/32] build failure on master with NO_DHCPv6 and fix....
|
||||
|
||||
Hi Simon,
|
||||
|
||||
master has a build error when building without HAVE_DHCPv6
|
||||
|
||||
option.c: In function 'dhcp_context_free':
|
||||
option.c:1042:15: error: 'struct dhcp_context' has no member named 'template_interface'
|
||||
free(ctx->template_interface);
|
||||
|
||||
Sadly, need to put in a little conditional compilation ifdef'erey
|
||||
|
||||
Simplest patch in the world attached
|
||||
|
||||
Cheers,
|
||||
|
||||
Kevin D-B
|
||||
|
||||
012C ACB2 28C6 C53E 9775 9123 B3A2 389B 9DE2 334A
|
||||
|
||||
From 061eb8599636bb360e0b7fa5986935b86db39497 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Date: Mon, 10 Dec 2018 10:07:33 +0000
|
||||
Subject: [PATCH] option: fix non DHCPv6 build error
|
||||
|
||||
option.c: In function 'dhcp_context_free':
|
||||
option.c:1042:15: error: 'struct dhcp_context' has no member named 'template_interface'
|
||||
free(ctx->template_interface);
|
||||
^~
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/option.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -1039,7 +1039,9 @@ static void dhcp_context_free(struct dhc
|
||||
{
|
||||
dhcp_netid_free(ctx->filter);
|
||||
free(ctx->netid.net);
|
||||
+#ifdef HAVE_DHCP6
|
||||
free(ctx->template_interface);
|
||||
+#endif
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
From e7bfd556c079c8b5e7425aed44abc35925b24043 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Mon, 31 Dec 2018 20:51:15 +0000
|
||||
Subject: [PATCH 17/32] Alter DHCP address selection after DECLINE in
|
||||
consec-addr mode. Avoid offering the same address after a recieving a DECLINE
|
||||
message to stop an infinite protocol loop. This has long been done in default
|
||||
address allocation mode: this adds similar behaviour when allocaing addresses
|
||||
consecutively.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/dhcp.c | 13 +++++++++++++
|
||||
src/dhcp6.c | 11 +++++++++--
|
||||
2 files changed, 22 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/src/dhcp.c
|
||||
+++ b/src/dhcp.c
|
||||
@@ -754,6 +754,19 @@ int address_allocate(struct dhcp_context
|
||||
if (addr.s_addr == d->router.s_addr)
|
||||
break;
|
||||
|
||||
+ /* in consec-ip mode, skip addresses equal to
|
||||
+ the number of addresses rejected by clients. This
|
||||
+ should avoid the same client being offered the same
|
||||
+ address after it has rjected it. */
|
||||
+ if (option_bool(OPT_CONSEC_ADDR))
|
||||
+ {
|
||||
+ if (c->addr_epoch)
|
||||
+ {
|
||||
+ c->addr_epoch--;
|
||||
+ d = context; /* d non-NULL skips the address. */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* Addresses which end in .255 and .0 are broken in Windows even when using
|
||||
supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
|
||||
then 192.168.0.255 is a valid IP address, but not for Windows as it's
|
||||
--- a/src/dhcp6.c
|
||||
+++ b/src/dhcp6.c
|
||||
@@ -431,8 +431,15 @@ struct dhcp_context *address6_allocate(s
|
||||
else
|
||||
{
|
||||
if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
|
||||
- /* seed is largest extant lease addr in this context */
|
||||
- start = lease_find_max_addr6(c) + serial;
|
||||
+ {
|
||||
+ /* seed is largest extant lease addr in this context,
|
||||
+ skip addresses equal to the number of addresses rejected
|
||||
+ by clients. This should avoid the same client being offered the same
|
||||
+ address after it has rjected it. */
|
||||
+ start = lease_find_max_addr6(c) + serial + c->addr_epoch;
|
||||
+ if (c->addr_epoch)
|
||||
+ c->addr_epoch--;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
|
||||
@@ -0,0 +1,80 @@
|
||||
From bde46476ee06c96e821653dfdb8fa11fe7326998 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Mon, 31 Dec 2018 23:28:24 +0000
|
||||
Subject: [PATCH 18/32] Tidy all_addr union, merge log and rcode fields.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 2 +-
|
||||
src/dnsmasq.h | 6 +-----
|
||||
src/forward.c | 2 +-
|
||||
src/rfc1035.c | 6 +++---
|
||||
4 files changed, 6 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -1926,7 +1926,7 @@ void log_query(unsigned int flags, char
|
||||
sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
|
||||
else if (flags & F_RCODE)
|
||||
{
|
||||
- unsigned int rcode = addr->addr.rcode.rcode;
|
||||
+ unsigned int rcode = addr->addr.log.rcode;
|
||||
|
||||
if (rcode == SERVFAIL)
|
||||
dest = "SERVFAIL";
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -279,12 +279,8 @@ struct all_addr {
|
||||
struct in6_addr addr6;
|
||||
/* for log_query */
|
||||
struct {
|
||||
- unsigned short keytag, algo, digest;
|
||||
+ unsigned short keytag, algo, digest, rcode;
|
||||
} log;
|
||||
- /* for log_query */
|
||||
- struct {
|
||||
- unsigned int rcode;
|
||||
- } rcode;
|
||||
/* for cache_insert of DNSKEY, DS */
|
||||
struct {
|
||||
unsigned short class, type;
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -658,7 +658,7 @@ static size_t process_reply(struct dns_h
|
||||
if (rcode != NOERROR && rcode != NXDOMAIN)
|
||||
{
|
||||
struct all_addr a;
|
||||
- a.addr.rcode.rcode = rcode;
|
||||
+ a.addr.log.rcode = rcode;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -950,7 +950,7 @@ size_t setup_reply(struct dns_header *he
|
||||
else if (flags == F_SERVFAIL)
|
||||
{
|
||||
struct all_addr a;
|
||||
- a.addr.rcode.rcode = SERVFAIL;
|
||||
+ a.addr.log.rcode = SERVFAIL;
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||
SET_RCODE(header, SERVFAIL);
|
||||
}
|
||||
@@ -975,7 +975,7 @@ size_t setup_reply(struct dns_header *he
|
||||
else /* nowhere to forward to */
|
||||
{
|
||||
struct all_addr a;
|
||||
- a.addr.rcode.rcode = REFUSED;
|
||||
+ a.addr.log.rcode = REFUSED;
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||
SET_RCODE(header, REFUSED);
|
||||
}
|
||||
@@ -1374,7 +1374,7 @@ size_t answer_request(struct dns_header
|
||||
notimp = 1, auth = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
- addr.addr.rcode.rcode = NOTIMP;
|
||||
+ addr.addr.log.rcode = NOTIMP;
|
||||
log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
|
||||
}
|
||||
ans = 1, sec_data = 0;
|
||||
@@ -0,0 +1,290 @@
|
||||
From 65a01b71bb433c9466e4c78a73a8d8ed218ed4e8 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Mon, 31 Dec 2018 23:56:33 +0000
|
||||
Subject: [PATCH 19/32] Tidy address-union handling: move class into explicit
|
||||
argument.
|
||||
|
||||
This moves the class argument to cache-insert into an argument,
|
||||
rather then overloading a union in the address argument. Note that
|
||||
tha class is NOT stored in the cache other than for DS/DNSKEY entries,
|
||||
so must always be C_IN except for these. The data-extraction code
|
||||
ensures this as it only attempts to cache C_IN class records.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 57 ++++++++++++++++++++++-----------------------------
|
||||
src/dnsmasq.h | 2 +-
|
||||
src/dnssec.c | 13 +++---------
|
||||
src/rfc1035.c | 12 +++++------
|
||||
4 files changed, 34 insertions(+), 50 deletions(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -26,7 +26,7 @@ static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
|
||||
static void make_non_terminals(struct crec *source);
|
||||
-static struct crec *really_insert(char *name, struct all_addr *addr,
|
||||
+static struct crec *really_insert(char *name, struct all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
@@ -330,8 +330,8 @@ static int is_expired(time_t now, struct
|
||||
return 1;
|
||||
}
|
||||
|
||||
-static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags,
|
||||
- struct crec **target_crec, unsigned int *target_uid)
|
||||
+static struct crec *cache_scan_free(char *name, struct all_addr *addr, unsigned short class, time_t now,
|
||||
+ unsigned short flags, struct crec **target_crec, unsigned int *target_uid)
|
||||
{
|
||||
/* Scan and remove old entries.
|
||||
If (flags & F_FORWARD) then remove any forward entries for name and any expired
|
||||
@@ -350,6 +350,8 @@ static struct crec *cache_scan_free(char
|
||||
This entry will get re-used with the same name, to preserve CNAMEs. */
|
||||
|
||||
struct crec *crecp, **up;
|
||||
+
|
||||
+ (void)class;
|
||||
|
||||
if (flags & F_FORWARD)
|
||||
{
|
||||
@@ -381,7 +383,7 @@ static struct crec *cache_scan_free(char
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Deletion has to be class-sensitive for DS and DNSKEY */
|
||||
- if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
|
||||
+ if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == class)
|
||||
{
|
||||
if (crecp->flags & F_CONFIG)
|
||||
return crecp;
|
||||
@@ -464,7 +466,7 @@ void cache_start_insert(void)
|
||||
insert_error = 0;
|
||||
}
|
||||
|
||||
-struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
+struct crec *cache_insert(char *name, struct all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned short flags)
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
@@ -478,11 +480,11 @@ struct crec *cache_insert(char *name, st
|
||||
ttl = daemon->min_cache_ttl;
|
||||
}
|
||||
|
||||
- return really_insert(name, addr, now, ttl, flags);
|
||||
+ return really_insert(name, addr, class, now, ttl, flags);
|
||||
}
|
||||
|
||||
|
||||
-static struct crec *really_insert(char *name, struct all_addr *addr,
|
||||
+static struct crec *really_insert(char *name, struct all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned short flags)
|
||||
{
|
||||
struct crec *new, *target_crec = NULL;
|
||||
@@ -497,7 +499,7 @@ static struct crec *really_insert(char *
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. */
|
||||
- if ((new = cache_scan_free(name, addr, now, flags, &target_crec, &target_uid)))
|
||||
+ if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &target_uid)))
|
||||
{
|
||||
/* We're trying to insert a record over one from
|
||||
/etc/hosts or DHCP, or other config. If the
|
||||
@@ -553,21 +555,14 @@ static struct crec *really_insert(char *
|
||||
|
||||
if (freed_all)
|
||||
{
|
||||
- struct all_addr free_addr = new->addr.addr;;
|
||||
-
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- /* For DNSSEC records, addr holds class. */
|
||||
- if (new->flags & (F_DS | F_DNSKEY))
|
||||
- free_addr.addr.dnssec.class = new->uid;
|
||||
-#endif
|
||||
-
|
||||
+ /* For DNSSEC records, uid holds class. */
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
- cache_scan_free(cache_get_name(new), &free_addr, now, new->flags, NULL, NULL);
|
||||
+ cache_scan_free(cache_get_name(new), &new->addr.addr, new->uid, now, new->flags, NULL, NULL);
|
||||
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
- cache_scan_free(NULL, NULL, now, 0, NULL, NULL);
|
||||
+ cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL);
|
||||
freed_all = 1;
|
||||
}
|
||||
}
|
||||
@@ -615,15 +610,13 @@ static struct crec *really_insert(char *
|
||||
else
|
||||
*cache_get_name(new) = 0;
|
||||
|
||||
- if (addr)
|
||||
- {
|
||||
#ifdef HAVE_DNSSEC
|
||||
- if (flags & (F_DS | F_DNSKEY))
|
||||
- new->uid = addr->addr.dnssec.class;
|
||||
- else
|
||||
+ if (flags & (F_DS | F_DNSKEY))
|
||||
+ new->uid = class;
|
||||
#endif
|
||||
- new->addr.addr = *addr;
|
||||
- }
|
||||
+
|
||||
+ if (addr)
|
||||
+ new->addr.addr = *addr;
|
||||
|
||||
new->ttd = now + (time_t)ttl;
|
||||
new->next = new_chain;
|
||||
@@ -747,11 +740,11 @@ int cache_recv_insert(time_t now, int fd
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||
return 0;
|
||||
- crecp = really_insert(daemon->namebuff, &addr, now, ttl, flags);
|
||||
+ crecp = really_insert(daemon->namebuff, &addr, C_IN, now, ttl, flags);
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
- struct crec *newc = really_insert(daemon->namebuff, NULL, now, ttl, flags);
|
||||
+ struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
|
||||
/* This relies on the fact the the target of a CNAME immediately preceeds
|
||||
it because of the order of extraction in extract_addresses, and
|
||||
the order reversal on the new_chain. */
|
||||
@@ -780,10 +773,8 @@ int cache_recv_insert(time_t now, int fd
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1))
|
||||
return 0;
|
||||
- /* Cache needs to known class for DNSSEC stuff */
|
||||
- addr.addr.dnssec.class = class;
|
||||
-
|
||||
- crecp = really_insert(daemon->namebuff, &addr, now, ttl, flags);
|
||||
+
|
||||
+ crecp = really_insert(daemon->namebuff, NULL, class, now, ttl, flags);
|
||||
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
@@ -1463,7 +1454,7 @@ void cache_add_dhcp_entry(char *host_nam
|
||||
}
|
||||
else if (!(crec->flags & F_DHCP))
|
||||
{
|
||||
- cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
|
||||
+ cache_scan_free(host_name, NULL, C_IN, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
|
||||
/* scan_free deletes all addresses associated with name */
|
||||
break;
|
||||
}
|
||||
@@ -1490,7 +1481,7 @@ void cache_add_dhcp_entry(char *host_nam
|
||||
if (crec->flags & F_NEG)
|
||||
{
|
||||
flags |= F_REVERSE;
|
||||
- cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags, NULL, NULL);
|
||||
+ cache_scan_free(NULL, (struct all_addr *)host_address, C_IN, 0, flags, NULL, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -1144,7 +1144,7 @@ struct crec *cache_find_by_name(struct c
|
||||
void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
int cache_recv_insert(time_t now, int fd);
|
||||
-struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
+struct crec *cache_insert(char *name, struct all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
void cache_reload(void);
|
||||
void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_address, time_t ttd);
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -798,12 +798,9 @@ int dnssec_validate_by_ds(time_t now, st
|
||||
algo = *p++;
|
||||
keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
|
||||
|
||||
- /* Cache needs to known class for DNSSEC stuff */
|
||||
- a.addr.dnssec.class = class;
|
||||
-
|
||||
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
{
|
||||
- if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
|
||||
+ if (!(recp1 = cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
|
||||
{
|
||||
blockdata_free(key);
|
||||
return STAT_BOGUS;
|
||||
@@ -927,12 +924,9 @@ int dnssec_validate_ds(time_t now, struc
|
||||
algo = *p++;
|
||||
digest = *p++;
|
||||
|
||||
- /* Cache needs to known class for DNSSEC stuff */
|
||||
- a.addr.dnssec.class = class;
|
||||
-
|
||||
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
{
|
||||
- if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
|
||||
+ if (!(crecp = cache_insert(name, NULL, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
|
||||
{
|
||||
blockdata_free(key);
|
||||
return STAT_BOGUS;
|
||||
@@ -1021,8 +1015,7 @@ int dnssec_validate_ds(time_t now, struc
|
||||
{
|
||||
cache_start_insert();
|
||||
|
||||
- a.addr.dnssec.class = class;
|
||||
- if (!cache_insert(name, &a, now, ttl, flags))
|
||||
+ if (!cache_insert(name, NULL, class, now, ttl, flags))
|
||||
return STAT_BOGUS;
|
||||
|
||||
cache_end_insert();
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -701,7 +701,7 @@ int extract_addresses(struct dns_header
|
||||
goto cname_loop;
|
||||
}
|
||||
|
||||
- cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
|
||||
+ cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
@@ -719,7 +719,7 @@ int extract_addresses(struct dns_header
|
||||
ttl = find_soa(header, qlen, NULL, doctored);
|
||||
}
|
||||
if (ttl)
|
||||
- cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
+ cache_insert(NULL, &addr, C_IN, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -773,7 +773,7 @@ int extract_addresses(struct dns_header
|
||||
{
|
||||
if (!cname_count--)
|
||||
return 0; /* looped CNAMES */
|
||||
- newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
|
||||
+ newc = cache_insert(name, NULL, C_IN, now, attl, F_CNAME | F_FORWARD | secflag);
|
||||
if (newc)
|
||||
{
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
@@ -833,7 +833,7 @@ int extract_addresses(struct dns_header
|
||||
}
|
||||
#endif
|
||||
|
||||
- newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
|
||||
+ newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
@@ -860,7 +860,7 @@ int extract_addresses(struct dns_header
|
||||
pointing at this, inherit its TTL */
|
||||
if (ttl || cpp)
|
||||
{
|
||||
- newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
+ newc = cache_insert(name, NULL, C_IN, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
@@ -1054,7 +1054,7 @@ int check_for_bogus_wildcard(struct dns_
|
||||
/* Found a bogus address. Insert that info here, since there no SOA record
|
||||
to get the ttl from in the normal processing */
|
||||
cache_start_insert();
|
||||
- cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
|
||||
+ cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
|
||||
cache_end_insert();
|
||||
|
||||
return 1;
|
||||
@@ -0,0 +1,363 @@
|
||||
From ab194ed7ca433e4e2e8b2ec338bfa4e6aa886a4b Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 1 Jan 2019 01:35:30 +0000
|
||||
Subject: [PATCH 20/32] Futher address union tidying.
|
||||
|
||||
Pass DNSKEY and DS data into cache_insert via the address argument,
|
||||
now these data types are included in struct all_addr.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 116 ++++++++++++++++----------------------------------
|
||||
src/dnsmasq.h | 26 +++++------
|
||||
src/dnssec.c | 53 +++++++++++------------
|
||||
3 files changed, 73 insertions(+), 122 deletions(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -202,9 +202,9 @@ static void cache_hash(struct crec *crec
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_DNSKEY)
|
||||
- blockdata_free(crecp->addr.key.keydata);
|
||||
+ blockdata_free(crecp->addr.addr.addr.key.keydata);
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
- blockdata_free(crecp->addr.ds.keydata);
|
||||
+ blockdata_free(crecp->addr.addr.addr.ds.keydata);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -659,33 +659,22 @@ void cache_end_insert(void)
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
|
||||
|
||||
- if (flags & (F_IPV4 | F_IPV6))
|
||||
+ if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
||||
#ifdef HAVE_DNSSEC
|
||||
- else if (flags & F_DNSKEY)
|
||||
+ if (flags & F_DNSKEY)
|
||||
{
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.algo, sizeof(new_chain->addr.key.algo), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keytag, sizeof(new_chain->addr.key.keytag), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.flags, sizeof(new_chain->addr.key.flags), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keylen, sizeof(new_chain->addr.key.keylen), 0);
|
||||
- blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
|
||||
+ blockdata_write(new_chain->addr.addr.addr.key.keydata, new_chain->addr.addr.addr.key.keylen, daemon->pipe_to_parent);
|
||||
}
|
||||
else if (flags & F_DS)
|
||||
{
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
|
||||
/* A negative DS entry is possible and has no data, obviously. */
|
||||
if (!(flags & F_NEG))
|
||||
- {
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.algo, sizeof(new_chain->addr.ds.algo), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keytag, sizeof(new_chain->addr.ds.keytag), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.digest, sizeof(new_chain->addr.ds.digest), 0);
|
||||
- read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keylen, sizeof(new_chain->addr.ds.keylen), 0);
|
||||
- blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
|
||||
- }
|
||||
+ blockdata_write(new_chain->addr.addr.addr.ds.keydata, new_chain->addr.addr.addr.ds.keylen, daemon->pipe_to_parent);
|
||||
}
|
||||
#endif
|
||||
-
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,11 +725,30 @@ int cache_recv_insert(time_t now, int fd
|
||||
|
||||
ttl = difftime(ttd, now);
|
||||
|
||||
- if (flags & (F_IPV4 | F_IPV6))
|
||||
+ if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
|
||||
{
|
||||
+ unsigned short class = C_IN;
|
||||
+
|
||||
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||
return 0;
|
||||
- crecp = really_insert(daemon->namebuff, &addr, C_IN, now, ttl, flags);
|
||||
+
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ if (flags & F_DNSKEY)
|
||||
+ {
|
||||
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
|
||||
+ !(addr.addr.key.keydata = blockdata_read(fd, addr.addr.key.keylen)))
|
||||
+ return 0;
|
||||
+ }
|
||||
+ else if (flags & F_DS)
|
||||
+ {
|
||||
+ if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
|
||||
+ (flags & F_NEG) ||
|
||||
+ !(addr.addr.key.keydata = blockdata_read(fd, addr.addr.key.keylen)))
|
||||
+ return 0;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
@@ -764,58 +772,6 @@ int cache_recv_insert(time_t now, int fd
|
||||
}
|
||||
}
|
||||
}
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- else if (flags & (F_DNSKEY | F_DS))
|
||||
- {
|
||||
- unsigned short class, keylen, keyflags, keytag;
|
||||
- unsigned char algo, digest;
|
||||
- struct blockdata *keydata;
|
||||
-
|
||||
- if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1))
|
||||
- return 0;
|
||||
-
|
||||
- crecp = really_insert(daemon->namebuff, NULL, class, now, ttl, flags);
|
||||
-
|
||||
- if (flags & F_DNSKEY)
|
||||
- {
|
||||
- if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) ||
|
||||
- !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) ||
|
||||
- !read_write(fd, (unsigned char *)&keyflags, sizeof(keyflags), 1) ||
|
||||
- !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) ||
|
||||
- !(keydata = blockdata_read(fd, keylen)))
|
||||
- return 0;
|
||||
- }
|
||||
- else if (!(flags & F_NEG))
|
||||
- {
|
||||
- if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) ||
|
||||
- !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) ||
|
||||
- !read_write(fd, (unsigned char *)&digest, sizeof(digest), 1) ||
|
||||
- !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) ||
|
||||
- !(keydata = blockdata_read(fd, keylen)))
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- if (crecp)
|
||||
- {
|
||||
- if (flags & F_DNSKEY)
|
||||
- {
|
||||
- crecp->addr.key.algo = algo;
|
||||
- crecp->addr.key.keytag = keytag;
|
||||
- crecp->addr.key.flags = flags;
|
||||
- crecp->addr.key.keylen = keylen;
|
||||
- crecp->addr.key.keydata = keydata;
|
||||
- }
|
||||
- else if (!(flags & F_NEG))
|
||||
- {
|
||||
- crecp->addr.ds.algo = algo;
|
||||
- crecp->addr.ds.keytag = keytag;
|
||||
- crecp->addr.ds.digest = digest;
|
||||
- crecp->addr.ds.keylen = keylen;
|
||||
- crecp->addr.ds.keydata = keydata;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1290,15 +1246,15 @@ void cache_reload(void)
|
||||
#ifdef HAVE_DNSSEC
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
|
||||
- (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
+ (cache->addr.addr.addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
cache->name.namep = ds->name;
|
||||
- cache->addr.ds.keylen = ds->digestlen;
|
||||
- cache->addr.ds.algo = ds->algo;
|
||||
- cache->addr.ds.keytag = ds->keytag;
|
||||
- cache->addr.ds.digest = ds->digest_type;
|
||||
+ cache->addr.addr.addr.ds.keylen = ds->digestlen;
|
||||
+ cache->addr.addr.addr.ds.algo = ds->algo;
|
||||
+ cache->addr.addr.addr.ds.keytag = ds->keytag;
|
||||
+ cache->addr.addr.addr.ds.digest = ds->digest_type;
|
||||
cache->uid = ds->class;
|
||||
cache_hash(cache);
|
||||
make_non_terminals(cache);
|
||||
@@ -1775,12 +1731,12 @@ void dump_cache(time_t now)
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
if (!(cache->flags & F_NEG))
|
||||
- sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
- cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
+ sprintf(a, "%5u %3u %3u", cache->addr.addr.addr.ds.keytag,
|
||||
+ cache->addr.addr.addr.ds.algo, cache->addr.addr.addr.ds.digest);
|
||||
}
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
- sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||
- cache->addr.key.algo, cache->addr.key.flags);
|
||||
+ sprintf(a, "%5u %3u %3u", cache->addr.addr.addr.key.keytag,
|
||||
+ cache->addr.addr.addr.key.algo, cache->addr.addr.addr.key.flags);
|
||||
#endif
|
||||
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
|
||||
{
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -277,14 +277,21 @@ struct all_addr {
|
||||
union {
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
+ struct {
|
||||
+ struct blockdata *keydata;
|
||||
+ unsigned short keylen, flags, keytag;
|
||||
+ unsigned char algo;
|
||||
+ } key;
|
||||
+ struct {
|
||||
+ struct blockdata *keydata;
|
||||
+ unsigned short keylen, keytag;
|
||||
+ unsigned char algo;
|
||||
+ unsigned char digest;
|
||||
+ } ds;
|
||||
/* for log_query */
|
||||
struct {
|
||||
unsigned short keytag, algo, digest, rcode;
|
||||
} log;
|
||||
- /* for cache_insert of DNSKEY, DS */
|
||||
- struct {
|
||||
- unsigned short class, type;
|
||||
- } dnssec;
|
||||
} addr;
|
||||
};
|
||||
|
||||
@@ -414,17 +421,6 @@ struct crec {
|
||||
} target;
|
||||
unsigned int uid; /* 0 if union is interface-name */
|
||||
} cname;
|
||||
- struct {
|
||||
- struct blockdata *keydata;
|
||||
- unsigned short keylen, flags, keytag;
|
||||
- unsigned char algo;
|
||||
- } key;
|
||||
- struct {
|
||||
- struct blockdata *keydata;
|
||||
- unsigned short keylen, keytag;
|
||||
- unsigned char algo;
|
||||
- unsigned char digest;
|
||||
- } ds;
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
/* used as class if DNSKEY/DS, index to source for F_HOSTS */
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -628,10 +628,10 @@ static int validate_rrset(time_t now, st
|
||||
{
|
||||
/* iterate through all possible keys 4035 5.3.1 */
|
||||
for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
|
||||
- if (crecp->addr.key.algo == algo &&
|
||||
- crecp->addr.key.keytag == key_tag &&
|
||||
+ if (crecp->addr.addr.addr.key.algo == algo &&
|
||||
+ crecp->addr.addr.addr.key.keytag == key_tag &&
|
||||
crecp->uid == (unsigned int)class &&
|
||||
- verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
|
||||
+ verify(crecp->addr.addr.addr.key.keydata, crecp->addr.addr.addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
|
||||
return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
|
||||
}
|
||||
}
|
||||
@@ -728,10 +728,10 @@ int dnssec_validate_by_ds(time_t now, st
|
||||
const struct nettle_hash *hash;
|
||||
int sigcnt, rrcnt;
|
||||
|
||||
- if (recp1->addr.ds.algo == algo &&
|
||||
- recp1->addr.ds.keytag == keytag &&
|
||||
+ if (recp1->addr.addr.addr.ds.algo == algo &&
|
||||
+ recp1->addr.addr.addr.ds.keytag == keytag &&
|
||||
recp1->uid == (unsigned int)class &&
|
||||
- (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
|
||||
+ (hash = hash_find(ds_digest_name(recp1->addr.addr.addr.ds.digest))) &&
|
||||
hash_init(hash, &ctx, &digest))
|
||||
|
||||
{
|
||||
@@ -746,9 +746,9 @@ int dnssec_validate_by_ds(time_t now, st
|
||||
from_wire(name);
|
||||
|
||||
if (!(recp1->flags & F_NEG) &&
|
||||
- recp1->addr.ds.keylen == (int)hash->digest_size &&
|
||||
- (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
|
||||
- memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
|
||||
+ recp1->addr.addr.addr.ds.keylen == (int)hash->digest_size &&
|
||||
+ (ds_digest = blockdata_retrieve(recp1->addr.addr.addr.ds.keydata, recp1->addr.addr.addr.ds.keylen, NULL)) &&
|
||||
+ memcmp(ds_digest, digest, recp1->addr.addr.addr.ds.keylen) == 0 &&
|
||||
explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
|
||||
sigcnt != 0 && rrcnt != 0 &&
|
||||
validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
@@ -800,7 +800,13 @@ int dnssec_validate_by_ds(time_t now, st
|
||||
|
||||
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
{
|
||||
- if (!(recp1 = cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
|
||||
+ a.addr.key.keylen = rdlen - 4;
|
||||
+ a.addr.key.keydata = key;
|
||||
+ a.addr.key.algo = algo;
|
||||
+ a.addr.key.keytag = keytag;
|
||||
+ a.addr.key.flags = flags;
|
||||
+
|
||||
+ if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK))
|
||||
{
|
||||
blockdata_free(key);
|
||||
return STAT_BOGUS;
|
||||
@@ -813,12 +819,6 @@ int dnssec_validate_by_ds(time_t now, st
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
|
||||
-
|
||||
- recp1->addr.key.keylen = rdlen - 4;
|
||||
- recp1->addr.key.keydata = key;
|
||||
- recp1->addr.key.algo = algo;
|
||||
- recp1->addr.key.keytag = keytag;
|
||||
- recp1->addr.key.flags = flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -915,8 +915,7 @@ int dnssec_validate_ds(time_t now, struc
|
||||
int algo, digest, keytag;
|
||||
unsigned char *psave = p;
|
||||
struct blockdata *key;
|
||||
- struct crec *crecp;
|
||||
-
|
||||
+
|
||||
if (rdlen < 4)
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
@@ -926,7 +925,13 @@ int dnssec_validate_ds(time_t now, struc
|
||||
|
||||
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
{
|
||||
- if (!(crecp = cache_insert(name, NULL, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
|
||||
+ a.addr.ds.digest = digest;
|
||||
+ a.addr.ds.keydata = key;
|
||||
+ a.addr.ds.algo = algo;
|
||||
+ a.addr.ds.keytag = keytag;
|
||||
+ a.addr.ds.keylen = rdlen - 4;
|
||||
+
|
||||
+ if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
|
||||
{
|
||||
blockdata_free(key);
|
||||
return STAT_BOGUS;
|
||||
@@ -940,12 +945,6 @@ int dnssec_validate_ds(time_t now, struc
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
|
||||
-
|
||||
- crecp->addr.ds.digest = digest;
|
||||
- crecp->addr.ds.keydata = key;
|
||||
- crecp->addr.ds.algo = algo;
|
||||
- crecp->addr.ds.keytag = keytag;
|
||||
- crecp->addr.ds.keylen = rdlen - 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1711,8 +1710,8 @@ static int zone_status(char *name, int c
|
||||
do
|
||||
{
|
||||
if (crecp->uid == (unsigned int)class &&
|
||||
- ds_digest_name(crecp->addr.ds.digest) &&
|
||||
- algo_digest_name(crecp->addr.ds.algo))
|
||||
+ ds_digest_name(crecp->addr.addr.addr.ds.digest) &&
|
||||
+ algo_digest_name(crecp->addr.addr.addr.ds.algo))
|
||||
break;
|
||||
}
|
||||
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
From 2c594732eb7391e7cfa817598e33e61cab71131f Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 3 Jan 2019 13:42:03 +0000
|
||||
Subject: [PATCH 22/32] File logic bug in cache-marshalling code. Introduced a
|
||||
couple of commits back.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -742,8 +742,7 @@ int cache_recv_insert(time_t now, int fd
|
||||
else if (flags & F_DS)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
|
||||
- (flags & F_NEG) ||
|
||||
- !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
|
||||
+ (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
From 2daca52b80afdc92e7c976629a2bf8182335a626 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Weiske <cweiske@cweiske.de>
|
||||
Date: Thu, 3 Jan 2019 20:10:14 +0000
|
||||
Subject: [PATCH 23/32] Fix typo in ra-param man page section.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
man/dnsmasq.8 | 2 +-
|
||||
man/fr/dnsmasq.8 | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -1829,7 +1829,7 @@ The interval between router advertisemen
|
||||
.B --ra-param=eth0,60.
|
||||
The lifetime of the route may be changed or set to zero, which allows
|
||||
a router to advertise prefixes but not a route via itself.
|
||||
-.B --ra-parm=eth0,0,0
|
||||
+.B --ra-param=eth0,0,0
|
||||
(A value of zero for the interval means the default value.) All four parameters may be set at once.
|
||||
.B --ra-param=eth0,mtu:1280,low,60,1200
|
||||
|
||||
--- a/man/fr/dnsmasq.8
|
||||
+++ b/man/fr/dnsmasq.8
|
||||
@@ -1774,7 +1774,7 @@ Un intervalle (en secondes) entre les an
|
||||
.B --ra-param=eth0,60.
|
||||
La durée de vie de la route peut être changée ou mise à zéro, auquel cas
|
||||
le routeur peut annoncer les préfixes mais pas de route :
|
||||
-.B --ra-parm=eth0,0,0
|
||||
+.B --ra-param=eth0,0,0
|
||||
(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
|
||||
Ces quatre paramètres peuvent être configurés en une fois :
|
||||
.B --ra-param=eth0,mtu:1280,low,60,1200
|
||||
@@ -0,0 +1,523 @@
|
||||
From 5b99eae59d59a8e34a7e512059b98bbd803312f2 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 6 Jan 2019 23:09:50 +0000
|
||||
Subject: [PATCH 24/32] Cache SRV records.
|
||||
|
||||
Inpsired by a patch from Jeremy Allison, but completely re-rolled
|
||||
by srk. All bugs are mine.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/auth.c | 2 +-
|
||||
src/blockdata.c | 12 ++---
|
||||
src/cache.c | 64 ++++++++++++++--------
|
||||
src/dnsmasq.c | 2 -
|
||||
src/dnsmasq.h | 11 ++--
|
||||
src/rfc1035.c | 141 ++++++++++++++++++++++++++++++++++++++----------
|
||||
6 files changed, 166 insertions(+), 66 deletions(-)
|
||||
|
||||
--- a/src/auth.c
|
||||
+++ b/src/auth.c
|
||||
@@ -129,7 +129,7 @@ size_t answer_auth(struct dns_header *he
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
- unsigned short flag = 0;
|
||||
+ unsigned int flag = 0;
|
||||
int found = 0;
|
||||
int cname_wildcard = 0;
|
||||
|
||||
--- a/src/blockdata.c
|
||||
+++ b/src/blockdata.c
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
-
|
||||
static struct blockdata *keyblock_free;
|
||||
static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
|
||||
|
||||
@@ -54,11 +52,10 @@ void blockdata_init(void)
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
- if (option_bool(OPT_DNSSEC_VALID))
|
||||
- my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
|
||||
- blockdata_count * sizeof(struct blockdata),
|
||||
- blockdata_hwm * sizeof(struct blockdata),
|
||||
- blockdata_alloced * sizeof(struct blockdata));
|
||||
+ my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
|
||||
+ blockdata_count * sizeof(struct blockdata),
|
||||
+ blockdata_hwm * sizeof(struct blockdata),
|
||||
+ blockdata_alloced * sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
|
||||
@@ -178,4 +175,3 @@ struct blockdata *blockdata_read(int fd,
|
||||
return blockdata_alloc_real(fd, NULL, len);
|
||||
}
|
||||
|
||||
-#endif
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -27,7 +27,7 @@ static int bignames_left, hash_size;
|
||||
|
||||
static void make_non_terminals(struct crec *source);
|
||||
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
- time_t now, unsigned long ttl, unsigned short flags);
|
||||
+ 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. */
|
||||
static const struct {
|
||||
@@ -198,15 +198,17 @@ static void cache_hash(struct crec *crec
|
||||
*up = crecp;
|
||||
}
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
- if (crecp->flags & F_DNSKEY)
|
||||
+ if (crecp->flags & F_SRV)
|
||||
+ blockdata_free(crecp->addr.srv.target);
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ else if (crecp->flags & F_DNSKEY)
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.ds.keydata);
|
||||
-}
|
||||
#endif
|
||||
+}
|
||||
|
||||
static void cache_free(struct crec *crecp)
|
||||
{
|
||||
@@ -230,9 +232,7 @@ static void cache_free(struct crec *crec
|
||||
crecp->flags &= ~F_BIGNAME;
|
||||
}
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
cache_blockdata_free(crecp);
|
||||
-#endif
|
||||
}
|
||||
|
||||
/* insert a new cache entry at the head of the list (youngest entry) */
|
||||
@@ -331,7 +331,7 @@ static int is_expired(time_t now, struct
|
||||
}
|
||||
|
||||
static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now,
|
||||
- unsigned short flags, struct crec **target_crec, unsigned int *target_uid)
|
||||
+ unsigned int flags, struct crec **target_crec, unsigned int *target_uid)
|
||||
{
|
||||
/* Scan and remove old entries.
|
||||
If (flags & F_FORWARD) then remove any forward entries for name and any expired
|
||||
@@ -360,7 +360,7 @@ static struct crec *cache_scan_free(char
|
||||
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)) ||
|
||||
+ if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
|
||||
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
@@ -467,10 +467,10 @@ void cache_start_insert(void)
|
||||
}
|
||||
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
- time_t now, unsigned long ttl, unsigned short flags)
|
||||
+ time_t now, unsigned long ttl, unsigned int flags)
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
- if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
|
||||
+ if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
|
||||
{
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don't mess with TTL for DNSSEC records. */
|
||||
@@ -485,7 +485,7 @@ struct crec *cache_insert(char *name, un
|
||||
|
||||
|
||||
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
- time_t now, unsigned long ttl, unsigned short flags)
|
||||
+ time_t now, unsigned long ttl, unsigned int flags)
|
||||
{
|
||||
struct crec *new, *target_crec = NULL;
|
||||
union bigname *big_name = NULL;
|
||||
@@ -649,7 +649,7 @@ void cache_end_insert(void)
|
||||
{
|
||||
char *name = cache_get_name(new_chain);
|
||||
ssize_t m = strlen(name);
|
||||
- unsigned short flags = new_chain->flags;
|
||||
+ unsigned int flags = new_chain->flags;
|
||||
#ifdef HAVE_DNSSEC
|
||||
u16 class = new_chain->uid;
|
||||
#endif
|
||||
@@ -659,8 +659,10 @@ void cache_end_insert(void)
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
|
||||
|
||||
- if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
|
||||
+ if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
||||
+ if (flags & F_SRV)
|
||||
+ blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
@@ -699,7 +701,7 @@ int cache_recv_insert(time_t now, int fd
|
||||
union all_addr addr;
|
||||
unsigned long ttl;
|
||||
time_t ttd;
|
||||
- unsigned short flags;
|
||||
+ unsigned int flags;
|
||||
struct crec *crecp = NULL;
|
||||
|
||||
cache_start_insert();
|
||||
@@ -725,13 +727,16 @@ int cache_recv_insert(time_t now, int fd
|
||||
|
||||
ttl = difftime(ttd, now);
|
||||
|
||||
- if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS))
|
||||
+ if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
|
||||
{
|
||||
unsigned short class = C_IN;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||
return 0;
|
||||
-
|
||||
+
|
||||
+ if (flags & F_SRV && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
|
||||
+ return 0;
|
||||
+
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
@@ -802,7 +807,7 @@ struct crec *cache_find_by_name(struct c
|
||||
/* first search, look for relevant entries and push to top of list
|
||||
also free anything which has expired */
|
||||
struct crec *next, **up, **insert = NULL, **chainp = &ans;
|
||||
- unsigned short ins_flags = 0;
|
||||
+ unsigned int ins_flags = 0;
|
||||
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
|
||||
{
|
||||
@@ -1086,7 +1091,7 @@ int read_hostsfile(char *filename, unsig
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
int addr_count = 0, name_count = cache_size, lineno = 0;
|
||||
- unsigned short flags = 0;
|
||||
+ unsigned int flags = 0;
|
||||
union all_addr addr;
|
||||
int atnl, addrlen = 0;
|
||||
|
||||
@@ -1201,9 +1206,8 @@ void cache_reload(void)
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
|
||||
{
|
||||
-#ifdef HAVE_DNSSEC
|
||||
cache_blockdata_free(cache);
|
||||
-#endif
|
||||
+
|
||||
tmp = cache->hash_next;
|
||||
if (cache->flags & (F_HOSTS | F_CONFIG))
|
||||
{
|
||||
@@ -1381,7 +1385,7 @@ void cache_add_dhcp_entry(char *host_nam
|
||||
union all_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec = NULL, *fail_crec = NULL;
|
||||
- unsigned short flags = F_IPV4;
|
||||
+ unsigned int flags = F_IPV4;
|
||||
int in_hosts = 0;
|
||||
size_t addrlen = sizeof(struct in_addr);
|
||||
|
||||
@@ -1682,9 +1686,8 @@ void dump_cache(time_t now)
|
||||
#ifdef HAVE_AUTH
|
||||
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
|
||||
#endif
|
||||
-#ifdef HAVE_DNSSEC
|
||||
+
|
||||
blockdata_report();
|
||||
-#endif
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
@@ -1726,6 +1729,17 @@ void dump_cache(time_t now)
|
||||
p += sprintf(p, "%-30.30s ", sanitise(n));
|
||||
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
|
||||
a = sanitise(cache_get_cname_target(cache));
|
||||
+ else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
|
||||
+ {
|
||||
+ int targetlen = cache->addr.srv.targetlen;
|
||||
+ ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
|
||||
+ cache->addr.srv.weight, cache->addr.srv.srvport);
|
||||
+
|
||||
+ if (targetlen > (40 - len))
|
||||
+ targetlen = 40 - len;
|
||||
+ blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
|
||||
+ a[len + targetlen] = 0;
|
||||
+ }
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
@@ -1752,6 +1766,8 @@ void dump_cache(time_t now)
|
||||
t = "6";
|
||||
else if (cache->flags & F_CNAME)
|
||||
t = "C";
|
||||
+ else if (cache->flags & F_SRV)
|
||||
+ t = "V";
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (cache->flags & F_DS)
|
||||
t = "S";
|
||||
@@ -1913,6 +1929,8 @@ void log_query(unsigned int flags, char
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
dest = "<CNAME>";
|
||||
+ else if (flags & F_SRV)
|
||||
+ dest = "<SRV>";
|
||||
else if (flags & F_RRNAME)
|
||||
dest = arg;
|
||||
|
||||
--- a/src/dnsmasq.c
|
||||
+++ b/src/dnsmasq.c
|
||||
@@ -366,9 +366,7 @@ int main (int argc, char **argv)
|
||||
{
|
||||
cache_init();
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
blockdata_init();
|
||||
-#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -299,6 +299,10 @@ union all_addr {
|
||||
unsigned char algo;
|
||||
unsigned char digest;
|
||||
} ds;
|
||||
+ struct {
|
||||
+ struct blockdata *target;
|
||||
+ unsigned short targetlen, srvport, priority, weight;
|
||||
+ } srv;
|
||||
/* for log_query */
|
||||
struct {
|
||||
unsigned short keytag, algo, digest, rcode;
|
||||
@@ -426,7 +430,7 @@ struct crec {
|
||||
time_t ttd; /* time to die */
|
||||
/* used as class if DNSKEY/DS, index to source for F_HOSTS */
|
||||
unsigned int uid;
|
||||
- unsigned short flags;
|
||||
+ unsigned int flags;
|
||||
union {
|
||||
char sname[SMALLDNAME];
|
||||
union bigname *bname;
|
||||
@@ -470,6 +474,7 @@ struct crec {
|
||||
#define F_NOEXTRA (1u<<27)
|
||||
#define F_SERVFAIL (1u<<28)
|
||||
#define F_RCODE (1u<<29)
|
||||
+#define F_SRV (1u<<30)
|
||||
|
||||
#define UID_NONE 0
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
@@ -1142,7 +1147,7 @@ void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
int cache_recv_insert(time_t now, int fd);
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
- time_t now, unsigned long ttl, unsigned short flags);
|
||||
+ time_t now, unsigned long ttl, unsigned int flags);
|
||||
void cache_reload(void);
|
||||
void cache_add_dhcp_entry(char *host_name, int prot, union all_addr *host_address, time_t ttd);
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||
@@ -1158,7 +1163,6 @@ int read_hostsfile(char *filename, unsig
|
||||
struct crec **rhash, int hashsz);
|
||||
|
||||
/* blockdata.c */
|
||||
-#ifdef HAVE_DNSSEC
|
||||
void blockdata_init(void);
|
||||
void blockdata_report(void);
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len);
|
||||
@@ -1166,7 +1170,6 @@ void *blockdata_retrieve(struct blockdat
|
||||
struct blockdata *blockdata_read(int fd, size_t len);
|
||||
void blockdata_write(struct blockdata *block, size_t len, int fd);
|
||||
void blockdata_free(struct blockdata *blocks);
|
||||
-#endif
|
||||
|
||||
/* domain.c */
|
||||
char *get_domain(struct in_addr addr);
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -726,7 +726,7 @@ int extract_addresses(struct dns_header
|
||||
{
|
||||
/* everything other than PTR */
|
||||
struct crec *newc;
|
||||
- int addrlen;
|
||||
+ int addrlen = 0;
|
||||
|
||||
if (qtype == T_A)
|
||||
{
|
||||
@@ -738,7 +738,9 @@ int extract_addresses(struct dns_header
|
||||
addrlen = IN6ADDRSZ;
|
||||
flags |= F_IPV6;
|
||||
}
|
||||
- else
|
||||
+ else if (qtype == T_SRV)
|
||||
+ flags |= F_SRV;
|
||||
+ else
|
||||
continue;
|
||||
|
||||
cname_loop1:
|
||||
@@ -799,39 +801,61 @@ int extract_addresses(struct dns_header
|
||||
{
|
||||
found = 1;
|
||||
|
||||
- /* copy address into aligned storage */
|
||||
- if (!CHECK_LEN(header, p1, qlen, addrlen))
|
||||
- return 0; /* bad packet */
|
||||
- memcpy(&addr, p1, addrlen);
|
||||
-
|
||||
- /* check for returned address in private space */
|
||||
- if (check_rebind)
|
||||
+ if (flags & F_SRV)
|
||||
{
|
||||
- if ((flags & F_IPV4) &&
|
||||
- private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
- return 1;
|
||||
-
|
||||
- if ((flags & F_IPV6) &&
|
||||
- IN6_IS_ADDR_V4MAPPED(&addr.addr6))
|
||||
+ unsigned char *tmp = namep;
|
||||
+
|
||||
+ if (!CHECK_LEN(header, p1, qlen, 6))
|
||||
+ return 0; /* bad packet */
|
||||
+ GETSHORT(addr.srv.priority, p1);
|
||||
+ GETSHORT(addr.srv.weight, p1);
|
||||
+ GETSHORT(addr.srv.srvport, p1);
|
||||
+ if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
+ return 0;
|
||||
+ addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
|
||||
+ if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
|
||||
+ return 0;
|
||||
+
|
||||
+ /* we overwrote the original name, so get it back here. */
|
||||
+ if (!extract_name(header, qlen, &tmp, name, 1, 0))
|
||||
+ return 0;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* copy address into aligned storage */
|
||||
+ if (!CHECK_LEN(header, p1, qlen, addrlen))
|
||||
+ return 0; /* bad packet */
|
||||
+ memcpy(&addr, p1, addrlen);
|
||||
+
|
||||
+ /* check for returned address in private space */
|
||||
+ if (check_rebind)
|
||||
{
|
||||
- struct in_addr v4;
|
||||
- v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
|
||||
- if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
+ if ((flags & F_IPV4) &&
|
||||
+ private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
+
|
||||
+ if ((flags & F_IPV6) &&
|
||||
+ IN6_IS_ADDR_V4MAPPED(&addr.addr6))
|
||||
+ {
|
||||
+ struct in_addr v4;
|
||||
+ v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
|
||||
+ if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
+ return 1;
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
-
|
||||
+
|
||||
#ifdef HAVE_IPSET
|
||||
- if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
- {
|
||||
- ipsets_cur = ipsets;
|
||||
- while (*ipsets_cur)
|
||||
+ if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
{
|
||||
- log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
|
||||
- add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
+ 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);
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
#endif
|
||||
+ }
|
||||
|
||||
newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
|
||||
if (newc && cpp)
|
||||
@@ -1844,7 +1868,68 @@ size_t answer_request(struct dns_header
|
||||
*up = move;
|
||||
move->next = NULL;
|
||||
}
|
||||
-
|
||||
+
|
||||
+ if (!found)
|
||||
+ {
|
||||
+ cname_srv_restart:
|
||||
+ if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_SRV | (dryrun ? F_NO_RR : 0))) &&
|
||||
+ (!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 {
|
||||
+ if (crecp->flags & F_CNAME)
|
||||
+ {
|
||||
+ char *cname_target = cache_get_cname_target(crecp);
|
||||
+
|
||||
+ 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++;
|
||||
+ }
|
||||
+
|
||||
+ strcpy(name, cname_target);
|
||||
+ goto cname_srv_restart;
|
||||
+ }
|
||||
+ else if (crecp->flags & F_NEG)
|
||||
+ {
|
||||
+ if (crecp->flags & F_NXDOMAIN)
|
||||
+ nxdomain = 1;
|
||||
+ if (!dryrun)
|
||||
+ log_query(crecp->flags, name, NULL, NULL);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ unsigned char *p1 = ((unsigned char *)header) + nameoffset;
|
||||
+
|
||||
+ if (!dryrun)
|
||||
+ {
|
||||
+ log_query(crecp->flags, name, NULL, 0);
|
||||
+
|
||||
+ blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, name);
|
||||
+ if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
+ crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
|
||||
+ crecp->addr.srv.priority, crecp->addr.srv.weight, crecp->addr.srv.srvport,
|
||||
+ name))
|
||||
+ anscount++;
|
||||
+
|
||||
+
|
||||
+ /* restore name we overwrote */
|
||||
+ if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
+ return 0; /* bad packet */
|
||||
+ }
|
||||
+ }
|
||||
+ } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV | F_CNAME)));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
@@ -0,0 +1,23 @@
|
||||
From a90f09db4cc635941a32b973b57e58c662569625 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 9 Jan 2019 15:08:16 +0000
|
||||
Subject: [PATCH 25/32] Fix crash freeing negative SRV cache entries.
|
||||
|
||||
Thanks to Daniel for finding this one.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -200,7 +200,7 @@ static void cache_hash(struct crec *crec
|
||||
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
- if (crecp->flags & F_SRV)
|
||||
+ if (crecp->flags & F_SRV && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.srv.target);
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (crecp->flags & F_DNSKEY)
|
||||
@@ -0,0 +1,24 @@
|
||||
From 2896e2485e44c04e73a0b7c9f7cbc9c8515d0800 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 9 Jan 2019 15:12:34 +0000
|
||||
Subject: [PATCH 26/32] Check for not(DS or DNSKEY) in
|
||||
is_outdated_cname_pointer()
|
||||
|
||||
Previous check was _for_ IPV4, IPv6 CNAME, and I missed adding SRV.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -312,7 +312,7 @@ static int is_outdated_cname_pointer(str
|
||||
/* NB. record may be reused as DS or DNSKEY, where uid is
|
||||
overloaded for something completely different */
|
||||
if (crecp->addr.cname.target.cache &&
|
||||
- (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||
+ !(crecp->addr.cname.target.cache->flags & (F_DNSKEY | F_DS)) &&
|
||||
crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
From 9c0d445ef4abffa2b9342ad65e85ef425c1f83bb Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 9 Jan 2019 17:57:56 +0000
|
||||
Subject: [PATCH 27/32] Fix e7bfd556c079c8b5e7425aed44abc35925b24043 to
|
||||
actually work.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/dhcp.c | 54 +++++++++++++++++++++++++----------------------------
|
||||
src/dhcp6.c | 2 +-
|
||||
2 files changed, 26 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/src/dhcp.c
|
||||
+++ b/src/dhcp.c
|
||||
@@ -754,19 +754,6 @@ int address_allocate(struct dhcp_context
|
||||
if (addr.s_addr == d->router.s_addr)
|
||||
break;
|
||||
|
||||
- /* in consec-ip mode, skip addresses equal to
|
||||
- the number of addresses rejected by clients. This
|
||||
- should avoid the same client being offered the same
|
||||
- address after it has rjected it. */
|
||||
- if (option_bool(OPT_CONSEC_ADDR))
|
||||
- {
|
||||
- if (c->addr_epoch)
|
||||
- {
|
||||
- c->addr_epoch--;
|
||||
- d = context; /* d non-NULL skips the address. */
|
||||
- }
|
||||
- }
|
||||
-
|
||||
/* Addresses which end in .255 and .0 are broken in Windows even when using
|
||||
supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
|
||||
then 192.168.0.255 is a valid IP address, but not for Windows as it's
|
||||
@@ -778,24 +765,33 @@ int address_allocate(struct dhcp_context
|
||||
(!IN_CLASSC(ntohl(addr.s_addr)) ||
|
||||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
|
||||
{
|
||||
- struct ping_result *r;
|
||||
-
|
||||
- if ((r = do_icmp_ping(now, addr, j, loopback)))
|
||||
- {
|
||||
- /* consec-ip mode: we offered this address for another client
|
||||
- (different hash) recently, don't offer it to this one. */
|
||||
- if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
|
||||
- {
|
||||
- *addrp = addr;
|
||||
- return 1;
|
||||
- }
|
||||
- }
|
||||
+ /* in consec-ip mode, skip addresses equal to
|
||||
+ the number of addresses rejected by clients. This
|
||||
+ should avoid the same client being offered the same
|
||||
+ address after it has rjected it. */
|
||||
+ if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
|
||||
+ c->addr_epoch--;
|
||||
else
|
||||
{
|
||||
- /* address in use: perturb address selection so that we are
|
||||
- less likely to try this address again. */
|
||||
- if (!option_bool(OPT_CONSEC_ADDR))
|
||||
- c->addr_epoch++;
|
||||
+ struct ping_result *r;
|
||||
+
|
||||
+ if ((r = do_icmp_ping(now, addr, j, loopback)))
|
||||
+ {
|
||||
+ /* consec-ip mode: we offered this address for another client
|
||||
+ (different hash) recently, don't offer it to this one. */
|
||||
+ if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
|
||||
+ {
|
||||
+ *addrp = addr;
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* address in use: perturb address selection so that we are
|
||||
+ less likely to try this address again. */
|
||||
+ if (!option_bool(OPT_CONSEC_ADDR))
|
||||
+ c->addr_epoch++;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--- a/src/dhcp6.c
|
||||
+++ b/src/dhcp6.c
|
||||
@@ -436,7 +436,7 @@ struct dhcp_context *address6_allocate(s
|
||||
skip addresses equal to the number of addresses rejected
|
||||
by clients. This should avoid the same client being offered the same
|
||||
address after it has rjected it. */
|
||||
- start = lease_find_max_addr6(c) + serial + c->addr_epoch;
|
||||
+ start = lease_find_max_addr6(c) + 1 + serial + c->addr_epoch;
|
||||
if (c->addr_epoch)
|
||||
c->addr_epoch--;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
From 4bf62f616b82fad7a7f91195b0204dd64d79a35c Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 10 Jan 2019 21:54:22 +0000
|
||||
Subject: [PATCH 28/32] Tidy cache_blockdata_free()
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/cache.c | 15 +++++++++------
|
||||
1 file changed, 9 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -200,14 +200,17 @@ static void cache_hash(struct crec *crec
|
||||
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
- if (crecp->flags & F_SRV && !(crecp->flags & F_NEG))
|
||||
- blockdata_free(crecp->addr.srv.target);
|
||||
+ if (!(crecp->flags & F_NEG))
|
||||
+ {
|
||||
+ if (crecp->flags & F_SRV)
|
||||
+ blockdata_free(crecp->addr.srv.target);
|
||||
#ifdef HAVE_DNSSEC
|
||||
- else if (crecp->flags & F_DNSKEY)
|
||||
- blockdata_free(crecp->addr.key.keydata);
|
||||
- else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
- blockdata_free(crecp->addr.ds.keydata);
|
||||
+ else if (crecp->flags & F_DNSKEY)
|
||||
+ blockdata_free(crecp->addr.key.keydata);
|
||||
+ else if (crecp->flags & F_DS)
|
||||
+ blockdata_free(crecp->addr.ds.keydata);
|
||||
#endif
|
||||
+ }
|
||||
}
|
||||
|
||||
static void cache_free(struct crec *crecp)
|
||||
@@ -0,0 +1,52 @@
|
||||
From f8c77edbdffb8ada7753ea9fa104f0f6da70cfe3 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 10 Jan 2019 21:58:18 +0000
|
||||
Subject: [PATCH 29/32] Fix removal of DHCP_CLIENT_MAC options from DHCPv6
|
||||
relay replies.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc3315.c | 30 +++++++++++++++++-------------
|
||||
1 file changed, 17 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/src/rfc3315.c
|
||||
+++ b/src/rfc3315.c
|
||||
@@ -219,21 +219,25 @@ static int dhcp6_maybe_relay(struct stat
|
||||
if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
|
||||
return 0;
|
||||
|
||||
- int o = new_opt6(opt6_type(opt));
|
||||
- if (opt6_type(opt) == OPTION6_RELAY_MSG)
|
||||
+ /* Don't copy MAC address into reply. */
|
||||
+ if (opt6_type(opt) != OPTION6_CLIENT_MAC)
|
||||
{
|
||||
- struct in6_addr align;
|
||||
- /* the packet data is unaligned, copy to aligned storage */
|
||||
- memcpy(&align, inbuff + 2, IN6ADDRSZ);
|
||||
- state->link_address = &align;
|
||||
- /* zero is_unicast since that is now known to refer to the
|
||||
- relayed packet, not the original sent by the client */
|
||||
- if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
|
||||
- return 0;
|
||||
+ int o = new_opt6(opt6_type(opt));
|
||||
+ if (opt6_type(opt) == OPTION6_RELAY_MSG)
|
||||
+ {
|
||||
+ struct in6_addr align;
|
||||
+ /* the packet data is unaligned, copy to aligned storage */
|
||||
+ memcpy(&align, inbuff + 2, IN6ADDRSZ);
|
||||
+ state->link_address = &align;
|
||||
+ /* zero is_unicast since that is now known to refer to the
|
||||
+ relayed packet, not the original sent by the client */
|
||||
+ if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
|
||||
+ return 0;
|
||||
+ }
|
||||
+ else
|
||||
+ put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||
+ end_opt6(o);
|
||||
}
|
||||
- else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
|
||||
- put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||
- end_opt6(o);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -0,0 +1,54 @@
|
||||
From 18eac67c0a15b673c8d27002c248651b308093e4 Mon Sep 17 00:00:00 2001
|
||||
From: Steven Siloti <ssiloti@gmail.com>
|
||||
Date: Sun, 13 Jan 2019 22:56:36 +0000
|
||||
Subject: [PATCH 30/32] Fix entries in /etc/hosts disabling static leases.
|
||||
|
||||
It is possible for a config entry to have one address family specified by a
|
||||
dhcp-host directive and the other added from /etc/hosts. This is especially
|
||||
common on OpenWrt because it uses odhcpd for DHCPv6 and IPv6 leases are
|
||||
imported into dnsmasq via a hosts file.
|
||||
|
||||
To handle this case there need to be separate *_HOSTS flags for IPv4 and IPv6.
|
||||
Otherwise when the hosts file is reloaded it will clear the CONFIG_ADDR(6) flag
|
||||
which was set by the dhcp-host directive.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/dhcp-common.c | 8 ++++++--
|
||||
src/dnsmasq.h | 1 +
|
||||
2 files changed, 7 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/src/dhcp-common.c
|
||||
+++ b/src/dhcp-common.c
|
||||
@@ -372,7 +372,11 @@ void dhcp_update_configs(struct dhcp_con
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config->flags & CONFIG_ADDR_HOSTS)
|
||||
- config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
|
||||
+ config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
|
||||
+#ifdef HAVE_DHCP6
|
||||
+ if (config->flags & CONFIG_ADDR6_HOSTS)
|
||||
+ config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
|
||||
+#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
again:
|
||||
@@ -421,7 +425,7 @@ void dhcp_update_configs(struct dhcp_con
|
||||
(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr6, 128, 0)) || conf_tmp == config))
|
||||
{
|
||||
memcpy(&config->addr6, &crec->addr.addr6, IN6ADDRSZ);
|
||||
- config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
|
||||
+ config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -789,6 +789,7 @@ struct dhcp_config {
|
||||
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
||||
#define CONFIG_ADDR6 4096
|
||||
#define CONFIG_WILDCARD 8192
|
||||
+#define CONFIG_ADDR6_HOSTS 16384 /* address added by from /etc/hosts */
|
||||
|
||||
struct dhcp_opt {
|
||||
int opt, len, flags;
|
||||
@@ -0,0 +1,28 @@
|
||||
From d2d49907435433001ab00698a3e9ca2a7b5b3236 Mon Sep 17 00:00:00 2001
|
||||
From: Steven Siloti <ssiloti@gmail.com>
|
||||
Date: Thu, 17 Jan 2019 22:52:13 +0000
|
||||
Subject: [PATCH 31/32] Fix missing braces in
|
||||
8eac67c0a15b673c8d27002c248651b308093e4
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/dhcp-common.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/src/dhcp-common.c
|
||||
+++ b/src/dhcp-common.c
|
||||
@@ -371,12 +371,14 @@ void dhcp_update_configs(struct dhcp_con
|
||||
int prot = AF_INET;
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
+ {
|
||||
if (config->flags & CONFIG_ADDR_HOSTS)
|
||||
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
|
||||
#ifdef HAVE_DHCP6
|
||||
if (config->flags & CONFIG_ADDR6_HOSTS)
|
||||
config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
|
||||
#endif
|
||||
+ }
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
again:
|
||||
@@ -0,0 +1,61 @@
|
||||
From 28cfe36e1eee9d2c234e0256ad459956b415a3bb Mon Sep 17 00:00:00 2001
|
||||
From: Brian Haley <haleyb.dev@gmail.com>
|
||||
Date: Thu, 17 Jan 2019 23:21:23 +0000
|
||||
Subject: [PATCH 32/32] Change read_leases() to skip invalid entries.
|
||||
|
||||
There's no reason to stop reading the existing lease file
|
||||
when dnsmasq is started and an invalid entry is found, it
|
||||
can just be ignored. This was fallout from an Openstack
|
||||
bug where the file was being written incorrectly with []
|
||||
around IPv6 addresses.
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/lease.c | 22 +++++++++++++++-------
|
||||
1 file changed, 15 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/src/lease.c
|
||||
+++ b/src/lease.c
|
||||
@@ -60,8 +60,13 @@ static int read_leases(time_t now, FILE
|
||||
|
||||
if (fscanf(leasestream, " %64s %255s %764s",
|
||||
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
|
||||
- return 0;
|
||||
-
|
||||
+ {
|
||||
+ my_syslog(MS_DHCP | LOG_WARNING, _("ignoring invalid line in lease database: %s %s %s %s ..."),
|
||||
+ daemon->dhcp_buff3, daemon->dhcp_buff2,
|
||||
+ daemon->namebuff, daemon->dhcp_buff);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr4))
|
||||
{
|
||||
if ((lease = lease4_allocate(addr.addr4)))
|
||||
@@ -92,7 +97,12 @@ static int read_leases(time_t now, FILE
|
||||
}
|
||||
#endif
|
||||
else
|
||||
- return 0;
|
||||
+ {
|
||||
+ my_syslog(MS_DHCP | LOG_WARNING, _("ignoring invalid line in lease database, bad address: %s"),
|
||||
+ daemon->namebuff);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
|
||||
if (!lease)
|
||||
die (_("too many stored leases"), NULL, EC_MISC);
|
||||
@@ -172,10 +182,8 @@ void lease_init(time_t now)
|
||||
if (leasestream)
|
||||
{
|
||||
if (!read_leases(now, leasestream))
|
||||
- my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."),
|
||||
- daemon->dhcp_buff3, daemon->dhcp_buff2,
|
||||
- daemon->namebuff, daemon->dhcp_buff);
|
||||
-
|
||||
+ my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database cleanly"));
|
||||
+
|
||||
if (ferror(leasestream))
|
||||
die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
From e710c34469af4378c2db6fa0b0be88313adcb68f Mon Sep 17 00:00:00 2001
|
||||
From: Alin Nastac <alin.nastac@gmail.com>
|
||||
Date: Mon, 30 Sep 2019 15:30:26 +0100
|
||||
Subject: [PATCH] Fix crash when negative SRV response over TCP gets stored in
|
||||
LRU cache entry.
|
||||
|
||||
Patch extended to receive side of pipe by SRK.
|
||||
---
|
||||
src/cache.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -665,7 +665,11 @@ void cache_end_insert(void)
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
||||
if (flags & F_SRV)
|
||||
- blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
|
||||
+ {
|
||||
+ /* A negative SRV entry is possible and has no data, obviously. */
|
||||
+ if (!(flags & F_NEG))
|
||||
+ blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
|
||||
+ }
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
@@ -737,7 +741,7 @@ int cache_recv_insert(time_t now, int fd
|
||||
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||
return 0;
|
||||
|
||||
- if (flags & F_SRV && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
|
||||
+ if ((flags & F_SRV) && !(flags & F_NEG) && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -0,0 +1,375 @@
|
||||
From 4e96a4be685c9e4445f6ee79ad0b36b9119b502a Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 11 Nov 2020 23:25:04 +0000
|
||||
Subject: Fix remote buffer overflow CERT VU#434904
|
||||
|
||||
The problem is in the sort_rrset() function and allows a remote
|
||||
attacker to overwrite memory. Any dnsmasq instance with DNSSEC
|
||||
enabled is vulnerable.
|
||||
---
|
||||
CHANGELOG | 7 +-
|
||||
src/dnssec.c | 273 ++++++++++++++++++++++++++++-----------------------
|
||||
2 files changed, 158 insertions(+), 122 deletions(-)
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -1,3 +1,9 @@
|
||||
+ Fix a remote buffer overflow problem in the DNSSEC code. Any
|
||||
+ dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
|
||||
+ referenced by CERT VU#434904.
|
||||
+
|
||||
+
|
||||
+>>>>>>> Fix remote buffer overflow CERT VU#434904
|
||||
version 2.81
|
||||
Impove cache behaviour for TCP connections. For ease of
|
||||
implementaion, dnsmasq has always forked a new process to handle
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -222,138 +222,147 @@ static int check_date_range(u32 date_sta
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
-/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
|
||||
- data, pointed to by *p, should be used raw. */
|
||||
-static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
|
||||
- unsigned char **p, u16 **desc)
|
||||
+/* Return bytes of canonicalised rrdata one by one.
|
||||
+ Init state->ip with the RR, and state->end with the end of same.
|
||||
+ Init state->op to NULL.
|
||||
+ Init state->desc to RR descriptor.
|
||||
+ Init state->buff with a MAXDNAME * 2 buffer.
|
||||
+
|
||||
+ After each call which returns 1, state->op points to the next byte of data.
|
||||
+ On returning 0, the end has been reached.
|
||||
+*/
|
||||
+struct rdata_state {
|
||||
+ u16 *desc;
|
||||
+ size_t c;
|
||||
+ unsigned char *end, *ip, *op;
|
||||
+ char *buff;
|
||||
+};
|
||||
+
|
||||
+static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state *state)
|
||||
{
|
||||
- int d = **desc;
|
||||
+ int d;
|
||||
|
||||
- /* No more data needs mangling */
|
||||
- if (d == (u16)-1)
|
||||
+ if (state->op && state->c != 1)
|
||||
{
|
||||
- /* If there's more data than we have space for, just return what fits,
|
||||
- we'll get called again for more chunks */
|
||||
- if (end - *p > bufflen)
|
||||
- {
|
||||
- memcpy(buff, *p, bufflen);
|
||||
- *p += bufflen;
|
||||
- return bufflen;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
+ state->op++;
|
||||
+ state->c--;
|
||||
+ return 1;
|
||||
}
|
||||
-
|
||||
- (*desc)++;
|
||||
-
|
||||
- if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
|
||||
- /* domain-name, canonicalise */
|
||||
- return to_wire(buff);
|
||||
- else
|
||||
- {
|
||||
- /* plain data preceding a domain-name, don't run off the end of the data */
|
||||
- if ((end - *p) < d)
|
||||
- d = end - *p;
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ d = *(state->desc);
|
||||
|
||||
- if (d != 0)
|
||||
+ if (d == (u16)-1)
|
||||
{
|
||||
- memcpy(buff, *p, d);
|
||||
- *p += d;
|
||||
+ /* all the bytes to the end. */
|
||||
+ if ((state->c = state->end - state->ip) != 0)
|
||||
+ {
|
||||
+ state->op = state->ip;
|
||||
+ state->ip = state->end;;
|
||||
+ }
|
||||
+ else
|
||||
+ return 0;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ state->desc++;
|
||||
+
|
||||
+ if (d == (u16)0)
|
||||
+ {
|
||||
+ /* domain-name, canonicalise */
|
||||
+ int len;
|
||||
+
|
||||
+ if (!extract_name(header, plen, &state->ip, state->buff, 1, 0) ||
|
||||
+ (len = to_wire(state->buff)) == 0)
|
||||
+ continue;
|
||||
+
|
||||
+ state->c = len;
|
||||
+ state->op = (unsigned char *)state->buff;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* plain data preceding a domain-name, don't run off the end of the data */
|
||||
+ if ((state->end - state->ip) < d)
|
||||
+ d = state->end - state->ip;
|
||||
+
|
||||
+ if (d == 0)
|
||||
+ continue;
|
||||
+
|
||||
+ state->op = state->ip;
|
||||
+ state->c = d;
|
||||
+ state->ip += d;
|
||||
+ }
|
||||
}
|
||||
|
||||
- return d;
|
||||
+ return 1;
|
||||
}
|
||||
}
|
||||
|
||||
-/* Bubble sort the RRset into the canonical order.
|
||||
- Note that the byte-streams from two RRs may get unsynced: consider
|
||||
- RRs which have two domain-names at the start and then other data.
|
||||
- The domain-names may have different lengths in each RR, but sort equal
|
||||
-
|
||||
- ------------
|
||||
- |abcde|fghi|
|
||||
- ------------
|
||||
- |abcd|efghi|
|
||||
- ------------
|
||||
-
|
||||
- leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
-*/
|
||||
+/* Bubble sort the RRset into the canonical order. */
|
||||
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
- int swap, quit, i, j;
|
||||
+ int swap, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
for (swap = 0, i = 0; i < rrsetidx-1; i++)
|
||||
{
|
||||
- int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
|
||||
- u16 *dp1, *dp2;
|
||||
- unsigned char *end1, *end2;
|
||||
+ int rdlen1, rdlen2;
|
||||
+ struct rdata_state state1, state2;
|
||||
+
|
||||
/* Note that these have been determined to be OK previously,
|
||||
so we don't need to check for NULL return here. */
|
||||
- unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
|
||||
- unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
|
||||
-
|
||||
- p1 += 8; /* skip class, type, ttl */
|
||||
- GETSHORT(rdlen1, p1);
|
||||
- end1 = p1 + rdlen1;
|
||||
-
|
||||
- p2 += 8; /* skip class, type, ttl */
|
||||
- GETSHORT(rdlen2, p2);
|
||||
- end2 = p2 + rdlen2;
|
||||
-
|
||||
- dp1 = dp2 = rr_desc;
|
||||
-
|
||||
- for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
|
||||
+ state1.ip = skip_name(rrset[i], header, plen, 10);
|
||||
+ state2.ip = skip_name(rrset[i+1], header, plen, 10);
|
||||
+ state1.op = state2.op = NULL;
|
||||
+ state1.buff = buff1;
|
||||
+ state2.buff = buff2;
|
||||
+ state1.desc = state2.desc = rr_desc;
|
||||
+
|
||||
+ state1.ip += 8; /* skip class, type, ttl */
|
||||
+ GETSHORT(rdlen1, state1.ip);
|
||||
+ if (!CHECK_LEN(header, state1.ip, plen, rdlen1))
|
||||
+ return rrsetidx; /* short packet */
|
||||
+ state1.end = state1.ip + rdlen1;
|
||||
+
|
||||
+ state2.ip += 8; /* skip class, type, ttl */
|
||||
+ GETSHORT(rdlen2, state2.ip);
|
||||
+ if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
|
||||
+ return rrsetidx; /* short packet */
|
||||
+ state2.end = state2.ip + rdlen2;
|
||||
+
|
||||
+ while (1)
|
||||
{
|
||||
- if (left1 != 0)
|
||||
- memmove(buff1, buff1 + len1 - left1, left1);
|
||||
-
|
||||
- if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
|
||||
- {
|
||||
- quit = 1;
|
||||
- len1 = end1 - p1;
|
||||
- memcpy(buff1 + left1, p1, len1);
|
||||
- }
|
||||
- len1 += left1;
|
||||
-
|
||||
- if (left2 != 0)
|
||||
- memmove(buff2, buff2 + len2 - left2, left2);
|
||||
-
|
||||
- if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
|
||||
- {
|
||||
- quit = 1;
|
||||
- len2 = end2 - p2;
|
||||
- memcpy(buff2 + left2, p2, len2);
|
||||
- }
|
||||
- len2 += left2;
|
||||
-
|
||||
- if (len1 > len2)
|
||||
- left1 = len1 - len2, left2 = 0, len = len2;
|
||||
- else
|
||||
- left2 = len2 - len1, left1 = 0, len = len1;
|
||||
+ int ok1, ok2;
|
||||
|
||||
- rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
|
||||
-
|
||||
- if (rc > 0 || (rc == 0 && quit && len1 > len2))
|
||||
- {
|
||||
- unsigned char *tmp = rrset[i+1];
|
||||
- rrset[i+1] = rrset[i];
|
||||
- rrset[i] = tmp;
|
||||
- swap = quit = 1;
|
||||
- }
|
||||
- else if (rc == 0 && quit && len1 == len2)
|
||||
+ ok1 = get_rdata(header, plen, &state1);
|
||||
+ ok2 = get_rdata(header, plen, &state2);
|
||||
+
|
||||
+ if (!ok1 && !ok2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
+ {
|
||||
+ unsigned char *tmp = rrset[i+1];
|
||||
+ rrset[i+1] = rrset[i];
|
||||
+ rrset[i] = tmp;
|
||||
+ swap = 1;
|
||||
+ break;
|
||||
}
|
||||
- else if (rc < 0)
|
||||
- quit = 1;
|
||||
+ else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
+ break;
|
||||
+
|
||||
+ /* arrive here when bytes are equal, go round the loop again
|
||||
+ and compare the next ones. */
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
@@ -549,15 +558,18 @@ static int validate_rrset(time_t now, st
|
||||
wire_len = to_wire(keyname);
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
|
||||
from_wire(keyname);
|
||||
+
|
||||
+#define RRBUFLEN 300 /* Most RRs are smaller than this. */
|
||||
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
- int seg;
|
||||
- unsigned char *end, *cp;
|
||||
- u16 len, *dp;
|
||||
+ int j;
|
||||
+ struct rdata_state state;
|
||||
+ u16 len;
|
||||
+ unsigned char rrbuf[RRBUFLEN];
|
||||
|
||||
p = rrset[i];
|
||||
-
|
||||
+
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -566,12 +578,11 @@ static int validate_rrset(time_t now, st
|
||||
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
|
||||
if (labels < name_labels)
|
||||
{
|
||||
- int k;
|
||||
- for (k = name_labels - labels; k != 0; k--)
|
||||
+ for (j = name_labels - labels; j != 0; j--)
|
||||
{
|
||||
while (*name_start != '.' && *name_start != 0)
|
||||
name_start++;
|
||||
- if (k != 1 && *name_start == '.')
|
||||
+ if (j != 1 && *name_start == '.')
|
||||
name_start++;
|
||||
}
|
||||
|
||||
@@ -592,24 +603,44 @@ static int validate_rrset(time_t now, st
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS;
|
||||
|
||||
- end = p + rdlen;
|
||||
-
|
||||
- /* canonicalise rdata and calculate length of same, use name buffer as workspace.
|
||||
- Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
|
||||
- cp = p;
|
||||
- dp = rr_desc;
|
||||
- for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
|
||||
- len += end - cp;
|
||||
- len = htons(len);
|
||||
+ /* canonicalise rdata and calculate length of same, use
|
||||
+ name buffer as workspace for get_rdata. */
|
||||
+ state.ip = p;
|
||||
+ state.op = NULL;
|
||||
+ state.desc = rr_desc;
|
||||
+ state.buff = name;
|
||||
+ state.end = p + rdlen;
|
||||
+
|
||||
+ for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
+ if (j < RRBUFLEN)
|
||||
+ rrbuf[j] = *state.op;
|
||||
+
|
||||
+ len = htons((u16)j);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
+
|
||||
+ /* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
+ then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
+ go back to the start and do it in chunks. */
|
||||
+ if (j >= RRBUFLEN)
|
||||
+ {
|
||||
+ state.ip = p;
|
||||
+ state.op = NULL;
|
||||
+ state.desc = rr_desc;
|
||||
+
|
||||
+ for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
+ {
|
||||
+ rrbuf[j] = *state.op;
|
||||
+
|
||||
+ if (j == RRBUFLEN - 1)
|
||||
+ {
|
||||
+ hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
+ j = -1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- /* Now canonicalise again and digest. */
|
||||
- cp = p;
|
||||
- dp = rr_desc;
|
||||
- while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
|
||||
- hash->update(ctx, seg, (unsigned char *)name);
|
||||
- if (cp != end)
|
||||
- hash->update(ctx, end - cp, cp);
|
||||
+ if (j != 0)
|
||||
+ hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
@@ -0,0 +1,106 @@
|
||||
From 257ac0c5f7732cbc6aa96fdd3b06602234593aca Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 12 Nov 2020 18:49:23 +0000
|
||||
Subject: Check destination of DNS UDP query replies.
|
||||
|
||||
At any time, dnsmasq will have a set of sockets open, bound to
|
||||
random ports, on which it sends queries to upstream nameservers.
|
||||
This patch fixes the existing problem that a reply for ANY in-flight
|
||||
query would be accepted via ANY open port, which increases the
|
||||
chances of an attacker flooding answers "in the blind" in an
|
||||
attempt to poison the DNS cache. CERT VU#434904 refers.
|
||||
---
|
||||
CHANGELOG | 6 +++++-
|
||||
src/forward.c | 37 ++++++++++++++++++++++++++++---------
|
||||
2 files changed, 33 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -2,8 +2,12 @@
|
||||
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
|
||||
referenced by CERT VU#434904.
|
||||
|
||||
+ Be sure to only accept UDP DNS query replies at the address
|
||||
+ from which the query was originated. This keeps as much entropy
|
||||
+ in the {query-ID, random-port} tuple as possible, help defeat
|
||||
+ cache poisoning attacks. Refer: CERT VU#434904.
|
||||
+
|
||||
|
||||
->>>>>>> Fix remote buffer overflow CERT VU#434904
|
||||
version 2.81
|
||||
Impove cache behaviour for TCP connections. For ease of
|
||||
implementaion, dnsmasq has always forked a new process to handle
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
-static struct frec *lookup_frec(unsigned short id, void *hash);
|
||||
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
|
||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
union mysockaddr *addr,
|
||||
void *hash);
|
||||
@@ -797,7 +797,7 @@ void reply_query(int fd, int family, tim
|
||||
crc = questions_crc(header, n, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
- if (!(forward = lookup_frec(ntohs(header->id), hash)))
|
||||
+ if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
@@ -2289,14 +2289,25 @@ struct frec *get_new_frec(time_t now, in
|
||||
}
|
||||
|
||||
/* crc is all-ones if not known. */
|
||||
-static struct frec *lookup_frec(unsigned short id, void *hash)
|
||||
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == id &&
|
||||
(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
- return f;
|
||||
+ {
|
||||
+ /* sent from random port */
|
||||
+ if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
|
||||
+ return f;
|
||||
+
|
||||
+ if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
|
||||
+ return f;
|
||||
+
|
||||
+ /* sent to upstream from bound socket. */
|
||||
+ if (f->sentto->sfd && f->sentto->sfd->fd == fd)
|
||||
+ return f;
|
||||
+ }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -2357,12 +2368,20 @@ void server_gone(struct server *server)
|
||||
static unsigned short get_id(void)
|
||||
{
|
||||
unsigned short ret = 0;
|
||||
+ struct frec *f;
|
||||
|
||||
- do
|
||||
- ret = rand16();
|
||||
- while (lookup_frec(ret, NULL));
|
||||
-
|
||||
- return ret;
|
||||
+ while (1)
|
||||
+ {
|
||||
+ ret = rand16();
|
||||
+
|
||||
+ /* ensure id is unique. */
|
||||
+ for (f = daemon->frec_list; f; f = f->next)
|
||||
+ if (f->sentto && f->new_id == ret)
|
||||
+ break;
|
||||
+
|
||||
+ if (!f)
|
||||
+ return ret;
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,581 @@
|
||||
From 2d765867c597db18be9d876c9c17e2c0fe1953cd Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 12 Nov 2020 22:06:07 +0000
|
||||
Subject: Use SHA-256 to provide security against DNS cache poisoning.
|
||||
|
||||
Use the SHA-256 hash function to verify that DNS answers
|
||||
received are for the questions originally asked. This replaces
|
||||
the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
|
||||
---
|
||||
CHANGELOG | 5 +
|
||||
Makefile | 3 +-
|
||||
bld/Android.mk | 2 +-
|
||||
src/dnsmasq.h | 11 +-
|
||||
src/dnssec.c | 31 -----
|
||||
src/forward.c | 43 ++-----
|
||||
src/hash_questions.c | 281 +++++++++++++++++++++++++++++++++++++++++++
|
||||
src/rfc1035.c | 49 --------
|
||||
8 files changed, 301 insertions(+), 124 deletions(-)
|
||||
create mode 100644 src/hash_questions.c
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -7,6 +7,11 @@
|
||||
in the {query-ID, random-port} tuple as possible, help defeat
|
||||
cache poisoning attacks. Refer: CERT VU#434904.
|
||||
|
||||
+ Use the SHA-256 hash function to verify that DNS answers
|
||||
+ received are for the questions originally asked. This replaces
|
||||
+ the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
+ the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
|
||||
+
|
||||
|
||||
version 2.81
|
||||
Impove cache behaviour for TCP connections. For ease of
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -77,7 +77,8 @@ objs = cache.o rfc1035.o util.o option.o
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
- poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
|
||||
+ poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||
+ metrics.o hash_questions.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
--- a/bld/Android.mk
|
||||
+++ b/bld/Android.mk
|
||||
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
|
||||
- crypto.c dump.c ubus.c
|
||||
+ crypto.c dump.c ubus.c metrics.c hash_questions.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -644,11 +644,7 @@ struct hostsfile {
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
-#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
-#else
|
||||
-#define HASH_SIZE sizeof(int)
|
||||
-#endif
|
||||
+#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
@@ -1199,7 +1195,6 @@ int check_for_bogus_wildcard(struct dns_
|
||||
struct bogus_addr *baddr, time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
-unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
@@ -1227,9 +1222,11 @@ int dnssec_validate_reply(time_t now, st
|
||||
int check_unsigned, int *neganswer, int *nons);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
-unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
+/* hash_questions.c */
|
||||
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
+
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -2082,35 +2082,4 @@ size_t dnssec_generate_query(struct dns_
|
||||
return ret;
|
||||
}
|
||||
|
||||
-unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
-{
|
||||
- int q;
|
||||
- unsigned int len;
|
||||
- unsigned char *p = (unsigned char *)(header+1);
|
||||
- const struct nettle_hash *hash;
|
||||
- void *ctx;
|
||||
- unsigned char *digest;
|
||||
-
|
||||
- if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
|
||||
- return NULL;
|
||||
-
|
||||
- for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
- {
|
||||
- if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
- break; /* bad packet */
|
||||
-
|
||||
- len = to_wire(name);
|
||||
- hash->update(ctx, len, (unsigned char *)name);
|
||||
- /* CRC the class and type as well */
|
||||
- hash->update(ctx, 4, p);
|
||||
-
|
||||
- p += 4;
|
||||
- if (!CHECK_LEN(header, p, plen, 0))
|
||||
- break; /* bad packet */
|
||||
- }
|
||||
-
|
||||
- hash->digest(ctx, hash->digest_size, digest);
|
||||
- return digest;
|
||||
-}
|
||||
-
|
||||
#endif /* HAVE_DNSSEC */
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -248,19 +248,16 @@ static int forward_query(int udpfd, unio
|
||||
union all_addr *addrp = NULL;
|
||||
unsigned int flags = 0;
|
||||
struct server *start = NULL;
|
||||
-#ifdef HAVE_DNSSEC
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
+#ifdef HAVE_DNSSEC
|
||||
int do_dnssec = 0;
|
||||
-#else
|
||||
- unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
- void *hash = &crc;
|
||||
#endif
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
(void)do_bit;
|
||||
|
||||
/* may be no servers available. */
|
||||
- if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||
+ if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
||||
{
|
||||
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
||||
fall back to 1280, which should work everywhere on IPv6.
|
||||
@@ -761,9 +758,6 @@ void reply_query(int fd, int family, tim
|
||||
size_t nn;
|
||||
struct server *server;
|
||||
void *hash;
|
||||
-#ifndef HAVE_DNSSEC
|
||||
- unsigned int crc;
|
||||
-#endif
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -790,12 +784,7 @@ void reply_query(int fd, int family, tim
|
||||
if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
|
||||
server->edns_pktsz = daemon->edns_pktsz;
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
hash = hash_questions(header, n, daemon->namebuff);
|
||||
-#else
|
||||
- hash = &crc;
|
||||
- crc = questions_crc(header, n, daemon->namebuff);
|
||||
-#endif
|
||||
|
||||
if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
|
||||
return;
|
||||
@@ -1100,8 +1089,7 @@ void reply_query(int fd, int family, tim
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
|
||||
querystr("dnssec-query", querytype));
|
||||
|
||||
- if ((hash = hash_questions(header, nn, daemon->namebuff)))
|
||||
- memcpy(new->hash, hash, HASH_SIZE);
|
||||
+ memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
|
||||
new->new_id = get_id();
|
||||
header->id = htons(new->new_id);
|
||||
/* Save query for retransmission */
|
||||
@@ -1937,15 +1925,9 @@ unsigned char *tcp_request(int confd, ti
|
||||
if (!flags && last_server)
|
||||
{
|
||||
struct server *firstsendto = NULL;
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- unsigned char *newhash, hash[HASH_SIZE];
|
||||
- if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
|
||||
- memcpy(hash, newhash, HASH_SIZE);
|
||||
- else
|
||||
- memset(hash, 0, HASH_SIZE);
|
||||
-#else
|
||||
- unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
|
||||
-#endif
|
||||
+ unsigned char hash[HASH_SIZE];
|
||||
+ memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
|
||||
+
|
||||
/* Loop round available servers until we succeed in connecting to one.
|
||||
Note that this code subtly ensures that consecutive queries on this connection
|
||||
which can go to the same server, do so. */
|
||||
@@ -2068,20 +2050,11 @@ unsigned char *tcp_request(int confd, ti
|
||||
/* If the crc of the question section doesn't match the crc we sent, then
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
|
||||
- if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
|
||||
+ if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
|
||||
{
|
||||
m = 0;
|
||||
break;
|
||||
}
|
||||
-#else
|
||||
- if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
- {
|
||||
- m = 0;
|
||||
- break;
|
||||
- }
|
||||
-#endif
|
||||
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
@@ -2295,7 +2268,7 @@ static struct frec *lookup_frec(unsigned
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == id &&
|
||||
- (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
+ (memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
{
|
||||
/* sent from random port */
|
||||
if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
|
||||
--- /dev/null
|
||||
+++ b/src/hash_questions.c
|
||||
@@ -0,0 +1,281 @@
|
||||
+/* Copyright (c) 2012-2020 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/>.
|
||||
+*/
|
||||
+
|
||||
+
|
||||
+/* Hash the question section. This is used to safely detect query
|
||||
+ retransmission and to detect answers to questions we didn't ask, which
|
||||
+ might be poisoning attacks. Note that we decode the name rather
|
||||
+ than CRC the raw bytes, since replies might be compressed differently.
|
||||
+ We ignore case in the names for the same reason.
|
||||
+
|
||||
+ The hash used is SHA-256. If we're building with DNSSEC support,
|
||||
+ we use the Nettle cypto library. If not, we prefer not to
|
||||
+ add a dependency on Nettle, and use a stand-alone implementaion.
|
||||
+*/
|
||||
+
|
||||
+#include "dnsmasq.h"
|
||||
+
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
+{
|
||||
+ int q;
|
||||
+ unsigned char *p = (unsigned char *)(header+1);
|
||||
+ const struct nettle_hash *hash;
|
||||
+ void *ctx;
|
||||
+ unsigned char *digest;
|
||||
+
|
||||
+ if (!(hash = hash_find("sha256")) || !hash_init(hash, &ctx, &digest))
|
||||
+ {
|
||||
+ /* don't think this can ever happen. */
|
||||
+ static unsigned char dummy[HASH_SIZE];
|
||||
+ static int warned = 0;
|
||||
+
|
||||
+ if (warned)
|
||||
+ my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object"));
|
||||
+ warned = 1;
|
||||
+
|
||||
+ return dummy;
|
||||
+ }
|
||||
+
|
||||
+ for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
+ {
|
||||
+ char *cp, c;
|
||||
+
|
||||
+ if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
+ break; /* bad packet */
|
||||
+
|
||||
+ for (cp = name; (c = *cp); cp++)
|
||||
+ if (c >= 'A' && c <= 'Z')
|
||||
+ *cp += 'a' - 'A';
|
||||
+
|
||||
+ hash->update(ctx, cp - name, (unsigned char *)name);
|
||||
+ /* CRC the class and type as well */
|
||||
+ hash->update(ctx, 4, p);
|
||||
+
|
||||
+ p += 4;
|
||||
+ if (!CHECK_LEN(header, p, plen, 0))
|
||||
+ break; /* bad packet */
|
||||
+ }
|
||||
+
|
||||
+ hash->digest(ctx, hash->digest_size, digest);
|
||||
+ return digest;
|
||||
+}
|
||||
+
|
||||
+#else /* HAVE_DNSSEC */
|
||||
+
|
||||
+#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
+typedef unsigned char BYTE; // 8-bit byte
|
||||
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
+
|
||||
+typedef struct {
|
||||
+ BYTE data[64];
|
||||
+ WORD datalen;
|
||||
+ unsigned long long bitlen;
|
||||
+ WORD state[8];
|
||||
+} SHA256_CTX;
|
||||
+
|
||||
+static void sha256_init(SHA256_CTX *ctx);
|
||||
+static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
+static void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
|
||||
+
|
||||
+
|
||||
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
+{
|
||||
+ int q;
|
||||
+ unsigned char *p = (unsigned char *)(header+1);
|
||||
+ SHA256_CTX ctx;
|
||||
+ static BYTE digest[SHA256_BLOCK_SIZE];
|
||||
+
|
||||
+ sha256_init(&ctx);
|
||||
+
|
||||
+ for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
+ {
|
||||
+ char *cp, c;
|
||||
+
|
||||
+ if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
+ break; /* bad packet */
|
||||
+
|
||||
+ for (cp = name; (c = *cp); cp++)
|
||||
+ if (c >= 'A' && c <= 'Z')
|
||||
+ *cp += 'a' - 'A';
|
||||
+
|
||||
+ sha256_update(&ctx, (BYTE *)name, cp - name);
|
||||
+ /* CRC the class and type as well */
|
||||
+ sha256_update(&ctx, (BYTE *)p, 4);
|
||||
+
|
||||
+ p += 4;
|
||||
+ if (!CHECK_LEN(header, p, plen, 0))
|
||||
+ break; /* bad packet */
|
||||
+ }
|
||||
+
|
||||
+ sha256_final(&ctx, digest);
|
||||
+ return (unsigned char *)digest;
|
||||
+}
|
||||
+
|
||||
+/* Code from here onwards comes from https://github.com/B-Con/crypto-algorithms
|
||||
+ and was written by Brad Conte (brad@bradconte.com), to whom all credit is given.
|
||||
+
|
||||
+ This code is in the public domain, and the copyright notice at the head of this
|
||||
+ file does not apply to it.
|
||||
+*/
|
||||
+
|
||||
+
|
||||
+/****************************** MACROS ******************************/
|
||||
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
|
||||
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
|
||||
+
|
||||
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
|
||||
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
|
||||
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
|
||||
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
|
||||
+
|
||||
+/**************************** VARIABLES *****************************/
|
||||
+static const WORD k[64] = {
|
||||
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
+};
|
||||
+
|
||||
+/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
+static void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
|
||||
+{
|
||||
+ WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
|
||||
+
|
||||
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
+ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
|
||||
+ for ( ; i < 64; ++i)
|
||||
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
+
|
||||
+ a = ctx->state[0];
|
||||
+ b = ctx->state[1];
|
||||
+ c = ctx->state[2];
|
||||
+ d = ctx->state[3];
|
||||
+ e = ctx->state[4];
|
||||
+ f = ctx->state[5];
|
||||
+ g = ctx->state[6];
|
||||
+ h = ctx->state[7];
|
||||
+
|
||||
+ for (i = 0; i < 64; ++i)
|
||||
+ {
|
||||
+ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
|
||||
+ t2 = EP0(a) + MAJ(a,b,c);
|
||||
+ h = g;
|
||||
+ g = f;
|
||||
+ f = e;
|
||||
+ e = d + t1;
|
||||
+ d = c;
|
||||
+ c = b;
|
||||
+ b = a;
|
||||
+ a = t1 + t2;
|
||||
+ }
|
||||
+
|
||||
+ ctx->state[0] += a;
|
||||
+ ctx->state[1] += b;
|
||||
+ ctx->state[2] += c;
|
||||
+ ctx->state[3] += d;
|
||||
+ ctx->state[4] += e;
|
||||
+ ctx->state[5] += f;
|
||||
+ ctx->state[6] += g;
|
||||
+ ctx->state[7] += h;
|
||||
+}
|
||||
+
|
||||
+static void sha256_init(SHA256_CTX *ctx)
|
||||
+{
|
||||
+ ctx->datalen = 0;
|
||||
+ ctx->bitlen = 0;
|
||||
+ ctx->state[0] = 0x6a09e667;
|
||||
+ ctx->state[1] = 0xbb67ae85;
|
||||
+ ctx->state[2] = 0x3c6ef372;
|
||||
+ ctx->state[3] = 0xa54ff53a;
|
||||
+ ctx->state[4] = 0x510e527f;
|
||||
+ ctx->state[5] = 0x9b05688c;
|
||||
+ ctx->state[6] = 0x1f83d9ab;
|
||||
+ ctx->state[7] = 0x5be0cd19;
|
||||
+}
|
||||
+
|
||||
+static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
|
||||
+{
|
||||
+ WORD i;
|
||||
+
|
||||
+ for (i = 0; i < len; ++i)
|
||||
+ {
|
||||
+ ctx->data[ctx->datalen] = data[i];
|
||||
+ ctx->datalen++;
|
||||
+ if (ctx->datalen == 64) {
|
||||
+ sha256_transform(ctx, ctx->data);
|
||||
+ ctx->bitlen += 512;
|
||||
+ ctx->datalen = 0;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
+{
|
||||
+ WORD i;
|
||||
+
|
||||
+ i = ctx->datalen;
|
||||
+
|
||||
+ // Pad whatever data is left in the buffer.
|
||||
+ if (ctx->datalen < 56)
|
||||
+ {
|
||||
+ ctx->data[i++] = 0x80;
|
||||
+ while (i < 56)
|
||||
+ ctx->data[i++] = 0x00;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ctx->data[i++] = 0x80;
|
||||
+ while (i < 64)
|
||||
+ ctx->data[i++] = 0x00;
|
||||
+ sha256_transform(ctx, ctx->data);
|
||||
+ memset(ctx->data, 0, 56);
|
||||
+ }
|
||||
+
|
||||
+ // Append to the padding the total message's length in bits and transform.
|
||||
+ ctx->bitlen += ctx->datalen * 8;
|
||||
+ ctx->data[63] = ctx->bitlen;
|
||||
+ ctx->data[62] = ctx->bitlen >> 8;
|
||||
+ ctx->data[61] = ctx->bitlen >> 16;
|
||||
+ ctx->data[60] = ctx->bitlen >> 24;
|
||||
+ ctx->data[59] = ctx->bitlen >> 32;
|
||||
+ ctx->data[58] = ctx->bitlen >> 40;
|
||||
+ ctx->data[57] = ctx->bitlen >> 48;
|
||||
+ ctx->data[56] = ctx->bitlen >> 56;
|
||||
+ sha256_transform(ctx, ctx->data);
|
||||
+
|
||||
+ // Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
+ // reverse all the bytes when copying the final state to the output hash.
|
||||
+ for (i = 0; i < 4; ++i)
|
||||
+ {
|
||||
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -333,55 +333,6 @@ unsigned char *skip_section(unsigned cha
|
||||
return ansp;
|
||||
}
|
||||
|
||||
-/* CRC the question section. This is used to safely detect query
|
||||
- retransmission and to detect answers to questions we didn't ask, which
|
||||
- might be poisoning attacks. Note that we decode the name rather
|
||||
- than CRC the raw bytes, since replies might be compressed differently.
|
||||
- We ignore case in the names for the same reason. Return all-ones
|
||||
- if there is not question section. */
|
||||
-#ifndef HAVE_DNSSEC
|
||||
-unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
|
||||
-{
|
||||
- int q;
|
||||
- unsigned int crc = 0xffffffff;
|
||||
- unsigned char *p1, *p = (unsigned char *)(header+1);
|
||||
-
|
||||
- for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
- {
|
||||
- if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
- return crc; /* bad packet */
|
||||
-
|
||||
- for (p1 = (unsigned char *)name; *p1; p1++)
|
||||
- {
|
||||
- int i = 8;
|
||||
- char c = *p1;
|
||||
-
|
||||
- if (c >= 'A' && c <= 'Z')
|
||||
- c += 'a' - 'A';
|
||||
-
|
||||
- crc ^= c << 24;
|
||||
- while (i--)
|
||||
- crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||
- }
|
||||
-
|
||||
- /* CRC the class and type as well */
|
||||
- for (p1 = p; p1 < p+4; p1++)
|
||||
- {
|
||||
- int i = 8;
|
||||
- crc ^= *p1 << 24;
|
||||
- while (i--)
|
||||
- crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||
- }
|
||||
-
|
||||
- p += 4;
|
||||
- if (!CHECK_LEN(header, p, plen, 0))
|
||||
- return crc; /* bad packet */
|
||||
- }
|
||||
-
|
||||
- return crc;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
{
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
@@ -0,0 +1,122 @@
|
||||
From 059aded0700309308dafd9720b0313ce52f6e189 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 12 Nov 2020 23:09:15 +0000
|
||||
Subject: Optimse RR digest calculation in DNSSEC.
|
||||
|
||||
If an RR is of a type which doesn't need canonicalisation,
|
||||
bypass the relatively slow canonicalisation code, and insert
|
||||
it direct into the digest.
|
||||
---
|
||||
src/dnssec.c | 82 +++++++++++++++++++++++++++++++---------------------
|
||||
1 file changed, 49 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -559,7 +559,7 @@ static int validate_rrset(time_t now, st
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
|
||||
from_wire(keyname);
|
||||
|
||||
-#define RRBUFLEN 300 /* Most RRs are smaller than this. */
|
||||
+#define RRBUFLEN 128 /* Most RRs are smaller than this. */
|
||||
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
@@ -597,50 +597,66 @@ static int validate_rrset(time_t now, st
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
|
||||
hash->update(ctx, 4, p); /* class and type */
|
||||
hash->update(ctx, 4, (unsigned char *)&nsigttl);
|
||||
-
|
||||
- p += 8; /* skip class, type, ttl */
|
||||
+
|
||||
+ p += 8; /* skip type, class, ttl */
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS;
|
||||
-
|
||||
- /* canonicalise rdata and calculate length of same, use
|
||||
- name buffer as workspace for get_rdata. */
|
||||
- state.ip = p;
|
||||
- state.op = NULL;
|
||||
- state.desc = rr_desc;
|
||||
- state.buff = name;
|
||||
- state.end = p + rdlen;
|
||||
-
|
||||
- for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
- if (j < RRBUFLEN)
|
||||
- rrbuf[j] = *state.op;
|
||||
|
||||
- len = htons((u16)j);
|
||||
- hash->update(ctx, 2, (unsigned char *)&len);
|
||||
-
|
||||
- /* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
- then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
- go back to the start and do it in chunks. */
|
||||
- if (j >= RRBUFLEN)
|
||||
+ /* Optimisation for RR types which need no cannonicalisation.
|
||||
+ This includes DNSKEY DS NSEC and NSEC3, which are also long, so
|
||||
+ it saves lots of calls to get_rdata, and avoids the pessimal
|
||||
+ segmented insertion, even with a small rrbuf[].
|
||||
+
|
||||
+ If canonicalisation is not needed, a simple insertion into the hash works.
|
||||
+ */
|
||||
+ if (*rr_desc == (u16)-1)
|
||||
+ {
|
||||
+ len = htons(rdlen);
|
||||
+ hash->update(ctx, 2, (unsigned char *)&len);
|
||||
+ hash->update(ctx, rdlen, p);
|
||||
+ }
|
||||
+ else
|
||||
{
|
||||
+ /* canonicalise rdata and calculate length of same, use
|
||||
+ name buffer as workspace for get_rdata. */
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
-
|
||||
+ state.buff = name;
|
||||
+ state.end = p + rdlen;
|
||||
+
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
+ if (j < RRBUFLEN)
|
||||
+ rrbuf[j] = *state.op;
|
||||
+
|
||||
+ len = htons((u16)j);
|
||||
+ hash->update(ctx, 2, (unsigned char *)&len);
|
||||
+
|
||||
+ /* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
+ then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
+ go back to the start and do it in chunks. */
|
||||
+ if (j >= RRBUFLEN)
|
||||
{
|
||||
- rrbuf[j] = *state.op;
|
||||
-
|
||||
- if (j == RRBUFLEN - 1)
|
||||
- {
|
||||
- hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
- j = -1;
|
||||
- }
|
||||
+ state.ip = p;
|
||||
+ state.op = NULL;
|
||||
+ state.desc = rr_desc;
|
||||
+
|
||||
+ for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
+ {
|
||||
+ rrbuf[j] = *state.op;
|
||||
+
|
||||
+ if (j == RRBUFLEN - 1)
|
||||
+ {
|
||||
+ hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
+ j = -1;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ if (j != 0)
|
||||
+ hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
-
|
||||
- if (j != 0)
|
||||
- hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
@@ -0,0 +1,64 @@
|
||||
From 824461192ca5098043f9ca4ddeba7df1f65b30ba Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 15 Nov 2020 22:13:25 +0000
|
||||
Subject: Add missing check for NULL return from allocate_rfd().
|
||||
|
||||
---
|
||||
src/forward.c | 18 ++++++++++--------
|
||||
1 file changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -815,7 +815,6 @@ void reply_query(int fd, int family, tim
|
||||
int is_sign;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
- /* For DNSSEC originated queries, just retry the query to the same server. */
|
||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||
{
|
||||
struct server *start;
|
||||
@@ -841,6 +840,8 @@ void reply_query(int fd, int family, tim
|
||||
}
|
||||
|
||||
|
||||
+ fd = -1;
|
||||
+
|
||||
if (start->sfd)
|
||||
fd = start->sfd->fd;
|
||||
else
|
||||
@@ -848,19 +849,21 @@ void reply_query(int fd, int family, tim
|
||||
if (start->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
/* may have changed family */
|
||||
- if (!forward->rfd6)
|
||||
- forward->rfd6 = allocate_rfd(AF_INET6);
|
||||
- fd = forward->rfd6->fd;
|
||||
+ if (forward->rfd6 || (forward->rfd6 = allocate_rfd(AF_INET6)))
|
||||
+ fd = forward->rfd6->fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* may have changed family */
|
||||
- if (!forward->rfd4)
|
||||
- forward->rfd4 = allocate_rfd(AF_INET);
|
||||
- fd = forward->rfd4->fd;
|
||||
+ if (forward->rfd4 || (forward->rfd4 = allocate_rfd(AF_INET)))
|
||||
+ fd = forward->rfd4->fd;
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Can't get socket. */
|
||||
+ if (fd == -1)
|
||||
+ return;
|
||||
+
|
||||
while (retry_send(sendto(fd, (char *)header, plen, 0,
|
||||
&start->addr.sa,
|
||||
sa_len(&start->addr))));
|
||||
@@ -2261,7 +2264,6 @@ struct frec *get_new_frec(time_t now, in
|
||||
return f; /* OK if malloc fails and this is NULL */
|
||||
}
|
||||
|
||||
-/* crc is all-ones if not known. */
|
||||
static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
@@ -0,0 +1,352 @@
|
||||
From 15b60ddf935a531269bb8c68198de012a4967156 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 18 Nov 2020 18:34:55 +0000
|
||||
Subject: Handle multiple identical near simultaneous DNS queries better.
|
||||
|
||||
Previously, such queries would all be forwarded
|
||||
independently. This is, in theory, inefficent but in practise
|
||||
not a problem, _except_ that is means that an answer for any
|
||||
of the forwarded queries will be accepted and cached.
|
||||
An attacker can send a query multiple times, and for each repeat,
|
||||
another {port, ID} becomes capable of accepting the answer he is
|
||||
sending in the blind, to random IDs and ports. The chance of a
|
||||
succesful attack is therefore multiplied by the number of repeats
|
||||
of the query. The new behaviour detects repeated queries and
|
||||
merely stores the clients sending repeats so that when the
|
||||
first query completes, the answer can be sent to all the
|
||||
clients who asked. Refer: CERT VU#434904.
|
||||
---
|
||||
CHANGELOG | 16 +++++-
|
||||
src/dnsmasq.h | 19 ++++---
|
||||
src/forward.c | 142 ++++++++++++++++++++++++++++++++++++++++++--------
|
||||
3 files changed, 147 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -4,13 +4,27 @@
|
||||
|
||||
Be sure to only accept UDP DNS query replies at the address
|
||||
from which the query was originated. This keeps as much entropy
|
||||
- in the {query-ID, random-port} tuple as possible, help defeat
|
||||
+ in the {query-ID, random-port} tuple as possible, to help defeat
|
||||
cache poisoning attacks. Refer: CERT VU#434904.
|
||||
|
||||
Use the SHA-256 hash function to verify that DNS answers
|
||||
received are for the questions originally asked. This replaces
|
||||
the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
|
||||
+
|
||||
+ Handle multiple identical near simultaneous DNS queries better.
|
||||
+ Previously, such queries would all be forwarded
|
||||
+ independently. This is, in theory, inefficent but in practise
|
||||
+ not a problem, _except_ that is means that an answer for any
|
||||
+ of the forwarded queries will be accepted and cached.
|
||||
+ An attacker can send a query multiple times, and for each repeat,
|
||||
+ another {port, ID} becomes capable of accepting the answer he is
|
||||
+ sending in the blind, to random IDs and ports. The chance of a
|
||||
+ succesful attack is therefore multiplied by the number of repeats
|
||||
+ of the query. The new behaviour detects repeated queries and
|
||||
+ merely stores the clients sending repeats so that when the
|
||||
+ first query completes, the answer can be sent to all the
|
||||
+ clients who asked. Refer: CERT VU#434904.
|
||||
|
||||
|
||||
version 2.81
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -642,19 +642,24 @@ struct hostsfile {
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
-#define FREC_HAS_EXTRADATA 512
|
||||
+#define FREC_HAS_EXTRADATA 512
|
||||
+#define FREC_HAS_PHEADER 1024
|
||||
|
||||
#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
struct frec {
|
||||
- union mysockaddr source;
|
||||
- union all_addr dest;
|
||||
+ struct frec_src {
|
||||
+ union mysockaddr source;
|
||||
+ union all_addr dest;
|
||||
+ unsigned int iface, log_id;
|
||||
+ unsigned short orig_id;
|
||||
+ struct frec_src *next;
|
||||
+ } frec_src;
|
||||
struct server *sentto; /* NULL means free */
|
||||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
- unsigned int iface;
|
||||
- unsigned short orig_id, new_id;
|
||||
- int log_id, fd, forwardall, flags;
|
||||
+ unsigned short new_id;
|
||||
+ int fd, forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -1069,6 +1074,8 @@ extern struct daemon {
|
||||
int back_to_the_future;
|
||||
#endif
|
||||
struct frec *frec_list;
|
||||
+ struct frec_src *free_frec_src;
|
||||
+ int frec_src_count;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -20,6 +20,8 @@ static struct frec *lookup_frec(unsigned
|
||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
union mysockaddr *addr,
|
||||
void *hash);
|
||||
+static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
|
||||
+
|
||||
static unsigned short get_id(void);
|
||||
static void free_frec(struct frec *f);
|
||||
|
||||
@@ -247,6 +249,7 @@ static int forward_query(int udpfd, unio
|
||||
int type = SERV_DO_DNSSEC, norebind = 0;
|
||||
union all_addr *addrp = NULL;
|
||||
unsigned int flags = 0;
|
||||
+ unsigned int fwd_flags = 0;
|
||||
struct server *start = NULL;
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -255,7 +258,18 @@ static int forward_query(int udpfd, unio
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
(void)do_bit;
|
||||
-
|
||||
+
|
||||
+ if (header->hb4 & HB4_CD)
|
||||
+ fwd_flags |= FREC_CHECKING_DISABLED;
|
||||
+ if (ad_reqd)
|
||||
+ fwd_flags |= FREC_AD_QUESTION;
|
||||
+ if (oph)
|
||||
+ fwd_flags |= FREC_HAS_PHEADER;
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ if (do_bit)
|
||||
+ fwd_flags |= FREC_DO_QUESTION;
|
||||
+#endif
|
||||
+
|
||||
/* may be no servers available. */
|
||||
if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
||||
{
|
||||
@@ -328,6 +342,39 @@ static int forward_query(int udpfd, unio
|
||||
}
|
||||
else
|
||||
{
|
||||
+ /* Query from new source, but the same query may be in progress
|
||||
+ from another source. If so, just add this client to the
|
||||
+ list that will get the reply.
|
||||
+
|
||||
+ Note that is the EDNS client subnet option is in use, we can't do this,
|
||||
+ as the clients (and therefore query EDNS options) will be different
|
||||
+ for each query. The EDNS subnet code has checks to avoid
|
||||
+ attacks in this case. */
|
||||
+ if (!option_bool(OPT_CLIENT_SUBNET) && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
+ {
|
||||
+ /* Note whine_malloc() zeros memory. */
|
||||
+ if (!daemon->free_frec_src &&
|
||||
+ daemon->frec_src_count < daemon->ftabsize &&
|
||||
+ (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
+ daemon->frec_src_count++;
|
||||
+
|
||||
+ /* If we've been spammed with many duplicates, just drop the query. */
|
||||
+ if (daemon->free_frec_src)
|
||||
+ {
|
||||
+ struct frec_src *new = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = new->next;
|
||||
+ new->next = forward->frec_src.next;
|
||||
+ forward->frec_src.next = new;
|
||||
+ new->orig_id = ntohs(header->id);
|
||||
+ new->source = *udpaddr;
|
||||
+ new->dest = *dst_addr;
|
||||
+ new->log_id = daemon->log_id;
|
||||
+ new->iface = dst_iface;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
@@ -335,22 +382,22 @@ static int forward_query(int udpfd, unio
|
||||
do_dnssec = type & SERV_DO_DNSSEC;
|
||||
#endif
|
||||
type &= ~SERV_DO_DNSSEC;
|
||||
-
|
||||
+
|
||||
if (daemon->servers && !flags)
|
||||
forward = get_new_frec(now, NULL, 0);
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
|
||||
if (forward)
|
||||
{
|
||||
- forward->source = *udpaddr;
|
||||
- forward->dest = *dst_addr;
|
||||
- forward->iface = dst_iface;
|
||||
- forward->orig_id = ntohs(header->id);
|
||||
+ forward->frec_src.source = *udpaddr;
|
||||
+ forward->frec_src.orig_id = ntohs(header->id);
|
||||
+ forward->frec_src.dest = *dst_addr;
|
||||
+ forward->frec_src.iface = dst_iface;
|
||||
forward->new_id = get_id();
|
||||
forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
forward->forwardall = 0;
|
||||
- forward->flags = 0;
|
||||
+ forward->flags = fwd_flags;
|
||||
if (norebind)
|
||||
forward->flags |= FREC_NOREBIND;
|
||||
if (header->hb4 & HB4_CD)
|
||||
@@ -405,9 +452,9 @@ static int forward_query(int udpfd, unio
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
- forward->log_id = daemon->log_id;
|
||||
+ forward->frec_src.log_id = daemon->log_id;
|
||||
|
||||
- plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
+ plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet);
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
@@ -544,7 +591,7 @@ static int forward_query(int udpfd, unio
|
||||
return 1;
|
||||
|
||||
/* could not send on, prepare to return */
|
||||
- header->id = htons(forward->orig_id);
|
||||
+ header->id = htons(forward->frec_src.orig_id);
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
|
||||
@@ -796,8 +843,8 @@ void reply_query(int fd, int family, tim
|
||||
|
||||
/* log_query gets called indirectly all over the place, so
|
||||
pass these in global variables - sorry. */
|
||||
- daemon->log_display_id = forward->log_id;
|
||||
- daemon->log_source_addr = &forward->source;
|
||||
+ daemon->log_display_id = forward->frec_src.log_id;
|
||||
+ daemon->log_source_addr = &forward->frec_src.source;
|
||||
|
||||
if (daemon->ignore_addr && RCODE(header) == NOERROR &&
|
||||
check_for_ignored_address(header, n, daemon->ignore_addr))
|
||||
@@ -1065,6 +1112,7 @@ void reply_query(int fd, int family, tim
|
||||
new->sentto = server;
|
||||
new->rfd4 = NULL;
|
||||
new->rfd6 = NULL;
|
||||
+ new->frec_src.next = NULL;
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
|
||||
new->forwardall = 0;
|
||||
|
||||
@@ -1199,9 +1247,11 @@ void reply_query(int fd, int family, tim
|
||||
|
||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
- forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||
+ forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
|
||||
{
|
||||
- header->id = htons(forward->orig_id);
|
||||
+ struct frec_src *src;
|
||||
+
|
||||
+ header->id = htons(forward->frec_src.orig_id);
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
|
||||
@@ -1217,13 +1267,26 @@ void reply_query(int fd, int family, tim
|
||||
}
|
||||
#endif
|
||||
|
||||
+ for (src = &forward->frec_src; src; src = src->next)
|
||||
+ {
|
||||
+ header->id = htons(src->orig_id);
|
||||
+
|
||||
#ifdef HAVE_DUMPFILE
|
||||
- dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
|
||||
+ dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
|
||||
#endif
|
||||
-
|
||||
- send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
- &forward->source, &forward->dest, forward->iface);
|
||||
+
|
||||
+ send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
+ &src->source, &src->dest, src->iface);
|
||||
+
|
||||
+ if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
+ {
|
||||
+ daemon->log_display_id = src->log_id;
|
||||
+ daemon->log_source_addr = &src->source;
|
||||
+ log_query(F_UPSTREAM, "query", NULL, "duplicate");
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
}
|
||||
@@ -2153,6 +2216,17 @@ void free_rfd(struct randfd *rfd)
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
+ struct frec_src *src, *tmp;
|
||||
+
|
||||
+ /* add back to freelist of not the record builtin to every frec. */
|
||||
+ for (src = f->frec_src.next; src; src = tmp)
|
||||
+ {
|
||||
+ tmp = src->next;
|
||||
+ src->next = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = src;
|
||||
+ }
|
||||
+
|
||||
+ f->frec_src.next = NULL;
|
||||
free_rfd(f->rfd4);
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
@@ -2292,17 +2366,39 @@ static struct frec *lookup_frec_by_sende
|
||||
void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
+ struct frec_src *src;
|
||||
+
|
||||
+ for (f = daemon->frec_list; f; f = f->next)
|
||||
+ if (f->sentto &&
|
||||
+ !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
|
||||
+ memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
+ for (src = &f->frec_src; src; src = src->next)
|
||||
+ if (src->orig_id == id &&
|
||||
+ sockaddr_isequal(&src->source, addr))
|
||||
+ return f;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
|
||||
+{
|
||||
+ struct frec *f;
|
||||
+
|
||||
+ /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||
+ ensures that no frec created for internal DNSSEC query can be returned here. */
|
||||
+
|
||||
+#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
|
||||
+ | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY)
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
- f->orig_id == id &&
|
||||
- memcmp(hash, f->hash, HASH_SIZE) == 0 &&
|
||||
- sockaddr_isequal(&f->source, addr))
|
||||
+ (f->flags & FLAGMASK) == flags &&
|
||||
+ memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
return f;
|
||||
-
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
-
|
||||
+
|
||||
/* Send query packet again, if we can. */
|
||||
void resend_query()
|
||||
{
|
||||
@@ -0,0 +1,350 @@
|
||||
From 25e63f1e56f5acdcf91893a1b92ad1e0f2f552d8 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 25 Nov 2020 21:17:52 +0000
|
||||
Subject: Handle caching with EDNS options better.
|
||||
|
||||
If we add the EDNS client subnet option, or the client's
|
||||
MAC address, then the reply we get back may very depending on
|
||||
that. Since the cache is ignorant of such things, it's not safe to
|
||||
cache such replies. This patch determines when a dangerous EDNS
|
||||
option is being added and disables caching.
|
||||
|
||||
Note that for much the same reason, we can't combine multiple
|
||||
queries for the same question when dangerous EDNS options are
|
||||
being added, and the code now handles that in the same way. This
|
||||
query combining is required for security against cache poisoning,
|
||||
so disabling the cache has a security function as well as a
|
||||
correctness one.
|
||||
---
|
||||
man/dnsmasq.8 | 4 +--
|
||||
src/dnsmasq.h | 3 ++-
|
||||
src/edns0.c | 75 ++++++++++++++++++++++++++++++++-------------------
|
||||
src/forward.c | 41 ++++++++++++++++++----------
|
||||
4 files changed, 78 insertions(+), 45 deletions(-)
|
||||
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -690,8 +690,8 @@ still marks the request so that no upstr
|
||||
address information either. The default is zero for both IPv4 and
|
||||
IPv6. Note that upstream nameservers may be configured to return
|
||||
different results based on this information, but the dnsmasq cache
|
||||
-does not take account. If a dnsmasq instance is configured such that
|
||||
-different results may be encountered, caching should be disabled.
|
||||
+does not take account. Caching is therefore disabled for such replies,
|
||||
+unless the subnet address being added is constant.
|
||||
|
||||
For example,
|
||||
.B --add-subnet=24,96
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -644,6 +644,7 @@ struct hostsfile {
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
#define FREC_HAS_PHEADER 1024
|
||||
+#define FREC_NO_CACHE 2048
|
||||
|
||||
#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
@@ -1628,7 +1629,7 @@ size_t add_pseudoheader(struct dns_heade
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
- union mysockaddr *source, time_t now, int *check_subnet);
|
||||
+ union mysockaddr *source, time_t now, int *check_subnet, int *cacheable);
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
|
||||
/* arp.c */
|
||||
--- a/src/edns0.c
|
||||
+++ b/src/edns0.c
|
||||
@@ -264,7 +264,8 @@ static void encoder(unsigned char *in, c
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
-static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
+static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
+ union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
@@ -273,6 +274,7 @@ static size_t add_dns_client(struct dns_
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
replace = 1;
|
||||
+ *cacheablep = 0;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
@@ -288,14 +290,18 @@ static size_t add_dns_client(struct dns_
|
||||
}
|
||||
|
||||
|
||||
-static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
+static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
+ union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
- plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
-
|
||||
+ {
|
||||
+ *cacheablep = 0;
|
||||
+ plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
+ }
|
||||
+
|
||||
return plen;
|
||||
}
|
||||
|
||||
@@ -313,17 +319,18 @@ static void *get_addrp(union mysockaddr
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
-static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
+static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp = NULL;
|
||||
int sa_family = source->sa.sa_family;
|
||||
-
|
||||
+ int cacheable = 0;
|
||||
+
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
-
|
||||
+
|
||||
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet6->mask;
|
||||
@@ -331,6 +338,7 @@ static size_t calc_subnet_opt(struct sub
|
||||
{
|
||||
sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
+ cacheable = 1;
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
@@ -343,6 +351,7 @@ static size_t calc_subnet_opt(struct sub
|
||||
{
|
||||
sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
+ cacheable = 1; /* Address is constant */
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
@@ -350,8 +359,6 @@ static size_t calc_subnet_opt(struct sub
|
||||
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
|
||||
- len = 0;
|
||||
-
|
||||
if (addrp && opt->source_netmask != 0)
|
||||
{
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
@@ -359,18 +366,26 @@ static size_t calc_subnet_opt(struct sub
|
||||
if (opt->source_netmask & 7)
|
||||
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ cacheable = 1; /* No address ever supplied. */
|
||||
+ len = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (cacheablep)
|
||||
+ *cacheablep = cacheable;
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
-static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
|
||||
+static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
struct subnet_opt opt;
|
||||
|
||||
- len = calc_subnet_opt(&opt, source);
|
||||
+ len = calc_subnet_opt(&opt, source, cacheable);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
|
||||
}
|
||||
|
||||
@@ -383,18 +398,18 @@ int check_source(struct dns_header *head
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
- calc_len = calc_subnet_opt(&opt, peer);
|
||||
-
|
||||
- if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
- return 1;
|
||||
-
|
||||
- p += 8; /* skip UDP length and RCODE */
|
||||
+ calc_len = calc_subnet_opt(&opt, peer, NULL);
|
||||
|
||||
- GETSHORT(rdlen, p);
|
||||
- if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
- return 1; /* bad packet */
|
||||
-
|
||||
- /* check if option there */
|
||||
+ if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
+ return 1;
|
||||
+
|
||||
+ p += 8; /* skip UDP length and RCODE */
|
||||
+
|
||||
+ GETSHORT(rdlen, p);
|
||||
+ if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
+ return 1; /* bad packet */
|
||||
+
|
||||
+ /* check if option there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
@@ -412,24 +427,28 @@ int check_source(struct dns_header *head
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||
+ in the reply. Set *cacheable to zero if we add an option which the answer
|
||||
+ may depend on. */
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
- union mysockaddr *source, time_t now, int *check_subnet)
|
||||
+ union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)
|
||||
{
|
||||
*check_subnet = 0;
|
||||
-
|
||||
+ *cacheable = 1;
|
||||
+
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
- plen = add_mac(header, plen, limit, source, now);
|
||||
+ plen = add_mac(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
|
||||
- plen = add_dns_client(header, plen, limit, source, now);
|
||||
-
|
||||
+ plen = add_dns_client(header, plen, limit, source, now, cacheable);
|
||||
+
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
- plen = add_source_addr(header, plen, limit, source);
|
||||
+ plen = add_source_addr(header, plen, limit, source, cacheable);
|
||||
*check_subnet = 1;
|
||||
}
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -344,13 +344,10 @@ static int forward_query(int udpfd, unio
|
||||
{
|
||||
/* Query from new source, but the same query may be in progress
|
||||
from another source. If so, just add this client to the
|
||||
- list that will get the reply.
|
||||
+ list that will get the reply.*/
|
||||
|
||||
- Note that is the EDNS client subnet option is in use, we can't do this,
|
||||
- as the clients (and therefore query EDNS options) will be different
|
||||
- for each query. The EDNS subnet code has checks to avoid
|
||||
- attacks in this case. */
|
||||
- if (!option_bool(OPT_CLIENT_SUBNET) && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
+ if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
|
||||
+ (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
{
|
||||
/* Note whine_malloc() zeros memory. */
|
||||
if (!daemon->free_frec_src &&
|
||||
@@ -447,18 +444,21 @@ static int forward_query(int udpfd, unio
|
||||
if (!flags && forward)
|
||||
{
|
||||
struct server *firstsentto = start;
|
||||
- int subnet, forwarded = 0;
|
||||
+ int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
forward->frec_src.log_id = daemon->log_id;
|
||||
|
||||
- plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet);
|
||||
+ plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
-
|
||||
+
|
||||
+ if (!cacheable)
|
||||
+ forward->flags |= FREC_NO_CACHE;
|
||||
+
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
|
||||
{
|
||||
@@ -642,7 +642,7 @@ static size_t process_reply(struct dns_h
|
||||
}
|
||||
}
|
||||
#endif
|
||||
-
|
||||
+
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
{
|
||||
/* Get extended RCODE. */
|
||||
@@ -1244,6 +1244,11 @@ void reply_query(int fd, int family, tim
|
||||
header->hb4 |= HB4_CD;
|
||||
else
|
||||
header->hb4 &= ~HB4_CD;
|
||||
+
|
||||
+ /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||
+ since the cache is ignorant of such things. */
|
||||
+ if (forward->flags & FREC_NO_CACHE)
|
||||
+ no_cache_dnssec = 1;
|
||||
|
||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
@@ -1788,7 +1793,7 @@ unsigned char *tcp_request(int confd, ti
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
|
||||
- int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
+ int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
size_t m;
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
@@ -1959,7 +1964,7 @@ unsigned char *tcp_request(int confd, ti
|
||||
char *domain = NULL;
|
||||
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
|
||||
|
||||
- size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
+ size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
@@ -2122,6 +2127,11 @@ unsigned char *tcp_request(int confd, ti
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||
+ since the cache is ignorant of such things. */
|
||||
+ if (!cacheable)
|
||||
+ no_cache_dnssec = 1;
|
||||
+
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
@@ -2385,10 +2395,13 @@ static struct frec *lookup_frec_by_query
|
||||
struct frec *f;
|
||||
|
||||
/* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||
- ensures that no frec created for internal DNSSEC query can be returned here. */
|
||||
+ ensures that no frec created for internal DNSSEC query can be returned here.
|
||||
+
|
||||
+ 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. */
|
||||
|
||||
#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
|
||||
- | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY)
|
||||
+ | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
@@ -0,0 +1,181 @@
|
||||
From 2024f9729713fd657d65e64c2e4e471baa0a3e5b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
|
||||
Date: Wed, 25 Nov 2020 17:18:55 +0100
|
||||
Subject: Support hash function from nettle (only)
|
||||
|
||||
Unlike COPTS=-DHAVE_DNSSEC, allow usage of just sha256 function from
|
||||
nettle, but keep DNSSEC disabled at build time. Skips use of internal
|
||||
hash implementation without support for validation built-in.
|
||||
---
|
||||
Makefile | 8 +++++---
|
||||
bld/pkg-wrapper | 41 ++++++++++++++++++++++-------------------
|
||||
src/config.h | 8 ++++++++
|
||||
src/crypto.c | 7 +++++++
|
||||
src/dnsmasq.h | 2 +-
|
||||
src/hash_questions.c | 2 +-
|
||||
6 files changed, 44 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -53,7 +53,7 @@ top?=$(CURDIR)
|
||||
|
||||
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
-ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus`
|
||||
+ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
|
||||
@@ -62,8 +62,10 @@ ct_cflags = `echo $(COPTS) | $(top)/
|
||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
|
||||
-nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
|
||||
-nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
|
||||
+nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
|
||||
+ HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
|
||||
+nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \
|
||||
+ 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)`\"'
|
||||
--- a/bld/pkg-wrapper
|
||||
+++ b/bld/pkg-wrapper
|
||||
@@ -1,35 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
-search=$1
|
||||
-shift
|
||||
-pkg=$1
|
||||
-shift
|
||||
-op=$1
|
||||
-shift
|
||||
-
|
||||
in=`cat`
|
||||
|
||||
-if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep $search >/dev/null 2>&1; then
|
||||
+search()
|
||||
+{
|
||||
+ grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
|
||||
+ echo $in | grep $1 >/dev/null 2>&1
|
||||
+}
|
||||
+
|
||||
+while [ "$#" -gt 0 ]; do
|
||||
+ search=$1
|
||||
+ pkg=$2
|
||||
+ op=$3
|
||||
+ lib=$4
|
||||
+ shift 4
|
||||
+if search "$search"; then
|
||||
+
|
||||
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
if [ -z "$pkg" ]; then
|
||||
- pkg="$*"
|
||||
- elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
+ pkg="$lib"
|
||||
+ elif search "$pkg"; then
|
||||
pkg=""
|
||||
else
|
||||
- pkg="$*"
|
||||
+ pkg="$lib"
|
||||
fi
|
||||
- elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
- pkg=`$pkg --static $op $*`
|
||||
+ elif search "${search}_STATIC"; then
|
||||
+ pkg=`$pkg --static $op $lib`
|
||||
else
|
||||
- pkg=`$pkg $op $*`
|
||||
+ pkg=`$pkg $op $lib`
|
||||
fi
|
||||
|
||||
- if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
+ if search "${search}_STATIC"; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
@@ -40,3 +42,4 @@ if grep "^\#[[:space:]]*define[[:space:]
|
||||
fi
|
||||
fi
|
||||
|
||||
+done
|
||||
--- a/src/config.h
|
||||
+++ b/src/config.h
|
||||
@@ -117,6 +117,9 @@ HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
+HAVE_NETTLEHASH
|
||||
+ include just hash function from nettle, but no DNSSEC.
|
||||
+
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
@@ -184,6 +187,7 @@ RESOLVFILE
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
+/* #define HAVE_NETTLEHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
|
||||
@@ -408,6 +412,10 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"auth "
|
||||
+#if !defined(HAVE_NETTLEHASH) && !defined(HAVE_DNSSEC)
|
||||
+"no-"
|
||||
+#endif
|
||||
+"nettlehash "
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
--- a/src/crypto.c
|
||||
+++ b/src/crypto.c
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <nettle/ecdsa.h>
|
||||
#include <nettle/ecc-curve.h>
|
||||
#include <nettle/eddsa.h>
|
||||
+#endif
|
||||
+
|
||||
+#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
@@ -165,6 +168,10 @@ int hash_init(const struct nettle_hash *
|
||||
|
||||
return 1;
|
||||
}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+#ifdef HAVE_DNSSEC
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -150,7 +150,7 @@ extern int capget(cap_user_header_t head
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
+#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
--- a/src/hash_questions.c
|
||||
+++ b/src/hash_questions.c
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
+#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
@@ -0,0 +1,56 @@
|
||||
From 6a6e06fbb0d4690507ceaf2bb6f0d8910f3d4914 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 4 Dec 2020 18:35:11 +0000
|
||||
Subject: Small cleanups in frec_src datastucture handling.
|
||||
|
||||
---
|
||||
src/forward.c | 22 +++++++++++++---------
|
||||
1 file changed, 13 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -353,7 +353,10 @@ static int forward_query(int udpfd, unio
|
||||
if (!daemon->free_frec_src &&
|
||||
daemon->frec_src_count < daemon->ftabsize &&
|
||||
(daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
- daemon->frec_src_count++;
|
||||
+ {
|
||||
+ daemon->frec_src_count++;
|
||||
+ daemon->free_frec_src->next = NULL;
|
||||
+ }
|
||||
|
||||
/* If we've been spammed with many duplicates, just drop the query. */
|
||||
if (daemon->free_frec_src)
|
||||
@@ -390,6 +393,7 @@ static int forward_query(int udpfd, unio
|
||||
forward->frec_src.orig_id = ntohs(header->id);
|
||||
forward->frec_src.dest = *dst_addr;
|
||||
forward->frec_src.iface = dst_iface;
|
||||
+ forward->frec_src.next = NULL;
|
||||
forward->new_id = get_id();
|
||||
forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
@@ -2226,16 +2230,16 @@ void free_rfd(struct randfd *rfd)
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
- struct frec_src *src, *tmp;
|
||||
-
|
||||
- /* add back to freelist of not the record builtin to every frec. */
|
||||
- for (src = f->frec_src.next; src; src = tmp)
|
||||
+ struct frec_src *last;
|
||||
+
|
||||
+ /* add back to freelist if not the record builtin to every frec. */
|
||||
+ for (last = f->frec_src.next; last && last->next; last = last->next) ;
|
||||
+ if (last)
|
||||
{
|
||||
- tmp = src->next;
|
||||
- src->next = daemon->free_frec_src;
|
||||
- daemon->free_frec_src = src;
|
||||
+ last->next = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = f->frec_src.next;
|
||||
}
|
||||
-
|
||||
+
|
||||
f->frec_src.next = NULL;
|
||||
free_rfd(f->rfd4);
|
||||
f->rfd4 = NULL;
|
||||
@@ -0,0 +1,41 @@
|
||||
From e01e09c7125b40646aff4a582672e711a18a69a4 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 8 Jan 2021 22:50:03 +0000
|
||||
Subject: Add CVE numbers to security update descriptions in CHANGELOG
|
||||
|
||||
---
|
||||
CHANGELOG | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -1,16 +1,17 @@
|
||||
Fix a remote buffer overflow problem in the DNSSEC code. Any
|
||||
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
|
||||
- referenced by CERT VU#434904.
|
||||
+ referenced by CVE-2020-25681, CVE-2020-25682, CVE-2020-25683
|
||||
+ CVE-2020-25687.
|
||||
|
||||
Be sure to only accept UDP DNS query replies at the address
|
||||
from which the query was originated. This keeps as much entropy
|
||||
in the {query-ID, random-port} tuple as possible, to help defeat
|
||||
- cache poisoning attacks. Refer: CERT VU#434904.
|
||||
+ cache poisoning attacks. Refer: CVE-2020-25684.
|
||||
|
||||
Use the SHA-256 hash function to verify that DNS answers
|
||||
received are for the questions originally asked. This replaces
|
||||
the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
- the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
|
||||
+ the very insecure CRC32 (otherwise). Refer: CVE-2020-25685.
|
||||
|
||||
Handle multiple identical near simultaneous DNS queries better.
|
||||
Previously, such queries would all be forwarded
|
||||
@@ -24,7 +25,7 @@
|
||||
of the query. The new behaviour detects repeated queries and
|
||||
merely stores the clients sending repeats so that when the
|
||||
first query completes, the answer can be sent to all the
|
||||
- clients who asked. Refer: CERT VU#434904.
|
||||
+ clients who asked. Refer: CVE-2020-25686.
|
||||
|
||||
|
||||
version 2.81
|
||||
@@ -0,0 +1,20 @@
|
||||
From 503f68dbc437df20a45aab440e6fad92062af229 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 15 Jan 2021 21:53:29 +0000
|
||||
Subject: Fix warning message logic.
|
||||
|
||||
---
|
||||
src/hash_questions.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/src/hash_questions.c
|
||||
+++ b/src/hash_questions.c
|
||||
@@ -43,7 +43,7 @@ unsigned char *hash_questions(struct dns
|
||||
static unsigned char dummy[HASH_SIZE];
|
||||
static int warned = 0;
|
||||
|
||||
- if (warned)
|
||||
+ if (!warned)
|
||||
my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object"));
|
||||
warned = 1;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
From cc0b4489c782f6b90ca118abb18e716a7a831289 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 15 Jan 2021 22:21:52 +0000
|
||||
Subject: Update to new struct frec fields in conntrack code.
|
||||
|
||||
---
|
||||
src/forward.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -530,7 +530,7 @@ static int forward_query(int udpfd, unio
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
- if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
|
||||
+ if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -1178,7 +1178,7 @@ void reply_query(int fd, int family, tim
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
- if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
|
||||
+ if (get_incoming_mark(&orig->frec_src.source, &orig->frec_src.dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
From 04490bf622ac84891aad6f2dd2edf83725decdee Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 22 Jan 2021 16:49:12 +0000
|
||||
Subject: Move fd into frec_src, fixes 15b60ddf935a531269bb8c68198de012a4967156
|
||||
|
||||
If identical queries from IPv4 and IPv6 sources are combined by the
|
||||
new code added in 15b60ddf935a531269bb8c68198de012a4967156 then replies
|
||||
can end up being sent via the wrong family of socket. The ->fd
|
||||
should be per query, not per-question.
|
||||
|
||||
In bind-interfaces mode, this could also result in replies being sent
|
||||
via the wrong socket even when IPv4/IPV6 issues are not in play.
|
||||
---
|
||||
src/dnsmasq.h | 3 ++-
|
||||
src/forward.c | 4 ++--
|
||||
2 files changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -653,6 +653,7 @@ struct frec {
|
||||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
unsigned int iface, log_id;
|
||||
+ int fd;
|
||||
unsigned short orig_id;
|
||||
struct frec_src *next;
|
||||
} frec_src;
|
||||
@@ -660,7 +661,7 @@ struct frec {
|
||||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
unsigned short new_id;
|
||||
- int fd, forwardall, flags;
|
||||
+ int forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -394,8 +394,8 @@ static int forward_query(int udpfd, unio
|
||||
forward->frec_src.dest = *dst_addr;
|
||||
forward->frec_src.iface = dst_iface;
|
||||
forward->frec_src.next = NULL;
|
||||
+ forward->frec_src.fd = udpfd;
|
||||
forward->new_id = get_id();
|
||||
- forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
forward->forwardall = 0;
|
||||
forward->flags = fwd_flags;
|
||||
@@ -1284,7 +1284,7 @@ void reply_query(int fd, int family, tim
|
||||
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
|
||||
#endif
|
||||
|
||||
- send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
+ send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&src->source, &src->dest, src->iface);
|
||||
|
||||
if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
@@ -0,0 +1,19 @@
|
||||
From 12af2b171de0d678d98583e2190789e544440e02 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 22 Jan 2021 18:24:03 +0000
|
||||
Subject: Fix to 75e2f0aec33e58ef5b8d4d107d821c215a52827c
|
||||
|
||||
---
|
||||
src/forward.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -370,6 +370,7 @@ static int forward_query(int udpfd, unio
|
||||
new->dest = *dst_addr;
|
||||
new->log_id = daemon->log_id;
|
||||
new->iface = dst_iface;
|
||||
+ forward->frec_src.fd = udpfd;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -0,0 +1,20 @@
|
||||
From 3f535da79e7a42104543ef5c7b5fa2bed819a78b Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 22 Jan 2021 22:26:25 +0000
|
||||
Subject: Fix for 12af2b171de0d678d98583e2190789e544440e02
|
||||
|
||||
---
|
||||
src/forward.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -370,7 +370,7 @@ static int forward_query(int udpfd, unio
|
||||
new->dest = *dst_addr;
|
||||
new->log_id = daemon->log_id;
|
||||
new->iface = dst_iface;
|
||||
- forward->frec_src.fd = udpfd;
|
||||
+ new->fd = udpfd;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -0,0 +1,35 @@
|
||||
From 1f55b09dd88bc65b3ee6e3a665bc844a5a9a9e8d Mon Sep 17 00:00:00 2001
|
||||
From: Hans Dedecker <dedeckeh@gmail.com>
|
||||
Date: Fri, 9 Aug 2019 21:08:17 +0200
|
||||
Subject: [PATCH] crypto: use nettle ecc_curve access functions
|
||||
|
||||
Nettle 3.5.1 has made ecc_curve definitions (nettle_secp_192r1,
|
||||
nettle_secp_224r1, nettle_secp_256r1, ...) private and forces
|
||||
users to make use of the accessor functions (nettle_get_secp_192r1,
|
||||
...) to retrieve the specific ecc_curve structs.
|
||||
|
||||
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
|
||||
---
|
||||
src/crypto.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/src/crypto.c
|
||||
+++ b/src/crypto.c
|
||||
@@ -301,7 +301,7 @@ static int dnsmasq_ecdsa_verify(struct b
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
- nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
+ nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
@@ -314,7 +314,7 @@ static int dnsmasq_ecdsa_verify(struct b
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
- nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
+ nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
@@ -0,0 +1,64 @@
|
||||
--- a/src/ipset.c
|
||||
+++ b/src/ipset.c
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
-#include <sys/utsname.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netlink.h>
|
||||
@@ -72,7 +71,7 @@ struct my_nfgenmsg {
|
||||
|
||||
#define NL_ALIGN(len) (((len)+3) & ~(3))
|
||||
static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
|
||||
-static int ipset_sock, old_kernel;
|
||||
+static int ipset_sock;
|
||||
static char *buffer;
|
||||
|
||||
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
|
||||
@@ -87,25 +86,7 @@ static inline void add_attr(struct nlmsg
|
||||
|
||||
void ipset_init(void)
|
||||
{
|
||||
- struct utsname utsname;
|
||||
- int version;
|
||||
- char *split;
|
||||
-
|
||||
- if (uname(&utsname) < 0)
|
||||
- die(_("failed to find kernel version: %s"), NULL, EC_MISC);
|
||||
-
|
||||
- split = strtok(utsname.release, ".");
|
||||
- version = (split ? atoi(split) : 0);
|
||||
- split = strtok(NULL, ".");
|
||||
- version = version * 256 + (split ? atoi(split) : 0);
|
||||
- split = strtok(NULL, ".");
|
||||
- version = version * 256 + (split ? atoi(split) : 0);
|
||||
- old_kernel = (version < KERNEL_VERSION(2,6,32));
|
||||
-
|
||||
- if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
|
||||
- return;
|
||||
-
|
||||
- if (!old_kernel &&
|
||||
+ if (
|
||||
(buffer = safe_malloc(BUFF_SZ)) &&
|
||||
(ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
|
||||
(bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
|
||||
@@ -211,16 +192,9 @@ int add_to_ipset(const char *setname, co
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
af = AF_INET6;
|
||||
- /* old method only supports IPv4 */
|
||||
- if (old_kernel)
|
||||
- {
|
||||
- errno = EAFNOSUPPORT ;
|
||||
- ret = -1;
|
||||
- }
|
||||
}
|
||||
|
||||
- if (ret != -1)
|
||||
- ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
|
||||
+ ret = new_add_to_ipset(setname, ipaddr, af, remove);
|
||||
|
||||
if (ret == -1)
|
||||
my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno));
|
||||
@@ -0,0 +1,18 @@
|
||||
dnsmasq: fix warning with poll.h include on musl
|
||||
|
||||
Warning is:
|
||||
#warning redirecting incorrect #include <sys/poll.h> to <poll.h>
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
|
||||
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -95,7 +95,7 @@ typedef unsigned long long u64;
|
||||
#if defined(HAVE_SOLARIS_NETWORK)
|
||||
# include <sys/sockio.h>
|
||||
#endif
|
||||
-#include <sys/poll.h>
|
||||
+#include <poll.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
Reference in New Issue
Block a user