Merge branch 'unbound' into next

This commit is contained in:
Michael Tremer
2016-09-08 19:50:45 +01:00
50 changed files with 1801 additions and 1834 deletions

View File

@@ -1,145 +0,0 @@
#!/bin/sh
########################################################################
# Begin $rc_base/init.d/dnsmasq
#
# Description : dnsmasq init script
#
# Authors : Michael Tremer - mitch@ipfire.org
#
# Version : 01.00
#
# Notes :
#
########################################################################
. /etc/sysconfig/rc
. ${rc_functions}
CACHE_SIZE=2500
ENABLE_DNSSEC=1
SHOW_SRV=1
TRUST_ANCHOR=".,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5"
TIMESTAMP_FILE="/var/ipfire/dns/dnssec-timestamp"
# Pull custom configuration file
if [ -e "/etc/sysconfig/dnsmasq" ]; then
. /etc/sysconfig/dnsmasq
fi
function dnssec_args() {
local cmdline="--dnssec --dnssec-timestamp ${TIMESTAMP_FILE}"
if [ -n "${TRUST_ANCHOR}" ]; then
cmdline="${cmdline} --trust-anchor=${TRUST_ANCHOR}"
fi
echo "${cmdline}"
}
function dns_forward_args() {
local file="${1}"
# Do nothing if file is empty.
[ -s "${file}" ] || return
local cmdline
local enabled zone server remark
while IFS="," read -r enabled zone server remark; do
# Line must be enabled.
[ "${enabled}" = "on" ] || continue
cmdline="${cmdline} --server=/${zone}/${server}"
done < ${file}
echo "${cmdline}"
}
function dns_leases_args() {
eval $(/usr/local/bin/readhash /var/ipfire/dhcp/settings)
# If the DHCP server is enabled and DNS Update (RFC2136) is
# enabled, too, we won't overlay the internal domain with
# the dynamic/static leases.
if ([ "${ENABLE_GREEN}" = "on" ] || [ "${ENABLE_BLUE}" = "on" ]) \
&& [ "${DNS_UPDATE_ENABLED}" = "on" ]; then
return
fi
echo "-l /var/state/dhcp/dhcpd.leases"
}
case "${1}" in
start)
# kill already running copy of dnsmasq...
killproc /usr/sbin/dnsmasq 2>&1 > /dev/null
boot_mesg "Starting Domain Name Service Proxy..."
eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
ARGS="$CUSTOM_ARGS"
[ "$DOMAIN_NAME_GREEN" != "" ] && ARGS="$ARGS -s $DOMAIN_NAME_GREEN"
# DHCP configuration
ARGS="${ARGS} $(dns_leases_args)"
echo > /var/ipfire/red/resolv.conf # Clear it
if [ -e "/var/ipfire/red/dns1" ]; then
DNS1=$(cat /var/ipfire/red/dns1 2>/dev/null)
if [ ! -z ${DNS1} ]; then
echo "nameserver ${DNS1}" >> /var/ipfire/red/resolv.conf
fi
fi
if [ -e "/var/ipfire/red/dns2" ]; then
DNS2=$(cat /var/ipfire/red/dns2 2>/dev/null)
if [ ! -z ${DNS2} ]; then
echo "nameserver ${DNS2}" >> /var/ipfire/red/resolv.conf
fi
fi
[ -e "/var/ipfire/red/active" ] && ARGS="$ARGS -r /var/ipfire/red/resolv.conf"
ARGS="$ARGS --domain=`cat /var/ipfire/main/settings |grep DOMAIN |cut -d = -f 2`"
# Add custom forward dns zones.
ARGS="${ARGS} $(dns_forward_args /var/ipfire/dnsforward/config)"
# Enabled DNSSEC validation
if [ "${ENABLE_DNSSEC}" -eq 1 ]; then
ARGS="${ARGS} $(dnssec_args)"
fi
if [ -n "${CACHE_SIZE}" ]; then
ARGS="${ARGS} --cache-size=${CACHE_SIZE}"
fi
loadproc /usr/sbin/dnsmasq ${ARGS}
if [ "${SHOW_SRV}" -eq 1 ] && [ "${DNS1}" != "" -o "${DNS2}" != "" ]; then
boot_mesg "Using DNS server(s): ${DNS1} ${DNS2}"
boot_mesg_flush
fi
;;
stop)
boot_mesg "Stopping Domain Name Service Proxy..."
killproc /usr/sbin/dnsmasq
;;
restart)
${0} stop
sleep 1
${0} start
;;
status)
statusproc /usr/sbin/dnsmasq
;;
*)
echo "Usage: ${0} {start|stop|restart|status}"
exit 1
;;
esac
# End $rc_base/init.d/dnsmasq

View File

@@ -16,10 +16,6 @@
. ${rc_functions}
eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
init_networking() {
/etc/rc.d/init.d/dnsmasq start
}
DO="${1}"
shift
@@ -46,8 +42,6 @@ done
case "${DO}" in
start)
[ "${ALL}" == "1" ] && init_networking
# Starting interfaces...
# GREEN
[ "$green" == "1" ] && /etc/rc.d/init.d/networking/green start
@@ -92,9 +86,6 @@ case "${DO}" in
fi
fi
# Stopping dnsmasq if network all networks shutdown
[ "${ALL}" == "1" ] && /etc/rc.d/init.d/dnsmasq stop
exit 0
;;

View File

@@ -0,0 +1,4 @@
#!/bin/bash
# Update DNS forwarders for unbound
exec /etc/init.d/unbound update-forwarders

View File

@@ -0,0 +1,4 @@
#!/bin/bash
# Update DNS forwarders for unbound
exec /etc/init.d/unbound update-forwarders

View File

@@ -0,0 +1,226 @@
#!/bin/sh
# Begin $rc_base/init.d/unbound
# Description : Unbound DNS resolver boot script for IPfire
# Author : Marcel Lorenz <marcel.lorenz@ipfire.org>
#
# Comment : This init script additional starts the dhcpd watcher daemon
# if DNS-Update (RFC2136) in web interface enabled
. /etc/sysconfig/rc
. ${rc_functions}
USE_FORWARDERS=1
# Load optional configuration
[ -e "/etc/sysconfig/unbound" ] && . /etc/sysconfig/unbound
function cidr() {
local cidr nbits IFS;
IFS=. read -r i1 i2 i3 i4 <<< ${1}
IFS=. read -r m1 m2 m3 m4 <<< ${2}
cidr=$(printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))")
nbits=0
IFS=.
for dec in $2 ; do
case $dec in
255) let nbits+=8;;
254) let nbits+=7;;
252) let nbits+=6;;
248) let nbits+=5;;
240) let nbits+=4;;
224) let nbits+=3;;
192) let nbits+=2;;
128) let nbits+=1;;
0);;
*) echo "Error: $dec is not recognised"; exit 1
esac
done
echo "${cidr}/${nbits}"
}
read_name_servers() {
local i
for i in 1 2; do
echo "$(</var/ipfire/red/dns${i})"
done | xargs echo
}
config_header() {
echo "# This file is automatically generated and any changes"
echo "# will be overwritten. DO NOT EDIT!"
echo
}
update_forwarders() {
local forwarders="$(read_name_servers)"
if [ "${USE_FORWARDERS}" = "1" ] && [ -n "${forwarders}" ]; then
boot_mesg "Using Name Server(s): ${forwarders}"
boot_mesg_flush
unbound-control -q forward ${forwarders}
# If forwarders cannot be used we run in recursor mode
else
unbound-control -q forward off
fi
}
write_interfaces_conf() {
(
config_header
if [ -n "${GREEN_ADDRESS}" ]; then
echo "# GREEN"
echo "interface: ${GREEN_ADDRESS}"
echo "access-control: $(cidr ${GREEN_NETADDRESS} ${GREEN_NETMASK}) allow"
fi
if [ -n "${BLUE_ADDRESS}" ]; then
echo "# BLUE"
echo "interface: ${BLUE_ADDRESS}"
echo "access-control: $(cidr ${BLUE_NETADDRESS} ${BLUE_NETMASK}) allow"
fi
) > /etc/unbound/interfaces.conf
}
write_forward_conf() {
(
config_header
local enabled zone server remark
while IFS="," read -r enabled zone server remark; do
# Line must be enabled.
[ "${enabled}" = "on" ] || continue
echo "forward-zone:"
echo " name: ${zone}"
echo " forward-addr: ${server}"
echo
done < /var/ipfire/dnsforward/config
) > /etc/unbound/forward.conf
}
write_tuning_conf() {
# https://www.unbound.net/documentation/howto_optimise.html
# Determine number of online processors
local processors=$(getconf _NPROCESSORS_ONLN)
# Determine number of slabs
local slabs=1
while [ ${slabs} -lt ${processors} ]; do
slabs=$(( ${slabs} * 2 ))
done
# Determine amount of system memory
local mem=$(get_memory_amount)
# In the worst case scenario, unbound can use double the
# amount of memory allocated to a cache due to malloc overhead
# Large systems with more than 2GB of RAM
if [ ${mem} -ge 2048 ]; then
mem=128
# Small systems with less than 256MB of RAM
elif [ ${mem} -le 256 ]; then
mem=8
# Everything else
else
mem=32
fi
(
config_header
# We run one thread per processor
echo "num-threads: ${processors}"
# Adjust number of slabs
echo "infra-cache-slabs: ${slabs}"
echo "key-cache-slabs: ${slabs}"
echo "msg-cache-slabs: ${slabs}"
echo "rrset-cache-slabs: ${slabs}"
# Slice up the cache
echo "rrset-cache-size: $(( ${mem} / 2 ))m"
echo "msg-cache-size: $(( ${mem} / 4 ))m"
echo "key-cache-size: $(( ${mem} / 4 ))m"
) > /etc/unbound/tuning.conf
}
get_memory_amount() {
local key val unit
while read -r key val unit; do
case "${key}" in
MemTotal:*)
# Convert to MB
echo "$(( ${val} / 1024 ))"
break
;;
esac
done < /proc/meminfo
}
case "$1" in
start)
eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
eval $(/usr/local/bin/readhash /var/ipfire/dhcp/settings)
# Create control keys at first run
if [ ! -r "/etc/unbound/unbound_control.key" ]; then
unbound-control-setup -d /etc/unbound &>/dev/null
fi
# Update configuration files
write_tuning_conf
write_interfaces_conf
write_forward_conf
boot_mesg "Starting Unbound DNS Proxy..."
loadproc /usr/sbin/unbound || exit $?
# Update any known forwarding name servers
update_forwarders
# Start Unbound DHCP Lease Bridge unless RFC2136 is used
if [ "${DNS_UPDATE_ENABLED}" != on ]; then
boot_mesg "Starting Unbound DHCP Leases Bridge..."
loadproc /usr/sbin/unbound-dhcp-leases-bridge -d
fi
;;
stop)
boot_mesg "Stopping Unbound DHCP Leases Bridge..."
killproc /usr/sbin/unbound-dhcp-leases-bridge
boot_mesg "Stopping Unbound DNS Proxy..."
killproc /usr/sbin/unbound
;;
restart)
$0 stop
sleep 1
$0 start
;;
status)
statusproc /usr/sbin/unbound
statusproc /usr/sbin/unbound-dhcp-leases-bridge
;;
update-forwarders)
update_forwarders
;;
*)
echo "Usage: $0 {start|stop|restart|status|update-forwarders}"
exit 1
;;
esac
# End $rc_base/init.d/unbound

View File

@@ -31,7 +31,7 @@ SUID_PROGS = squidctrl sshctrl ipfirereboot \
redctrl syslogdctrl extrahdctrl sambactrl upnpctrl \
smartctrl clamavctrl addonctrl pakfire mpfirectrl wlanapctrl \
setaliases urlfilterctrl updxlratorctrl fireinfoctrl rebuildroutes \
getconntracktable wirelessclient dnsmasqctrl torctrl ddnsctrl
getconntracktable wirelessclient torctrl ddnsctrl unboundctrl
SUID_UPDX = updxsetperms
OBJS = $(patsubst %,%.o,$(PROGS) $(SUID_PROGS))

View File

@@ -19,14 +19,14 @@ int main(int argc, char *argv[]) {
exit(1);
if (argc < 2) {
fprintf(stderr, "\nNo argument given.\n\ndnsmasqctrl (restart)\n\n");
fprintf(stderr, "\nNo argument given.\n\nunboundctrl (restart)\n\n");
exit(1);
}
if (strcmp(argv[1], "restart") == 0) {
safe_system("/etc/rc.d/init.d/dnsmasq restart");
safe_system("/etc/rc.d/init.d/unbound restart");
} else {
fprintf(stderr, "\nBad argument given.\n\ndnsmasqctrl (restart)\n\n");
fprintf(stderr, "\nBad argument given.\n\nunboundctrl (restart)\n\n");
exit(1);
}

View File

@@ -1,363 +0,0 @@
--- a/src/cache.c Wed Dec 16 19:24:12 2015
+++ b/src/cache.c Wed Dec 16 19:37:37 2015
@@ -17,7 +17,7 @@
#include "dnsmasq.h"
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
-#ifdef HAVE_DHCP
+#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER)
static struct crec *dhcp_spare = NULL;
#endif
static struct crec *new_chain = NULL;
@@ -217,6 +217,9 @@
crecp->flags &= ~F_BIGNAME;
}
+ if (crecp->flags & F_DHCP)
+ free(crecp->name.namep);
+
#ifdef HAVE_DNSSEC
cache_blockdata_free(crecp);
#endif
@@ -1138,7 +1141,7 @@
}
-#ifdef HAVE_DHCP
+#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER)
struct in_addr a_record_from_hosts(char *name, time_t now)
{
struct crec *crecp = NULL;
@@ -1281,7 +1284,11 @@
else
crec->ttd = ttd;
crec->addr.addr = *host_address;
+#ifdef HAVE_ISC_READER
+ crec->name.namep = strdup(host_name);
+#else
crec->name.namep = host_name;
+#endif
crec->uid = next_uid();
cache_hash(crec);
--- a/src/dnsmasq.c Thu Jul 30 20:59:06 2015
+++ b/src/dnsmasq.c Wed Dec 16 19:38:32 2015
@@ -1017,6 +1017,11 @@
poll_resolv(0, daemon->last_resolv != 0, now);
daemon->last_resolv = now;
+
+#ifdef HAVE_ISC_READER
+ if (daemon->lease_file && !daemon->dhcp)
+ load_dhcp(now);
+#endif
}
#endif
--- a/src/dnsmasq.h Wed Dec 16 19:24:12 2015
+++ b/src/dnsmasq.h Wed Dec 16 19:40:11 2015
@@ -1516,6 +1516,11 @@
void poll_listen(int fd, short event);
int do_poll(int timeout);
+/* isc.c */
+#ifdef HAVE_ISC_READER
+void load_dhcp(time_t now);
+#endif
+
/* rrfilter.c */
size_t rrfilter(struct dns_header *header, size_t plen, int mode);
u16 *rrfilter_desc(int type);
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
-
--- /dev/null Wed Dec 16 19:48:08 2015
+++ b/src/isc.c Wed Dec 16 19:41:35 2015
@@ -0,0 +1,266 @@
+/* dnsmasq is Copyright (c) 2014 John Volpe, Simon Kelley and
+ Michael Tremer
+
+ 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/>.
+
+ Code in this file is based on contributions by John Volpe and
+ Simon Kelley. Updated for recent versions of dnsmasq by
+ Michael Tremer.
+*/
+
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_ISC_READER
+#define MAXTOK 50
+
+struct isc_dhcp_lease {
+ char* name;
+ char* fqdn;
+ time_t expires;
+ struct in_addr addr;
+ struct isc_dhcp_lease* next;
+};
+
+static struct isc_dhcp_lease* dhcp_lease_new(const char* hostname) {
+ struct isc_dhcp_lease* lease = whine_malloc(sizeof(*lease));
+ if (!lease)
+ return NULL;
+
+ lease->name = strdup(hostname);
+ if (daemon->domain_suffix) {
+ int r = asprintf(&lease->fqdn, "%s.%s", hostname, daemon->domain_suffix);
+
+ // Handle OOM
+ if (r < 0) {
+ free(lease);
+ return NULL;
+ }
+ }
+ lease->expires = 0;
+ lease->next = NULL;
+
+ return lease;
+}
+
+static void dhcp_lease_free(struct isc_dhcp_lease* lease) {
+ if (!lease)
+ return;
+
+ if (lease->name)
+ free(lease->name);
+ if (lease->fqdn)
+ free(lease->fqdn);
+ free(lease);
+}
+
+static int next_token(char* token, int buffsize, FILE* fp) {
+ int c, count = 0;
+ char* cp = token;
+
+ while ((c = getc(fp)) != EOF) {
+ if (c == '#') {
+ do {
+ c = getc(fp);
+ } while (c != '\n' && c != EOF);
+ }
+
+ if (c == ' ' || c == '\t' || c == '\n' || c == ';') {
+ if (count)
+ break;
+ } else if ((c != '"') && (count < buffsize - 1)) {
+ *cp++ = c;
+ count++;
+ }
+ }
+
+ *cp = 0;
+ return count ? 1 : 0;
+}
+
+static long get_utc_offset() {
+ time_t t = time(NULL);
+ struct tm* time_struct = localtime(&t);
+
+ return time_struct->tm_gmtoff;
+}
+
+static time_t parse_lease_time(const char* token_date, const char* token_time) {
+ time_t time = (time_t)(-1);
+ struct tm lease_time;
+
+ if (sscanf(token_date, "%d/%d/%d", &lease_time.tm_year, &lease_time.tm_mon, &lease_time.tm_mday) == 3) {
+ lease_time.tm_year -= 1900;
+ lease_time.tm_mon -= 1;
+
+ if (sscanf(token_time, "%d:%d:%d", &lease_time.tm_hour, &lease_time.tm_min, &lease_time.tm_sec) == 3) {
+ time = mktime(&lease_time) + get_utc_offset();
+ }
+ }
+
+ return time;
+}
+
+static struct isc_dhcp_lease* find_lease(const char* hostname, struct isc_dhcp_lease* leases) {
+ struct isc_dhcp_lease* lease = leases;
+
+ while (lease) {
+ if (strcmp(hostname, lease->name) == 0) {
+ return lease;
+ }
+ lease = lease->next;
+ }
+
+ return NULL;
+}
+
+static off_t lease_file_size = (off_t)0;
+static ino_t lease_file_inode = (ino_t)0;
+
+void load_dhcp(time_t now) {
+ struct isc_dhcp_lease* leases = NULL;
+
+ struct stat statbuf;
+ if (stat(daemon->lease_file, &statbuf) == -1) {
+ return;
+ }
+
+ /* Do nothing if the lease file has not changed. */
+ if ((statbuf.st_size <= lease_file_size) && (statbuf.st_ino == lease_file_inode))
+ return;
+
+ lease_file_size = statbuf.st_size;
+ lease_file_inode = statbuf.st_ino;
+
+ FILE* fp = fopen(daemon->lease_file, "r");
+ if (!fp) {
+ my_syslog(LOG_ERR, _("failed to load %s:%s"), daemon->lease_file, strerror(errno));
+ return;
+ }
+
+ my_syslog(LOG_INFO, _("reading %s"), daemon->lease_file);
+
+ char* hostname = daemon->namebuff;
+ struct in_addr host_address;
+ time_t time_starts = -1;
+ time_t time_ends = -1;
+ int nomem;
+
+ char token[MAXTOK];
+ while ((next_token(token, MAXTOK, fp))) {
+ if (strcmp(token, "lease") == 0) {
+ hostname[0] = '\0';
+
+ if (next_token(token, MAXTOK, fp) && ((host_address.s_addr = inet_addr(token)) != (in_addr_t)-1)) {
+ if (next_token(token, MAXTOK, fp) && *token == '{') {
+ while (next_token(token, MAXTOK, fp) && *token != '}') {
+ if ((strcmp(token, "client-hostname") == 0) || (strcmp(token, "hostname") == 0)) {
+ if (next_token(hostname, MAXDNAME, fp)) {
+ if (!canonicalise(hostname, &nomem)) {
+ *hostname = 0;
+ my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
+ }
+ }
+ } else if ((strcmp(token, "starts") == 0) || (strcmp(token, "ends") == 0)) {
+ char token_date[MAXTOK];
+ char token_time[MAXTOK];
+
+ int is_starts = strcmp(token, "starts") == 0;
+
+ // Throw away the weekday and parse the date.
+ if (next_token(token, MAXTOK, fp) && next_token(token_date, MAXTOK, fp) && next_token(token_time, MAXTOK, fp)) {
+ time_t time = parse_lease_time(token_date, token_time);
+
+ if (is_starts)
+ time_starts = time;
+ else
+ time_ends = time;
+ }
+ }
+ }
+
+ if (!*hostname)
+ continue;
+
+ if ((time_starts == -1) || (time_ends == -1))
+ continue;
+
+ if (difftime(now, time_ends) > 0)
+ continue;
+
+ char* dot = strchr(hostname, '.');
+ if (dot) {
+ if (!daemon->domain_suffix || hostname_isequal(dot + 1, daemon->domain_suffix)) {
+ my_syslog(LOG_WARNING,
+ _("Ignoring DHCP lease for %s because it has an illegal domain part"),
+ hostname);
+ continue;
+ }
+ *dot = 0;
+ }
+
+ // Search for an existing lease in the list
+ // with the given host name and update the data
+ // if needed.
+ struct isc_dhcp_lease* lease = find_lease(hostname, leases);
+
+ // If no lease already exists, we create a new one
+ // and append it to the list.
+ if (!lease) {
+ lease = dhcp_lease_new(hostname);
+ assert(lease);
+
+ lease->next = leases;
+ leases = lease;
+ }
+
+ // Only update more recent leases.
+ if (lease->expires > time_ends)
+ continue;
+
+ lease->addr = host_address;
+ lease->expires = time_ends;
+ }
+ }
+ }
+ }
+
+ fclose(fp);
+
+ // Drop all entries.
+ cache_unhash_dhcp();
+
+ while (leases) {
+ struct isc_dhcp_lease *lease = leases;
+ leases = lease->next;
+
+ if (lease->fqdn) {
+ cache_add_dhcp_entry(lease->fqdn, AF_INET, (struct all_addr*)&lease->addr.s_addr, lease->expires);
+ }
+
+ if (lease->name) {
+ cache_add_dhcp_entry(lease->name, AF_INET, (struct all_addr*)&lease->addr.s_addr, lease->expires);
+ }
+
+ // Cleanup
+ dhcp_lease_free(lease);
+ }
+}
+
+#endif
--- a/src/option.c Wed Dec 16 19:24:12 2015
+++ b/src/option.c Wed Dec 16 19:42:48 2015
@@ -1771,7 +1771,7 @@
ret_err(_("bad MX target"));
break;
-#ifdef HAVE_DHCP
+#if (defined HAVE_DHCP) || (defined HAVE_ISC_READER)
case 'l': /* --dhcp-leasefile */
daemon->lease_file = opt_string_alloc(arg);
break;
--- a/Makefile Wed Dec 16 19:24:12 2015
+++ b/Makefile Wed Dec 16 19:28:45 2015
@@ -74,7 +74,7 @@
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
+ poll.o rrfilter.o edns0.o arp.o isc.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h

View File

@@ -1,65 +0,0 @@
From 294d36df4749e01199ab220d44c170e7db2b0c05 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Wed, 6 Jul 2016 21:30:25 +0100
Subject: [PATCH] Calculate length of TFTP error reply correctly.
---
CHANGELOG | 14 ++++++++++++++
src/tftp.c | 7 +++++--
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 04ff3f0..0559a6f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,17 @@
+version 2.77
+ Calculate the length of TFTP error reply packet
+ correctly. This fixes a problem when the error
+ message in a TFTP packet exceeds the arbitrary
+ limit of 500 characters. The message was correctly
+ truncated, but not the packet length, so
+ extra data was appended. This is a possible
+ security risk, since the extra data comes from
+ a buffer which is also used for DNS, so that
+ previous DNS queries or replies may be leaked.
+ Thanks to Mozilla for funding the security audit
+ which spotted this bug.
+
+
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
translates to hosts on the local network, or, at
diff --git a/src/tftp.c b/src/tftp.c
index 5e4a32a..3e1b5c5 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -652,20 +652,23 @@ static void sanitise(char *buf)
}
+#define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */
static ssize_t tftp_err(int err, char *packet, char *message, char *file)
{
struct errmess {
unsigned short op, err;
char message[];
} *mess = (struct errmess *)packet;
- ssize_t ret = 4;
+ ssize_t len, ret = 4;
char *errstr = strerror(errno);
sanitise(file);
mess->op = htons(OP_ERR);
mess->err = htons(err);
- ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
+ len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
+ ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
+
my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
return ret;
--
1.7.10.4

View File

@@ -1,36 +0,0 @@
From d55f81f5fd53b1dfc2c4b3249b542f2d9679e236 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Wed, 6 Jul 2016 21:33:56 +0100
Subject: [PATCH] Zero newly malloc'ed memory.
---
src/util.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/util.c b/src/util.c
index 93b24f5..82443c9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -248,6 +248,8 @@ void *safe_malloc(size_t size)
if (!ret)
die(_("could not get memory"), NULL, EC_NOMEM);
+ else
+ memset(ret, 0, size);
return ret;
}
@@ -266,7 +268,9 @@ void *whine_malloc(size_t size)
if (!ret)
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
-
+ else
+ memset(ret, 0, size);
+
return ret;
}
--
1.7.10.4

View File

@@ -1,44 +0,0 @@
From ce7845bf5429bd2962c9b2e7d75e2659f3b5c1a8 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Wed, 6 Jul 2016 21:42:27 +0100
Subject: [PATCH] Check return of expand() always.
---
src/radv.c | 4 +++-
src/slaac.c | 5 ++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/radv.c b/src/radv.c
index 749b666..faa0f6d 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -262,7 +262,9 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
parm.prio = calc_prio(ra_param);
save_counter(0);
- ra = expand(sizeof(struct ra_packet));
+
+ if (!(ra = expand(sizeof(struct ra_packet))))
+ return;
ra->type = ND_ROUTER_ADVERT;
ra->code = 0;
diff --git a/src/slaac.c b/src/slaac.c
index 8034805..07b8ba4 100644
--- a/src/slaac.c
+++ b/src/slaac.c
@@ -147,7 +147,10 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
struct sockaddr_in6 addr;
save_counter(0);
- ping = expand(sizeof(struct ping_packet));
+
+ if (!(ping = expand(sizeof(struct ping_packet))))
+ continue;
+
ping->type = ICMP6_ECHO_REQUEST;
ping->code = 0;
ping->identifier = ping_id;
--
1.7.10.4

View File

@@ -1,40 +0,0 @@
From 5874f3e9222397d82aabd9884d9bf5ce7e4109b0 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Sun, 10 Jul 2016 22:12:08 +0100
Subject: [PATCH] Fix editing error on man page.
Thanks to Eric Westbrook for spotting this.
---
man/dnsmasq.8 | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 0521534..bd8c0b3 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1037,6 +1037,10 @@ is given, then read all the files contained in that directory. The advantage of
using this option is the same as for --dhcp-hostsfile: the
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a
+.B --dhcp-boot
+flag as DHCP options, using the options names bootfile-name,
+server-ip-address and tftp-server. This allows these to be included
+in a dhcp-optsfile.
.TP
.B --dhcp-hostsdir=<path>
This is equivalent to dhcp-hostsfile, except for the following. The path MUST be a
@@ -1048,11 +1052,6 @@ is restarted; ie host records are only added dynamically.
.TP
.B --dhcp-optsdir=<path>
This is equivalent to dhcp-optsfile, with the differences noted for --dhcp-hostsdir.
-.TP
-.B --dhcp-boot
-flag as DHCP options, using the options names bootfile-name,
-server-ip-address and tftp-server. This allows these to be included
-in a dhcp-optsfile.
.TP
.B \-Z, --read-ethers
Read /etc/ethers for information about hosts for the DHCP server. The
--
1.7.10.4

View File

@@ -1,25 +0,0 @@
From 907efeb2dc712603271093bce8a93c7c3e6fe64d Mon Sep 17 00:00:00 2001
From: Kristjan Onu <jeixav@gmail.com>
Date: Sun, 10 Jul 2016 22:37:57 +0100
Subject: [PATCH] Manpage typo.
---
man/dnsmasq.8 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index bd8c0b3..ac8d921 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -242,7 +242,7 @@ addresses associated with the interface.
.B --local-service
Accept DNS queries only from hosts whose address is on a local subnet,
ie a subnet for which an interface exists on the server. This option
-only has effect is there are no --interface --except-interface,
+only has effect if there are no --interface --except-interface,
--listen-address or --auth-server options. It is intended to be set as
a default on installation, to allow unconfigured installations to be
useful but also safe from being used for DNS amplification attacks.
--
1.7.10.4

View File

@@ -1,49 +0,0 @@
From 591ed1e90503817938ccf5f127e677a8dd48b6d8 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Mon, 11 Jul 2016 18:18:42 +0100
Subject: [PATCH] Fix bad behaviour with some DHCP option arrangements.
The check that there's enough space to store the DHCP agent-id
at the end of the packet could succeed when it should fail
if the END option is in either of the oprion-overload areas.
That could overwrite legit options in the request and cause
bad behaviour. It's highly unlikely that any sane DHCP client
would trigger this bug, and it's never been seen, but this
fixes the problem.
Also fix off-by-one in bounds checking of option processing.
Worst case scenario on that is a read one byte beyond the
end off a buffer with a crafted packet, and maybe therefore
a SIGV crash if the memory after the buffer is not mapped.
Thanks to Timothy Becker for spotting these.
---
src/rfc2131.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/rfc2131.c b/src/rfc2131.c
index b7c167e..8b99d4b 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -186,7 +186,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
be enough free space at the end of the packet to copy the option. */
unsigned char *sopt;
unsigned int total = option_len(opt) + 2;
- unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);
+ unsigned char *last_opt = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + sz,
+ OPTION_END, 0);
if (last_opt && last_opt < end - total)
{
end -= total;
@@ -1606,7 +1607,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
{
while (1)
{
- if (p > end)
+ if (p >= end)
return NULL;
else if (*p == OPTION_END)
return opt == OPTION_END ? p : NULL;
--
1.7.10.4

View File

@@ -1,55 +0,0 @@
From 1d07667ac77c55b9de56b1b2c385167e0e0ec27a Mon Sep 17 00:00:00 2001
From: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Date: Mon, 11 Jul 2016 18:36:05 +0100
Subject: [PATCH] Fix logic error in Linux netlink code.
This could cause dnsmasq to enter a tight loop on systems
with a very large number of network interfaces.
---
CHANGELOG | 6 ++++++
src/netlink.c | 8 +++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG b/CHANGELOG
index 0559a6f..59c9c49 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,12 @@ version 2.77
Thanks to Mozilla for funding the security audit
which spotted this bug.
+ Fix logic error in Linux netlink code. This could
+ cause dnsmasq to enter a tight loop on systems
+ with a very large number of network interfaces.
+ Thanks to Ivan Kokshaysky for the diagnosis and
+ patch.
+
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
diff --git a/src/netlink.c b/src/netlink.c
index 049247b..8cd51af 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -188,11 +188,17 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
- if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
+ if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{
/* May be multicast arriving async */
nl_async(h);
}
+ else if (h->nlmsg_seq != seq)
+ {
+ /* May be part of incomplete response to previous request after
+ ENOBUFS. Drop it. */
+ continue;
+ }
else if (h->nlmsg_type == NLMSG_DONE)
return callback_ok;
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
--
1.7.10.4

View File

@@ -1,93 +0,0 @@
From 06093a9a845bb597005d892d5d1bc7859933ada4 Mon Sep 17 00:00:00 2001
From: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
Date: Mon, 11 Jul 2016 21:03:27 +0100
Subject: [PATCH] Fix problem with --dnssec-timestamp whereby receipt of
SIGHUP would erroneously engage timestamp checking.
---
CHANGELOG | 4 ++++
src/dnsmasq.c | 7 ++++---
src/dnsmasq.h | 1 +
src/dnssec.c | 5 +++--
4 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 59c9c49..9f1e404 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -17,6 +17,10 @@ version 2.77
Thanks to Ivan Kokshaysky for the diagnosis and
patch.
+ Fix problem with --dnssec-timestamp whereby receipt
+ of SIGHUP would erroneously engage timestamp checking.
+ Thanks to Kevin Darbyshire-Bryant for this work.
+
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 045ec53..a47273f 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -750,7 +750,8 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
- if (option_bool(OPT_DNSSEC_TIME))
+ daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
+ if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future)
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
if (rc == 1)
@@ -1226,10 +1227,10 @@ static void async_event(int pipe, time_t now)
{
case EVENT_RELOAD:
#ifdef HAVE_DNSSEC
- if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
+ if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
{
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
- reset_option_bool(OPT_DNSSEC_TIME);
+ daemon->dnssec_no_time_check = 0;
}
#endif
/* fall through */
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 1896a64..be27ae0 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -992,6 +992,7 @@ extern struct daemon {
#endif
#ifdef HAVE_DNSSEC
struct ds_config *ds;
+ int dnssec_no_time_check;
int back_to_the_future;
char *timestamp_file;
#endif
diff --git a/src/dnssec.c b/src/dnssec.c
index 3c77c7d..64358fa 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -522,15 +522,16 @@ static int check_date_range(u32 date_start, u32 date_end)
if (utime(daemon->timestamp_file, NULL) != 0)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
+ my_syslog(LOG_INFO, _("system time considered valid, now checking DNSSEC signature timestamps."));
daemon->back_to_the_future = 1;
- set_option_bool(OPT_DNSSEC_TIME);
+ daemon->dnssec_no_time_check = 0;
queue_event(EVENT_RELOAD); /* purge cache */
}
if (daemon->back_to_the_future == 0)
return 1;
}
- else if (option_bool(OPT_DNSSEC_TIME))
+ else if (daemon->dnssec_no_time_check)
return 1;
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
--
1.7.10.4

View File

@@ -1,46 +0,0 @@
From d6dce53e08b3a06be16d43e1bf566c6c1988e4a9 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Mon, 11 Jul 2016 21:34:31 +0100
Subject: [PATCH] malloc(); memset() -> calloc() for efficiency.
---
src/util.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/util.c b/src/util.c
index 82443c9..211690e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -244,13 +244,11 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
/* for use during startup */
void *safe_malloc(size_t size)
{
- void *ret = malloc(size);
+ void *ret = calloc(1, size);
if (!ret)
die(_("could not get memory"), NULL, EC_NOMEM);
- else
- memset(ret, 0, size);
-
+
return ret;
}
@@ -264,12 +262,10 @@ void safe_pipe(int *fd, int read_noblock)
void *whine_malloc(size_t size)
{
- void *ret = malloc(size);
+ void *ret = calloc(1, size);
if (!ret)
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
- else
- memset(ret, 0, size);
return ret;
}
--
1.7.10.4

View File

@@ -1,169 +0,0 @@
From fa78573778cb23337f67f5d0c9de723169919047 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Fri, 22 Jul 2016 20:56:01 +0100
Subject: [PATCH] Zero packet buffers before building output, to reduce risk
of information leakage.
---
src/auth.c | 5 +++++
src/dnsmasq.h | 1 +
src/outpacket.c | 10 ++++++++++
src/radv.c | 2 +-
src/rfc1035.c | 5 +++++
src/rfc3315.c | 6 +++---
src/slaac.c | 2 +-
src/tftp.c | 5 ++++-
8 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/src/auth.c b/src/auth.c
index 198572d..3c5c37f 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -101,6 +101,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
struct all_addr addr;
struct cname *a;
+ /* Clear buffer beyond request to avoid risk of
+ information disclosure. */
+ memset(((char *)header) + qlen, 0,
+ (limit - ((char *)header)) - qlen);
+
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index be27ae0..2bda5d0 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1471,6 +1471,7 @@ void log_relay(int family, struct dhcp_relay *relay);
/* outpacket.c */
#ifdef HAVE_DHCP6
void end_opt6(int container);
+void reset_counter(void);
int save_counter(int newval);
void *expand(size_t headroom);
int new_opt6(int opt);
diff --git a/src/outpacket.c b/src/outpacket.c
index a414efa..2caacd9 100644
--- a/src/outpacket.c
+++ b/src/outpacket.c
@@ -29,9 +29,19 @@ void end_opt6(int container)
PUTSHORT(len, p);
}
+void reset_counter(void)
+{
+ /* Clear out buffer when starting from begining */
+ if (daemon->outpacket.iov_base)
+ memset(daemon->outpacket.iov_base, 0, daemon->outpacket.iov_len);
+
+ save_counter(0);
+}
+
int save_counter(int newval)
{
int ret = outpacket_counter;
+
if (newval != -1)
outpacket_counter = newval;
diff --git a/src/radv.c b/src/radv.c
index faa0f6d..39c9217 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -261,7 +261,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
parm.adv_interval = calc_interval(ra_param);
parm.prio = calc_prio(ra_param);
- save_counter(0);
+ reset_counter();
if (!(ra = expand(sizeof(struct ra_packet))))
return;
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 24d08c1..9e730a9 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1209,6 +1209,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
struct mx_srv_record *rec;
size_t len;
+
+ /* Clear buffer beyond request to avoid risk of
+ information disclosure. */
+ memset(((char *)header) + qlen, 0,
+ (limit - ((char *)header)) - qlen);
if (ntohs(header->ancount) != 0 ||
ntohs(header->nscount) != 0 ||
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 3f4d69c..e1271a1 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -89,7 +89,7 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
vendor->netid.next = &vendor->netid;
- save_counter(0);
+ reset_counter();
state.context = context;
state.interface = interface;
state.iface_name = iface_name;
@@ -2084,7 +2084,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
if (hopcount > 32)
return;
- save_counter(0);
+ reset_counter();
if ((header = put_opt6(NULL, 34)))
{
@@ -2161,7 +2161,7 @@ unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival
(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
break;
- save_counter(0);
+ reset_counter();
if (relay)
{
diff --git a/src/slaac.c b/src/slaac.c
index 07b8ba4..bd6c9b4 100644
--- a/src/slaac.c
+++ b/src/slaac.c
@@ -146,7 +146,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
struct ping_packet *ping;
struct sockaddr_in6 addr;
- save_counter(0);
+ reset_counter();
if (!(ping = expand(sizeof(struct ping_packet))))
continue;
diff --git a/src/tftp.c b/src/tftp.c
index 3e1b5c5..618c406 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -662,8 +662,9 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
ssize_t len, ret = 4;
char *errstr = strerror(errno);
+ memset(packet, 0, daemon->packet_buff_sz);
sanitise(file);
-
+
mess->op = htons(OP_ERR);
mess->err = htons(err);
len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
@@ -684,6 +685,8 @@ static ssize_t tftp_err_oops(char *packet, char *file)
/* return -1 for error, zero for done. */
static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
{
+ memset(packet, 0, daemon->packet_buff_sz);
+
if (transfer->block == 0)
{
/* send OACK */
--
1.7.10.4

View File

@@ -1,54 +0,0 @@
From 6b1c464d6de3d7d2afc9b53afe78cda6d6e3316f Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Fri, 22 Jul 2016 20:59:16 +0100
Subject: [PATCH] Don't reset packet length on transmission, in case of
retransmission.
---
src/radv.c | 2 +-
src/rfc3315.c | 2 +-
src/slaac.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/radv.c b/src/radv.c
index 39c9217..ffc37f2 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -528,7 +528,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
}
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
- save_counter(0), 0, (struct sockaddr *)&addr,
+ save_counter(-1), 0, (struct sockaddr *)&addr,
sizeof(addr))));
}
diff --git a/src/rfc3315.c b/src/rfc3315.c
index e1271a1..c7bf46f 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -2127,7 +2127,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
}
- send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(0), &to, &from, 0);
+ send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
diff --git a/src/slaac.c b/src/slaac.c
index bd6c9b4..7ecf127 100644
--- a/src/slaac.c
+++ b/src/slaac.c
@@ -164,7 +164,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = slaac->addr;
- if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
+ if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(-1), 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1 &&
errno == EHOSTUNREACH)
slaac->ping_time = 0; /* Give up */
--
1.7.10.4

View File

@@ -1,103 +0,0 @@
From bf4e62c19e619f7edf8d03d58d33a5752f190bfd Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Fri, 22 Jul 2016 21:37:59 +0100
Subject: [PATCH] Compile-time check on buffer sizes for leasefile parsing
code.
---
src/dhcp-common.c | 16 ++++++++--------
src/dhcp-protocol.h | 4 ++++
src/lease.c | 9 ++++++++-
src/rfc3315.c | 2 +-
4 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 08528e8..ecc752b 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -20,11 +20,11 @@
void dhcp_common_init(void)
{
- /* These each hold a DHCP option max size 255
- and get a terminating zero added */
- daemon->dhcp_buff = safe_malloc(256);
- daemon->dhcp_buff2 = safe_malloc(256);
- daemon->dhcp_buff3 = safe_malloc(256);
+ /* These each hold a DHCP option max size 255
+ and get a terminating zero added */
+ daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
+ daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ);
+ daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
/* dhcp_packet is used by v4 and v6, outpacket only by v6
sizeof(struct dhcp_packet) is as good an initial size as any,
@@ -855,14 +855,14 @@ void log_context(int family, struct dhcp_context *context)
if (context->flags & CONTEXT_RA_STATELESS)
{
if (context->flags & CONTEXT_TEMPLATE)
- strncpy(daemon->dhcp_buff, context->template_interface, 256);
+ strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
else
strcpy(daemon->dhcp_buff, daemon->addrbuff);
}
else
#endif
- inet_ntop(family, start, daemon->dhcp_buff, 256);
- inet_ntop(family, end, daemon->dhcp_buff3, 256);
+ inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
+ inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") :
diff --git a/src/dhcp-protocol.h b/src/dhcp-protocol.h
index a31d829..0ea449b 100644
--- a/src/dhcp-protocol.h
+++ b/src/dhcp-protocol.h
@@ -19,6 +19,10 @@
#define DHCP_CLIENT_ALTPORT 1068
#define PXE_PORT 4011
+/* These each hold a DHCP option max size 255
+ and get a terminating zero added */
+#define DHCP_BUFF_SZ 256
+
#define BOOTREQUEST 1
#define BOOTREPLY 2
#define DHCP_COOKIE 0x63825363
diff --git a/src/lease.c b/src/lease.c
index 20cac90..ca62cc5 100644
--- a/src/lease.c
+++ b/src/lease.c
@@ -65,7 +65,14 @@ void lease_init(time_t now)
}
/* client-id max length is 255 which is 255*2 digits + 254 colons
- borrow DNS packet buffer which is always larger than 1000 bytes */
+ borrow DNS packet buffer which is always larger than 1000 bytes
+
+ Check various buffers are big enough for the code below */
+
+#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764)
+# error Buffer size breakage in leasfile parsing.
+#endif
+
if (leasestream)
while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
{
diff --git a/src/rfc3315.c b/src/rfc3315.c
index c7bf46f..568b0c8 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -1975,7 +1975,7 @@ static void log6_packet(struct state *state, char *type, struct in6_addr *addr,
if (addr)
{
- inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255);
+ inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
strcat(daemon->dhcp_buff2, " ");
}
else
--
1.7.10.4

View File

@@ -1,184 +0,0 @@
From 094bfaeb4ff69cae99387bc2ea07ff57632c89f5 Mon Sep 17 00:00:00 2001
From: Mathias Kresin <dev@kresin.me>
Date: Sun, 24 Jul 2016 14:15:22 +0100
Subject: [PATCH] auth-zone: allow to exclude ip addresses from answer.
---
man/dnsmasq.8 | 6 +++++-
src/auth.c | 61 ++++++++++++++++++++++++++++++++++++---------------------
src/dnsmasq.h | 1 +
src/option.c | 21 ++++++++++++++++++--
4 files changed, 64 insertions(+), 25 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index ac8d921..8910947 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -739,7 +739,7 @@ a return code of SERVFAIL. Note that
setting this may affect DNS behaviour in bad ways, it is not an
extra-logging flag and should not be set in production.
.TP
-.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
+.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....][,exclude:<subnet>[/<prefix length>]].....]
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
will be served. If subnet(s) are given, A and AAAA records must be in one of the
specified subnets.
@@ -756,6 +756,10 @@ appear in the zone, but RFC1918 IPv4 addresses which should not.
Interface-name and address-literal subnet specifications may be used
freely in the same --auth-zone declaration.
+It's possible to exclude certain IP addresses from responses. It can be
+used, to make sure that answers contain only global routeable IP
+addresses (by excluding loopback, RFC1918 and ULA addresses).
+
The subnet(s) are also used to define in-addr.arpa and
ip6.arpa domains which are served for reverse-DNS queries. If not
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
diff --git a/src/auth.c b/src/auth.c
index 3c5c37f..f1ca2f5 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -18,36 +18,53 @@
#ifdef HAVE_AUTH
-static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
+static struct addrlist *find_addrlist(struct addrlist *list, int flag, struct all_addr *addr_u)
{
- struct addrlist *subnet;
-
- for (subnet = zone->subnet; subnet; subnet = subnet->next)
- {
- if (!(subnet->flags & ADDRLIST_IPV6))
- {
- struct in_addr netmask, addr = addr_u->addr.addr4;
-
- if (!(flag & F_IPV4))
- continue;
-
- netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
-
- if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
- return subnet;
- }
+ do {
+ if (!(list->flags & ADDRLIST_IPV6))
+ {
+ struct in_addr netmask, addr = addr_u->addr.addr4;
+
+ if (!(flag & F_IPV4))
+ continue;
+
+ netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
+
+ if (is_same_net(addr, list->addr.addr.addr4, netmask))
+ return list;
+ }
#ifdef HAVE_IPV6
- else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen))
- return subnet;
+ else if (is_same_net6(&(addr_u->addr.addr6), &list->addr.addr.addr6, list->prefixlen))
+ return list;
#endif
-
- }
+
+ } while ((list = list->next));
+
return NULL;
}
+static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
+{
+ if (!zone->subnet)
+ return NULL;
+
+ return find_addrlist(zone->subnet, flag, addr_u);
+}
+
+static struct addrlist *find_exclude(struct auth_zone *zone, int flag, struct all_addr *addr_u)
+{
+ if (!zone->exclude)
+ return NULL;
+
+ return find_addrlist(zone->exclude, flag, addr_u);
+}
+
static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
- /* No zones specified, no filter */
+ if (find_exclude(zone, flag, addr_u))
+ return 0;
+
+ /* No subnets specified, no filter */
if (!zone->subnet)
return 1;
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 2bda5d0..27385a9 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -340,6 +340,7 @@ struct auth_zone {
struct auth_name_list *next;
} *interface_names;
struct addrlist *subnet;
+ struct addrlist *exclude;
struct auth_zone *next;
};
diff --git a/src/option.c b/src/option.c
index d8c57d6..6cedef3 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1906,6 +1906,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new = opt_malloc(sizeof(struct auth_zone));
new->domain = opt_string_alloc(arg);
new->subnet = NULL;
+ new->exclude = NULL;
new->interface_names = NULL;
new->next = daemon->auth_zones;
daemon->auth_zones = new;
@@ -1913,6 +1914,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
while ((arg = comma))
{
int prefixlen = 0;
+ int is_exclude = 0;
char *prefix;
struct addrlist *subnet = NULL;
struct all_addr addr;
@@ -1923,6 +1925,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (prefix && !atoi_check(prefix, &prefixlen))
ret_err(gen_err);
+ if (strstr(arg, "exclude:") == arg)
+ {
+ is_exclude = 1;
+ arg = arg+8;
+ }
+
if (inet_pton(AF_INET, arg, &addr.addr.addr4))
{
subnet = opt_malloc(sizeof(struct addrlist));
@@ -1960,8 +1968,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (subnet)
{
subnet->addr = addr;
- subnet->next = new->subnet;
- new->subnet = subnet;
+
+ if (is_exclude)
+ {
+ subnet->next = new->exclude;
+ new->exclude = subnet;
+ }
+ else
+ {
+ subnet->next = new->subnet;
+ new->subnet = subnet;
+ }
}
}
break;
--
1.7.10.4

View File

@@ -1,41 +0,0 @@
From c8328ecde896575b3cb81cf537747df531f90771 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Fri, 5 Aug 2016 16:54:58 +0100
Subject: [PATCH] Bump auth zone serial when reloading /etc/hosts and friends.
---
CHANGELOG | 4 ++++
src/dnsmasq.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 9f1e404..4f89799 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,10 @@ version 2.77
Fix problem with --dnssec-timestamp whereby receipt
of SIGHUP would erroneously engage timestamp checking.
Thanks to Kevin Darbyshire-Bryant for this work.
+
+ Bump zone serial on reloading /etc/hosts and friends
+ when providing authoritative DNS. Thanks to Harrald
+ Dunkel for spotting this.
version 2.76
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index a47273f..3580bea 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1226,6 +1226,8 @@ static void async_event(int pipe, time_t now)
switch (ev.event)
{
case EVENT_RELOAD:
+ daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
+
#ifdef HAVE_DNSSEC
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
{
--
1.7.10.4

View File

@@ -1,101 +0,0 @@
From 6d95099c56a926d672e0407d6017fef9714f40c4 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Thu, 11 Aug 2016 23:38:54 +0100
Subject: [PATCH] Handle v4-mapped IPv6 addresses sanely for --synth-domain.
---
CHANGELOG | 7 ++++++-
man/dnsmasq.8 | 2 ++
src/domain.c | 34 ++++++++++++++++++++++++----------
3 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 4f89799..2731cc4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,7 +24,12 @@ version 2.77
Bump zone serial on reloading /etc/hosts and friends
when providing authoritative DNS. Thanks to Harrald
Dunkel for spotting this.
-
+
+ Handle v4-mapped IPv6 addresses sanely in --synth-domain.
+ These have standard representation like ::ffff:1.2.3.4
+ and are now converted to names like
+ <prefix>--ffff-1-2-3-4.<domain>
+
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 8910947..91fe672 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -619,6 +619,8 @@ but IPv6 addresses may start with '::'
but DNS labels may not start with '-' so in this case if no prefix is
configured a zero is added in front of the label. ::1 becomes 0--1.
+V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
+
The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask>
.TP
diff --git a/src/domain.c b/src/domain.c
index 1dd5027..a007acd 100644
--- a/src/domain.c
+++ b/src/domain.c
@@ -77,18 +77,31 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
*p = 0;
- /* swap . or : for - */
- for (p = tail; *p; p++)
- if (*p == '-')
- {
- if (prot == AF_INET)
+ #ifdef HAVE_IPV6
+ if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
+ {
+ /* special hack for v4-mapped. */
+ memcpy(tail, "::ffff:", 7);
+ for (p = tail + 7; *p; p++)
+ if (*p == '-')
*p = '.';
+ }
+ else
+#endif
+ {
+ /* swap . or : for - */
+ for (p = tail; *p; p++)
+ if (*p == '-')
+ {
+ if (prot == AF_INET)
+ *p = '.';
#ifdef HAVE_IPV6
- else
- *p = ':';
+ else
+ *p = ':';
#endif
- }
-
+ }
+ }
+
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
{
if (prot == AF_INET)
@@ -169,8 +182,9 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
}
+ /* V4-mapped have periods.... */
for (p = name; *p; p++)
- if (*p == ':')
+ if (*p == ':' || *p == '.')
*p = '-';
strncat(name, ".", MAXDNAME);
--
1.7.10.4

View File

@@ -1,149 +0,0 @@
From 396750cef533cf72c7e6a72e47a9c93e2e431cb7 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Sat, 13 Aug 2016 22:34:11 +0100
Subject: [PATCH] Refactor openBSD pftables code to remove blatant copyright
violation.
---
src/tables.c | 90 +++++++++++++++++++++-------------------------------------
1 file changed, 32 insertions(+), 58 deletions(-)
diff --git a/src/tables.c b/src/tables.c
index aae1252..4fa3487 100644
--- a/src/tables.c
+++ b/src/tables.c
@@ -53,52 +53,6 @@ static char *pfr_strerror(int errnum)
}
}
-static int pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
-{
- struct pfioc_table io;
-
- if (size < 0 || (size && tbl == NULL))
- {
- errno = EINVAL;
- return (-1);
- }
- bzero(&io, sizeof io);
- io.pfrio_flags = flags;
- io.pfrio_buffer = tbl;
- io.pfrio_esize = sizeof(*tbl);
- io.pfrio_size = size;
- if (ioctl(dev, DIOCRADDTABLES, &io))
- return (-1);
- if (nadd != NULL)
- *nadd = io.pfrio_nadd;
- return (0);
-}
-
-static int fill_addr(const struct all_addr *ipaddr, int flags, struct pfr_addr* addr) {
- if ( !addr || !ipaddr)
- {
- my_syslog(LOG_ERR, _("error: fill_addr missused"));
- return -1;
- }
- bzero(addr, sizeof(*addr));
-#ifdef HAVE_IPV6
- if (flags & F_IPV6)
- {
- addr->pfra_af = AF_INET6;
- addr->pfra_net = 0x80;
- memcpy(&(addr->pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr));
- }
- else
-#endif
- {
- addr->pfra_af = AF_INET;
- addr->pfra_net = 0x20;
- addr->pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr;
- }
- return 1;
-}
-
-/*****************************************************************************/
void ipset_init(void)
{
@@ -111,14 +65,13 @@ void ipset_init(void)
}
int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
- int flags, int remove)
+ int flags, int remove)
{
struct pfr_addr addr;
struct pfioc_table io;
struct pfr_table table;
- int n = 0, rc = 0;
- if ( dev == -1 )
+ if (dev == -1)
{
my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device);
return -1;
@@ -126,31 +79,52 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
bzero(&table, sizeof(struct pfr_table));
table.pfrt_flags |= PFR_TFLAG_PERSIST;
- if ( strlen(setname) >= PF_TABLE_NAME_SIZE )
+ if (strlen(setname) >= PF_TABLE_NAME_SIZE)
{
my_syslog(LOG_ERR, _("error: cannot use table name %s"), setname);
errno = ENAMETOOLONG;
return -1;
}
- if ( strlcpy(table.pfrt_name, setname,
- sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
+ if (strlcpy(table.pfrt_name, setname,
+ sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
{
my_syslog(LOG_ERR, _("error: cannot strlcpy table name %s"), setname);
return -1;
}
- if ((rc = pfr_add_tables(&table, 1, &n, 0)))
+ bzero(&io, sizeof io);
+ io.pfrio_flags = 0;
+ io.pfrio_buffer = &table;
+ io.pfrio_esize = sizeof(table);
+ io.pfrio_size = 1;
+ if (ioctl(dev, DIOCRADDTABLES, &io))
{
- my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"),
- pfr_strerror(errno),rc);
+ my_syslog(LOG_WARNING, _("IPset: error:%s"), pfr_strerror(errno));
+
return -1;
}
+
table.pfrt_flags &= ~PFR_TFLAG_PERSIST;
- if (n)
+ if (io.pfrio_nadd)
my_syslog(LOG_INFO, _("info: table created"));
-
- fill_addr(ipaddr,flags,&addr);
+
+ bzero(&addr, sizeof(addr));
+#ifdef HAVE_IPV6
+ if (flags & F_IPV6)
+ {
+ addr.pfra_af = AF_INET6;
+ addr.pfra_net = 0x80;
+ memcpy(&(addr.pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr));
+ }
+ else
+#endif
+ {
+ addr.pfra_af = AF_INET;
+ addr.pfra_net = 0x20;
+ addr.pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr;
+ }
+
bzero(&io, sizeof(io));
io.pfrio_flags = 0;
io.pfrio_table = table;
--
1.7.10.4