# limitations under the License.
PREFERRED_VERSION_ceph = "13.2.2"
+PREFERRED_VERSION_dnsmasq = "2.76"
PREFERRED_VERSION_keyutils = "1.6"
PREFERRED_VERSION_python-voluptuous = "0.8.9"
PREFERRED_VERSION_python3-cherrypy = "18.2.0"
audit-python \
"
RDEPENDS_dhclient-config += "dhcp-client"
-RDEPENDS_dnsmasq-config += ""
+RDEPENDS_dnsmasq-config += "dnsmasq"
RDEPENDS_docker-config += "docker-ce logrotate "
RDEPENDS_initscripts-config += "initscripts"
RDEPENDS_filesystem-scripts += ""
--- /dev/null
+d root root 0755 /run/dnsmasq none
--- /dev/null
+#!/bin/bash
+#
+# Borrowing heavily from the dnsmasq initscript's version of support for
+# resolvconf, intended for use in systemd-only configurations.
+#
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/dnsmasq
+NAME=dnsmasq
+
+# Most configuration options in /etc/default/dnsmasq are deprecated
+# but still honoured.
+if [ -r /etc/default/$NAME ]; then
+ . /etc/default/$NAME
+fi
+
+start_resolvconf()
+{
+ # If interface "lo" is explicitly disabled in /etc/default/dnsmasq
+ # Then dnsmasq won't be providing local DNS, so don't add it to
+ # the resolvconf server set.
+ for interface in $DNSMASQ_EXCEPT
+ do
+ [ $interface = lo ] && return
+ done
+
+ if [ -x /sbin/resolvconf ] ; then
+ echo "nameserver 127.0.0.1" |
+ /sbin/resolvconf -a lo.$NAME
+ fi
+ return 0
+}
+
+stop_resolvconf()
+{
+ if [ -x /sbin/resolvconf ] ; then
+ /sbin/resolvconf -d lo.$NAME
+ fi
+ return 0
+}
+
+case "$1" in
+ start)
+ start_resolvconf
+ exit 0
+ ;;
+ stop)
+ stop_resolvconf
+ exit 0
+ ;;
+ restart)
+ stop_resolvconf
+ start_resolvconf
+ exit 0
+ ;;
+ *)
+ echo "Usage: /etc/init.d/$NAME {start|stop|restart}" >&2
+ exit 3
+ ;;
+esac
+
+exit 0
+
--- /dev/null
+[Unit]
+Description=DNS forwarder and DHCP server
+After=network.target
+
+[Service]
+Type=forking
+PIDFile=/run/dnsmasq.pid
+ExecStartPre=/usr/bin/dnsmasq --test
+ExecStart=/usr/bin/dnsmasq -x /run/dnsmasq.pid -7 /etc/dnsmasq.d --local-service
+ExecStartPost=/usr/bin/dnsmasq-resolvconf-helper start
+ExecStopPre=/usr/bin/dnsmasq-resolvconf-helper stop
+ExecStop=/bin/kill $MAINPID
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
+
--- /dev/null
+#!/bin/sh
+#
+# Script to update the resolver list for dnsmasq
+#
+# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
+# If dnsmasq is installed then we go ahead and update the resolver list
+# in case dnsmasq is started later.
+#
+# Assumption: On entry, PWD contains the resolv.conf-type files.
+#
+# This file is part of the dnsmasq package.
+#
+
+set -e
+
+RUN_DIR="/run/dnsmasq"
+RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
+TMP_FILE="${RSLVRLIST_FILE}_new.$$"
+MY_NAME_FOR_RESOLVCONF="dnsmasq"
+
+[ -x /usr/bin/dnsmasq ] || exit 0
+[ -x /lib/resolvconf/list-records ] || exit 1
+
+PATH=/bin:/sbin
+
+report_err() { echo "$0: Error: $*" >&2 ; }
+
+# Stores arguments (minus duplicates) in RSLT, separated by spaces
+# Doesn't work properly if an argument itself contains whitespace
+uniquify()
+{
+ RSLT=""
+ while [ "$1" ] ; do
+ for E in $RSLT ; do
+ [ "$1" = "$E" ] && { shift ; continue 2 ; }
+ done
+ RSLT="${RSLT:+$RSLT }$1"
+ shift
+ done
+}
+
+if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
+ report_err "Failed trying to create directory $RUN_DIR"
+ exit 1
+fi
+
+RSLVCNFFILES=""
+for F in $(/lib/resolvconf/list-records --after "lo.$MY_NAME_FOR_RESOLVCONF") ; do
+ case "$F" in
+ "lo.$MY_NAME_FOR_RESOLVCONF")
+ # Omit own record
+ ;;
+ lo.*)
+ # Include no more records after one for a local nameserver
+ RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
+ break
+ ;;
+ *)
+ RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
+ ;;
+ esac
+done
+
+NMSRVRS=""
+if [ "$RSLVCNFFILES" ] ; then
+ uniquify $(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]\+//p' $RSLVCNFFILES)
+ NMSRVRS="$RSLT"
+fi
+
+# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
+# to detect changes in the file. This means that if a resolvconf update occurs
+# within one second of the previous one then dnsmasq may fail to notice the
+# more recent change. To work around this problem we sleep one second here
+# if necessary in order to ensure that the new mtime is different.
+if [ -f "$RSLVRLIST_FILE" ] && [ "$(stat -c %X "$RSLVRLIST_FILE")" = "$(date +%s)" ] ; then
+ sleep 1
+fi
+
+clean_up() { rm -f "$TMP_FILE" ; }
+trap clean_up EXIT
+: >| "$TMP_FILE"
+for N in $NMSRVRS ; do echo "nameserver $N" >> "$TMP_FILE" ; done
+mv -f "$TMP_FILE" "$RSLVRLIST_FILE"
+
--- /dev/null
+#!/bin/sh
+DAEMON=/usr/bin/dnsmasq
+NAME=dnsmasq
+DESC="DNS forwarder and DHCP server"
+ARGS="-7 /etc/dnsmasq.d"
+
+test -f $DAEMON || exit 0
+
+set -e
+
+if [ -r /etc/default/$NAME ]
+then
+ . /etc/default/$NAME
+fi
+
+DNSMASQ_CONF="/etc/dnsmasq.conf"
+test "/etc/dnsmasq.d/*" != '/etc/dnsmasq.d/*' && DNSMASQ_CONF="${DNSMASQ_CONF} /etc/dnsmasq.d/*"
+
+test -z "${PIDFILE}" && PIFILE="/run/dnsmasq.pid"
+
+if [ -z "$IGNORE_RESOLVCONF" ]
+then
+ egrep -h -q '^no-resolv' ${DNSMASQ_CONF} && IGNORE_RESOLVCONF="yes"
+fi
+
+# RESOLV_CONF:
+# If the resolvconf package is installed then use the resolv conf file
+# that it provides as the default. Otherwise use /etc/resolv.conf as
+# the default.
+#
+# If IGNORE_RESOLVCONF is set in /etc/default/dnsmasq or an explicit
+# filename is set there then this inhibits the use of the resolvconf-provided
+# information.
+#
+# Note that if the resolvconf package is installed it is not possible to
+# override it just by configuration in /etc/dnsmasq.conf, it is necessary
+# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
+
+test -z "$RESOLV_CONF" -a "$IGNORE_RESOLVCONF" != "yes" -a -x /sbin/resolvconf && \
+ RESOLV_CONF=/run/dnsmasq/resolv.conf
+
+start_resolvconf()
+{
+ if [ "$IGNORE_RESOLVCONF" != "yes" -a -x /sbin/resolvconf ]
+ then
+ echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
+ fi
+ :
+}
+
+stop_resolvconf()
+{
+ if [ "$IGNORE_RESOLVCONF" != "yes" -a -x /sbin/resolvconf ]
+ then
+ /sbin/resolvconf -d lo.$NAME
+ fi
+ :
+}
+
+case "$1" in
+ start)
+ echo -n "starting $DESC: $NAME... "
+ test -d /var/lib/misc/ || mkdir /var/lib/misc/
+ start-stop-daemon -S -x $DAEMON -- $ARGS \
+ ${RESOLV_CONF:+ -r $RESOLV_CONF} \
+ ${PIDFILE:+ -x $PIDFILE}
+ test $? -eq 0 && start_resolvconf
+ echo "done."
+ ;;
+ stop)
+ echo -n "stopping $DESC: $NAME... "
+ stop_resolvconf
+ start-stop-daemon -K -x $DAEMON
+ echo "done."
+ ;;
+ status)
+ echo -n "dnsmasq "
+ start-stop-daemon -q -K -t -x $DAEMON
+ RET=$?
+ if [ "$RET" = "0" ]; then
+ PID=`cat ${PIDFILE}`
+ echo "($PID) is running"
+ else
+ echo "is not running"
+ exit $RET
+ fi
+ ;;
+ restart)
+ echo "restarting $DESC: $NAME... "
+ $0 stop
+ $0 start
+ echo "done."
+ ;;
+ reload)
+ echo -n "reloading $DESC: $NAME... "
+ killall -HUP $(basename ${DAEMON})
+ echo "done."
+ ;;
+ systemd-start-resolvconf)
+ start_resolvconf
+ ;;
+ systemd-stop-resolvconf)
+ stop_resolvconf
+ ;;
+ systemd-exec)
+ test -d /var/lib/misc/ || mkdir /var/lib/misc/
+ exec $DAEMON --keep-in-foreground $ARGS \
+ ${RESOLV_CONF:+ -r $RESOLV_CONF} \
+ ${PIDFILE:+ -x $PIDFILE}
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|status|restart|reload}"
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+From 7a7ba871bc9280e76c13ffd87c7d9aaa72dad88d Mon Sep 17 00:00:00 2001
+From: Joe MacDonald <joe_macdonald@mentor.com>
+Date: Tue, 9 Sep 2014 10:24:58 -0400
+Subject: [PATCH] Upstream-status: Inappropriate [OE specific]
+
+Signed-off-by: Christopher Larson <chris_larson@mentor.com>
+
+---
+ Makefile | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index dd0513b..c49e84f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -57,8 +57,8 @@ idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) -
+ idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
+ ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
+ 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.1`
+-lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
++lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua`
++lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua`
+ 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`
+ gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
--- /dev/null
+From 858e259bf7125695c068301d0ef56cc4750d6544 Mon Sep 17 00:00:00 2001
+From: Don Penney <don.penney@windriver.com>
+Date: Thu, 15 Sep 2016 13:32:03 -0400
+Subject: [PATCH 1/1] Close tftp sockets immediately
+
+---
+ src/tftp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/tftp.c b/src/tftp.c
+index d7d050f..ecc6ce8 100644
+--- a/src/tftp.c
++++ b/src/tftp.c
+@@ -768,9 +768,11 @@ int do_tftp_script_run(void)
+ if ((transfer = daemon->tftp_done_trans))
+ {
+ daemon->tftp_done_trans = transfer->next;
++#if 0 /* Disable delayed closing of TFTP UDP socket */
+ #ifdef HAVE_SCRIPT
+ queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
+ #endif
++#endif
+ free_transfer(transfer);
+ return 1;
+ }
+--
+1.9.1
+
--- /dev/null
+From 62cb936cb7ad5f219715515ae7d32dd281a5aa1f Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Tue, 26 Sep 2017 22:00:11 +0100
+Subject: Security fix, CVE-2017-14491, DNS heap buffer overflow.
+
+Further fix to 0549c73b7ea6b22a3c49beb4d432f185a81efcbc
+Handles case when RR name is not a pointer to the question,
+only occurs for some auth-mode replies, therefore not
+detected by fuzzing (?)
+---
+ src/rfc1035.c | 27 +++++++++++++++------------
+ 1 file changed, 15 insertions(+), 12 deletions(-)
+
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 27af023..56ab88b 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1086,32 +1086,35 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+
+ va_start(ap, format); /* make ap point to 1st unamed argument */
+
+- /* nameoffset (1 or 2) + type (2) + class (2) + ttl (4) + 0 (2) */
+- CHECK_LIMIT(12);
+-
+ if (nameoffset > 0)
+ {
++ CHECK_LIMIT(2);
+ PUTSHORT(nameoffset | 0xc000, p);
+ }
+ else
+ {
+ char *name = va_arg(ap, char *);
+- if (name)
+- p = do_rfc1035_name(p, name, limit);
+- if (!p)
+- {
+- va_end(ap);
+- goto truncated;
+- }
+-
++ if (name && !(p = do_rfc1035_name(p, name, limit)))
++ {
++ va_end(ap);
++ goto truncated;
++ }
++
+ if (nameoffset < 0)
+ {
++ CHECK_LIMIT(2);
+ PUTSHORT(-nameoffset | 0xc000, p);
+ }
+ else
+- *p++ = 0;
++ {
++ CHECK_LIMIT(1);
++ *p++ = 0;
++ }
+ }
+
++ /* type (2) + class (2) + ttl (4) + rdlen (2) */
++ CHECK_LIMIT(10);
++
+ PUTSHORT(type, p);
+ PUTSHORT(class, p);
+ PUTLONG(ttl, p); /* TTL */
+--
+2.7.4
+
--- /dev/null
+From 8868a04895b27d42d42e364f1a0c0196c1505b04 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 18:17:11 +0100
+Subject: [PATCH 1/9] Security fix, CVE-2017-14491 DNS heap buffer
+ overflow.
+
+ Fix heap overflow in DNS code. This is a potentially serious
+ security hole. It allows an attacker who can make DNS
+ requests to dnsmasq, and who controls the contents of
+ a domain, which is thereby queried, to overflow
+ (by 2 bytes) a heap buffer and either crash, or
+ even take control of, dnsmasq.
+---
+ src/dnsmasq.h | 2 +-
+ src/dnssec.c | 2 +-
+ src/option.c | 2 +-
+ src/rfc1035.c | 50 +++++++++++++++++++++++++++++++++++++++++---------
+ src/rfc2131.c | 4 ++--
+ src/rfc3315.c | 4 ++--
+ src/util.c | 7 ++++++-
+ 7 files changed, 54 insertions(+), 17 deletions(-)
+
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 1179492..06e5579 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -1162,7 +1162,7 @@ u32 rand32(void);
+ u64 rand64(void);
+ int legal_hostname(char *c);
+ char *canonicalise(char *s, int *nomem);
+-unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
++unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
+ void *safe_malloc(size_t size);
+ void safe_pipe(int *fd, int read_noblock);
+ void *whine_malloc(size_t size);
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 3c77c7d..f45c804 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -2227,7 +2227,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
+
+ p = (unsigned char *)(header+1);
+
+- p = do_rfc1035_name(p, name);
++ p = do_rfc1035_name(p, name, NULL);
+ *p++ = 0;
+ PUTSHORT(type, p);
+ PUTSHORT(class, p);
+diff --git a/src/option.c b/src/option.c
+index eb78b1a..3469f53 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -1378,7 +1378,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
+ }
+
+ p = newp;
+- end = do_rfc1035_name(p + len, dom);
++ end = do_rfc1035_name(p + len, dom, NULL);
+ *end++ = 0;
+ len = end - p;
+ free(dom);
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 24d08c1..78410d6 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1049,6 +1049,7 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog
+ return 0;
+ }
+
++
+ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
+ unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
+ {
+@@ -1058,12 +1059,21 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ unsigned short usval;
+ long lval;
+ char *sval;
++#define CHECK_LIMIT(size) \
++ if (limit && p + (size) > (unsigned char*)limit) \
++ { \
++ va_end(ap); \
++ goto truncated; \
++ }
+
+ if (truncp && *truncp)
+ return 0;
+-
++
+ va_start(ap, format); /* make ap point to 1st unamed argument */
+-
++
++ /* nameoffset (1 or 2) + type (2) + class (2) + ttl (4) + 0 (2) */
++ CHECK_LIMIT(12);
++
+ if (nameoffset > 0)
+ {
+ PUTSHORT(nameoffset | 0xc000, p);
+@@ -1072,7 +1082,13 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ {
+ char *name = va_arg(ap, char *);
+ if (name)
+- p = do_rfc1035_name(p, name);
++ p = do_rfc1035_name(p, name, limit);
++ if (!p)
++ {
++ va_end(ap);
++ goto truncated;
++ }
++
+ if (nameoffset < 0)
+ {
+ PUTSHORT(-nameoffset | 0xc000, p);
+@@ -1093,6 +1109,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ {
+ #ifdef HAVE_IPV6
+ case '6':
++ CHECK_LIMIT(IN6ADDRSZ);
+ sval = va_arg(ap, char *);
+ memcpy(p, sval, IN6ADDRSZ);
+ p += IN6ADDRSZ;
+@@ -1100,36 +1117,47 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ #endif
+
+ case '4':
++ CHECK_LIMIT(INADDRSZ);
+ sval = va_arg(ap, char *);
+ memcpy(p, sval, INADDRSZ);
+ p += INADDRSZ;
+ break;
+
+ case 'b':
++ CHECK_LIMIT(1);
+ usval = va_arg(ap, int);
+ *p++ = usval;
+ break;
+
+ case 's':
++ CHECK_LIMIT(2);
+ usval = va_arg(ap, int);
+ PUTSHORT(usval, p);
+ break;
+
+ case 'l':
++ CHECK_LIMIT(4);
+ lval = va_arg(ap, long);
+ PUTLONG(lval, p);
+ break;
+
+ case 'd':
+- /* get domain-name answer arg and store it in RDATA field */
+- if (offset)
+- *offset = p - (unsigned char *)header;
+- p = do_rfc1035_name(p, va_arg(ap, char *));
+- *p++ = 0;
++ /* get domain-name answer arg and store it in RDATA field */
++ if (offset)
++ *offset = p - (unsigned char *)header;
++ p = do_rfc1035_name(p, va_arg(ap, char *), limit);
++ if (!p)
++ {
++ va_end(ap);
++ goto truncated;
++ }
++ CHECK_LIMIT(1);
++ *p++ = 0;
+ break;
+
+ case 't':
+ usval = va_arg(ap, int);
++ CHECK_LIMIT(usval);
+ sval = va_arg(ap, char *);
+ if (usval != 0)
+ memcpy(p, sval, usval);
+@@ -1141,20 +1169,24 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ usval = sval ? strlen(sval) : 0;
+ if (usval > 255)
+ usval = 255;
++ CHECK_LIMIT(usval + 1);
+ *p++ = (unsigned char)usval;
+ memcpy(p, sval, usval);
+ p += usval;
+ break;
+ }
+
++#undef CHECK_LIMIT
+ va_end(ap); /* clean up variable argument pointer */
+
+ j = p - sav - 2;
+- PUTSHORT(j, sav); /* Now, store real RDLength */
++ /* this has already been checked against limit before */
++ PUTSHORT(j, sav); /* Now, store real RDLength */
+
+ /* check for overflow of buffer */
+ if (limit && ((unsigned char *)limit - p) < 0)
+ {
++truncated:
+ if (truncp)
+ *truncp = 1;
+ return 0;
+diff --git a/src/rfc2131.c b/src/rfc2131.c
+index 8b99d4b..75893a6 100644
+--- a/src/rfc2131.c
++++ b/src/rfc2131.c
+@@ -2420,10 +2420,10 @@ static void do_options(struct dhcp_context *context,
+
+ if (fqdn_flags & 0x04)
+ {
+- p = do_rfc1035_name(p, hostname);
++ p = do_rfc1035_name(p, hostname, NULL);
+ if (domain)
+ {
+- p = do_rfc1035_name(p, domain);
++ p = do_rfc1035_name(p, domain, NULL);
+ *p++ = 0;
+ }
+ }
+diff --git a/src/rfc3315.c b/src/rfc3315.c
+index 3f4d69c..73bdee4 100644
+--- a/src/rfc3315.c
++++ b/src/rfc3315.c
+@@ -1472,10 +1472,10 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
+ if ((p = expand(len + 2)))
+ {
+ *(p++) = state->fqdn_flags;
+- p = do_rfc1035_name(p, state->hostname);
++ p = do_rfc1035_name(p, state->hostname, NULL);
+ if (state->send_domain)
+ {
+- p = do_rfc1035_name(p, state->send_domain);
++ p = do_rfc1035_name(p, state->send_domain, NULL);
+ *p = 0;
+ }
+ }
+diff --git a/src/util.c b/src/util.c
+index 1a9f228..be9f8a6 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -218,15 +218,20 @@ char *canonicalise(char *in, int *nomem)
+ return ret;
+ }
+
+-unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
++unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
+ {
+ int j;
+
+ while (sval && *sval)
+ {
++ if (limit && p + 1 > (unsigned char*)limit)
++ return p;
++
+ unsigned char *cp = p++;
+ for (j = 0; *sval && (*sval != '.'); sval++, j++)
+ {
++ if (limit && p + 1 > (unsigned char*)limit)
++ return p;
+ #ifdef HAVE_DNSSEC
+ if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
+ *p++ = (*(++sval))-1;
+--
+2.9.5
+
--- /dev/null
+From c14b8b511ac55f6933aebefbd6cc27c1ec74ad58 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 18:47:15 +0100
+Subject: [PATCH 2/9] Security fix, CVE-2017-14492, DHCPv6 RA heap
+ overflow.
+
+ Fix heap overflow in IPv6 router advertisement code.
+ This is a potentially serious security hole, as a
+ crafted RA request can overflow a buffer and crash or
+ control dnsmasq. Attacker must be on the local network.
+---
+ src/radv.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/radv.c b/src/radv.c
+index 749b666..d09fe0e 100644
+--- a/src/radv.c
++++ b/src/radv.c
+@@ -198,6 +198,9 @@ void icmp6_packet(time_t now)
+ /* look for link-layer address option for logging */
+ if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
+ {
++ if ((packet[9] * 8 - 2) * 3 - 1 >= MAXDNAME) {
++ return;
++ }
+ print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
+ mac = daemon->namebuff;
+ }
+--
+2.9.5
+
--- /dev/null
+From 5086b12a4b1269d1576b5bab01f72c6fa19c55bc Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 18:52:50 +0100
+Subject: [PATCH 3/9] Security fix, CVE-2017-14493, DHCPv6 - Stack buffer
+ overflow.
+
+ Fix stack overflow in DHCPv6 code. An attacker who can send
+ a DHCPv6 request to dnsmasq can overflow the stack frame and
+ crash or control dnsmasq.
+---
+ src/rfc3315.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/rfc3315.c b/src/rfc3315.c
+index 73bdee4..8d18a28 100644
+--- a/src/rfc3315.c
++++ b/src/rfc3315.c
+@@ -206,6 +206,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
+ /* RFC-6939 */
+ if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
+ {
++ if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
++ return 0;
++ }
+ state->mac_type = opt6_uint(opt, 0, 2);
+ state->mac_len = opt6_len(opt) - 2;
+ memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
+--
+2.9.5
+
--- /dev/null
+From 8c8fe650dc17aad0fbafc920fde719218dc4568d Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 20:05:11 +0100
+Subject: [PATCH 4/9] Security fix, CVE-2017-14494, Infoleak handling
+ DHCPv6 forwarded requests.
+
+ Fix information leak in DHCPv6. A crafted DHCPv6 packet can
+ cause dnsmasq to forward memory from outside the packet
+ buffer to a DHCPv6 server when acting as a relay.
+---
+ src/rfc3315.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/rfc3315.c b/src/rfc3315.c
+index 8d18a28..03b3f84 100644
+--- a/src/rfc3315.c
++++ b/src/rfc3315.c
+@@ -216,6 +216,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
+
+ for (opt = opts; opt; opt = opt6_next(opt, end))
+ {
++ 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)
+ {
+--
+2.9.5
+
--- /dev/null
+From f2ad2cecb55825f7e4409222de1688b9ceebceda Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 20:16:50 +0100
+Subject: [PATCH 6/9] Security fix, CVE-2017-14495, OOM in DNS response
+ creation.
+
+ Fix out-of-memory Dos vulnerability. An attacker which can
+ send malicious DNS queries to dnsmasq can trigger memory
+ allocations in the add_pseudoheader function
+ The allocated memory is never freed which leads to a DoS
+ through memory exhaustion. dnsmasq is vulnerable only
+ if one of the following option is specified:
+ --add-mac, --add-cpe-id or --add-subnet.
+---
+ src/edns0.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/edns0.c b/src/edns0.c
+index eed135e..5bdc133 100644
+--- a/src/edns0.c
++++ b/src/edns0.c
+@@ -192,9 +192,15 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ !(p = skip_section(p,
+ ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
+ header, plen)))
++ {
++ free(buff);
+ return plen;
++ }
+ if (p + 11 > limit)
+- return plen; /* Too big */
++ {
++ free(buff);
++ return plen; /* Too big */
++ }
+ *p++ = 0; /* empty name */
+ PUTSHORT(T_OPT, p);
+ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
+--
+2.9.5
+
--- /dev/null
+From 5ab67e936085a9e584c9b3e43f442ef5bee7f40e Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 20:11:58 +0100
+Subject: [PATCH 5/9] Security fix, CVE-2017-14496, Integer underflow in
+ DNS response creation.
+
+ Fix DoS in DNS. Invalid boundary checks in the
+ add_pseudoheader function allows a memcpy call with negative
+ size An attacker which can send malicious DNS queries
+ to dnsmasq can trigger a DoS remotely.
+ dnsmasq is vulnerable only if one of the following option is
+ specified: --add-mac, --add-cpe-id or --add-subnet.
+---
+ src/edns0.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/edns0.c b/src/edns0.c
+index d2b514b..eed135e 100644
+--- a/src/edns0.c
++++ b/src/edns0.c
+@@ -144,7 +144,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ GETSHORT(len, p);
+
+ /* malformed option, delete the whole OPT RR and start again. */
+- if (i + len > rdlen)
++ if (i + 4 + len > rdlen)
+ {
+ rdlen = 0;
+ is_last = 0;
+@@ -193,6 +193,8 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
+ header, plen)))
+ return plen;
++ if (p + 11 > limit)
++ return plen; /* Too big */
+ *p++ = 0; /* empty name */
+ PUTSHORT(T_OPT, p);
+ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
+@@ -204,6 +206,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ /* Copy back any options */
+ if (buff)
+ {
++ if (p + rdlen > limit)
++ {
++ free(buff);
++ return plen; /* Too big */
++ }
+ memcpy(p, buff, rdlen);
+ free(buff);
+ p += rdlen;
+@@ -217,8 +224,12 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ /* Add new option */
+ if (optno != 0 && replace != 2)
+ {
++ if (p + 4 > limit)
++ return plen; /* Too big */
+ PUTSHORT(optno, p);
+ PUTSHORT(optlen, p);
++ if (p + optlen > limit)
++ return plen; /* Too big */
+ memcpy(p, opt, optlen);
+ p += optlen;
+ PUTSHORT(p - datap, lenp);
+--
+2.9.5
+
--- /dev/null
+From 7ab5d6bd1f8b018c73341f50a395405dee6873d8 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Wed, 15 Mar 2017 14:26:04 +0100
+Subject: [PATCH] Coverity fixes
+
+---
+ src/dbus.c | 2 +-
+ src/dhcp-common.c | 2 +-
+ src/dhcp.c | 4 ++--
+ src/dnsmasq.h | 2 +-
+ src/edns0.c | 2 ++
+ src/inotify.c | 9 ++++++---
+ src/lease.c | 4 ++--
+ src/network.c | 8 ++++----
+ src/option.c | 16 +++++++++++-----
+ src/tftp.c | 2 +-
+ src/util.c | 2 +-
+ 11 files changed, 32 insertions(+), 21 deletions(-)
+
+diff --git a/src/dbus.c b/src/dbus.c
+index 2e1a48e..f27ec3e 100644
+--- a/src/dbus.c
++++ b/src/dbus.c
+@@ -550,7 +550,7 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
+ "Invalid IP address '%s'", ipaddr);
+
+ hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
+- if (hw_type == 0 && hw_len != 0)
++ if (hw_type == 0 && hw_len > 0)
+ hw_type = ARPHRD_ETHER;
+
+ lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
+diff --git a/src/dhcp-common.c b/src/dhcp-common.c
+index 08528e8..ebf06b6 100644
+--- a/src/dhcp-common.c
++++ b/src/dhcp-common.c
+@@ -487,7 +487,7 @@ void bindtodevice(char *device, int fd)
+ {
+ struct ifreq ifr;
+
+- strcpy(ifr.ifr_name, device);
++ strncpy(ifr.ifr_name, device, IF_NAMESIZE-1);
+ /* only allowed by root. */
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
+ errno != EPERM)
+diff --git a/src/dhcp.c b/src/dhcp.c
+index 10f1fb9..37bb71e 100644
+--- a/src/dhcp.c
++++ b/src/dhcp.c
+@@ -246,7 +246,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+ }
+ else
+ {
+- strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
++ strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE-1);
+ break;
+ }
+ }
+@@ -270,7 +270,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+ is_relay_reply = 1;
+ iov.iov_len = sz;
+ #ifdef HAVE_LINUX_NETWORK
+- strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
++ strncpy(arp_req.arp_dev, ifr.ifr_name, IF_NAMESIZE-1);
+ #endif
+ }
+ else
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index dfd15aa..1179492 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -180,7 +180,7 @@ struct event_desc {
+ #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 option_bool(x) (((x) < 32) ? daemon->options & (1u << ((x)&0x1F)) : daemon->options2 & (1u << ((x) - 32)))
+
+ #define OPT_BOGUSPRIV 0
+ #define OPT_FILTER 1
+diff --git a/src/edns0.c b/src/edns0.c
+index c7a101e..d2b514b 100644
+--- a/src/edns0.c
++++ b/src/edns0.c
+@@ -263,6 +263,8 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
+ encode[8] = 0;
+ }
+ }
++ else
++ encode[0] = '\0';
+
+ return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
+ }
+diff --git a/src/inotify.c b/src/inotify.c
+index 603ce9d..fcc0d97 100644
+--- a/src/inotify.c
++++ b/src/inotify.c
+@@ -224,17 +224,20 @@ int inotify_check(time_t now)
+
+ if (rc <= 0)
+ break;
++ else
++ inotify_buffer[rc] = '\0';
+
+ for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
+ {
+ in = (struct inotify_event*)p;
+-
++
+ for (res = daemon->resolv_files; res; res = res->next)
+- if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
++ if (res->wd == in->wd && in->len != 0 && strncmp(res->file, in->name, NAME_MAX) == 0)
+ hit = 1;
+
+ /* ignore emacs backups and dotfiles */
+- if (in->len == 0 ||
++ if (in->len == 0 ||
++ in->len > NAME_MAX+1 ||
+ in->name[in->len - 1] == '~' ||
+ (in->name[0] == '#' && in->name[in->len - 1] == '#') ||
+ in->name[0] == '.')
+diff --git a/src/lease.c b/src/lease.c
+index 20cac90..9ad106d 100644
+--- a/src/lease.c
++++ b/src/lease.c
+@@ -827,9 +827,9 @@ void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
+
+ if (hw_len != lease->hwaddr_len ||
+ hw_type != lease->hwaddr_type ||
+- (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
++ (hw_len > 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
+ {
+- if (hw_len != 0)
++ if (hw_len > 0)
+ memcpy(lease->hwaddr, hwaddr, hw_len);
+ lease->hwaddr_len = hw_len;
+ lease->hwaddr_type = hw_type;
+diff --git a/src/network.c b/src/network.c
+index 6119039..fcd9d8d 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -188,7 +188,7 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
+ struct ifreq ifr;
+ struct irec *iface;
+
+- strncpy(ifr.ifr_name, name, IF_NAMESIZE);
++ strncpy(ifr.ifr_name, name, IF_NAMESIZE-1);
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
+ ifr.ifr_flags & IFF_LOOPBACK)
+ {
+@@ -1206,7 +1206,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
+ return 0;
+
+ #if defined(SO_BINDTODEVICE)
+- if (intname[0] != 0 &&
++ if (intname && intname[0] != 0 &&
+ setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
+ return 0;
+ #endif
+@@ -1245,7 +1245,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
+ /* may have a suitable one already */
+ for (sfd = daemon->sfds; sfd; sfd = sfd->next )
+ if (sockaddr_isequal(&sfd->source_addr, addr) &&
+- strcmp(intname, sfd->interface) == 0 &&
++ intname && strcmp(intname, sfd->interface) == 0 &&
+ ifindex == sfd->ifindex)
+ return sfd;
+
+@@ -1437,7 +1437,7 @@ void add_update_server(int flags,
+ serv->flags |= SERV_HAS_DOMAIN;
+
+ if (interface)
+- strcpy(serv->interface, interface);
++ strncpy(serv->interface, interface, sizeof(serv->interface)-1);
+ if (addr)
+ serv->addr = *addr;
+ if (source_addr)
+diff --git a/src/option.c b/src/option.c
+index 5503b79..eb78b1a 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -3929,13 +3929,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+
+ case LOPT_HOST_REC: /* --host-record */
+ {
+- struct host_record *new = opt_malloc(sizeof(struct host_record));
+- memset(new, 0, sizeof(struct host_record));
+- new->ttl = -1;
++ struct host_record *new;
+
+ if (!arg || !(comma = split(arg)))
+ ret_err(_("Bad host-record"));
+
++ new = opt_malloc(sizeof(struct host_record));
++ memset(new, 0, sizeof(struct host_record));
++ new->ttl = -1;
++
+ while (arg)
+ {
+ struct all_addr addr;
+@@ -3956,10 +3958,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+ {
+ int nomem;
+ char *canon = canonicalise(arg, &nomem);
+- struct name_list *nl = opt_malloc(sizeof(struct name_list));
++ struct name_list *nl;
+ if (!canon)
+ ret_err(_("Bad name in host-record"));
+
++ nl = opt_malloc(sizeof(struct name_list));
+ nl->name = canon;
+ /* keep order, so that PTR record goes to first name */
+ nl->next = NULL;
+@@ -4023,7 +4026,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+ !atoi_check8(algo, &new->algo) ||
+ !atoi_check8(digest, &new->digest_type) ||
+ !(new->name = canonicalise_opt(arg)))
+- ret_err(_("bad trust anchor"));
++ {
++ free(new);
++ ret_err(_("bad trust anchor"));
++ }
+
+ /* Upper bound on length */
+ len = (2*strlen(keyhex))+1;
+diff --git a/src/tftp.c b/src/tftp.c
+index 5e4a32a..bd8c622 100644
+--- a/src/tftp.c
++++ b/src/tftp.c
+@@ -234,7 +234,7 @@ void tftp_request(struct listener *listen, time_t now)
+ #endif
+ }
+
+- strncpy(ifr.ifr_name, name, IF_NAMESIZE);
++ strncpy(ifr.ifr_name, name, IF_NAMESIZE-1);
+ if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
+ {
+ mtu = ifr.ifr_mtu;
+diff --git a/src/util.c b/src/util.c
+index 93b24f5..1a9f228 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -491,7 +491,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
+ int j, bytes = (1 + (r - in))/2;
+ for (j = 0; j < bytes; j++)
+ {
+- char sav = sav;
++ char sav;
+ if (j < bytes - 1)
+ {
+ sav = in[(j+1)*2];
+--
+2.9.3
+
--- /dev/null
+From 87444dc6977b61096127dcdfe87dc6cf2c0167d6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
+Date: Sun, 16 Apr 2017 20:20:08 +0100
+Subject: [PATCH] Capture and log STDOUT and STDERR output from dhcp-script.
+
+(cherry picked from commit c77fb9d8f09d136fa71bde2469c4fd11cefa6f4a)
+
+Compile-time check on buffer sizes for leasefile parsing code.
+
+(cherry picked from commit bf4e62c19e619f7edf8d03d58d33a5752f190bfd)
+
+Improve error handling with shcp-script "init" mode.
+
+(cherry picked from commit 3a8b0f6fccf464b1ec6d24c0e00e540ab2b17705)
+
+Tweak logging introduced in 3a8b0f6fccf464b1ec6d24c0e00e540ab2b17705
+
+(cherry picked from commit efff74c1aea14757ce074db28e02671c7f7bb5f5)
+
+Don't die() on failing to parse lease-script output.
+
+(cherry picked from commit 05f76dab89d5b879519a4f45b0cccaa1fc3d162d)
+---
+ man/dnsmasq.8 | 4 +-
+ src/dhcp-common.c | 16 +++---
+ src/dhcp-protocol.h | 4 ++
+ src/dnsmasq.c | 8 +++
+ src/dnsmasq.h | 54 +++++++++---------
+ src/helper.c | 56 +++++++++++++++++-
+ src/lease.c | 159 +++++++++++++++++++++++++++++++---------------------
+ src/log.c | 4 +-
+ src/rfc3315.c | 2 +-
+ 9 files changed, 202 insertions(+), 105 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index 0521534..97d0a4f 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -1551,8 +1551,8 @@ database.
+
+
+ All file descriptors are
+-closed except stdin, stdout and stderr which are open to /dev/null
+-(except in debug mode).
++closed except stdin, which is open to /dev/null, and stdout and stderr which capture output for logging by dnsmasq.
++(In debug mode, stdio, stdout and stderr file are left as those inherited from the invoker of dnsmasq).
+
+ The script is not invoked concurrently: at most one instance
+ of the script is ever running (dnsmasq waits for an instance of script to exit
+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/dnsmasq.c b/src/dnsmasq.c
+index 045ec53..9cd4052 100644
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -1294,6 +1294,7 @@ static void async_event(int pipe, time_t now)
+ daemon->tcp_pids[i] = 0;
+ break;
+
++#if defined(HAVE_SCRIPT)
+ case EVENT_KILLED:
+ my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
+ break;
+@@ -1307,12 +1308,19 @@ static void async_event(int pipe, time_t now)
+ daemon->lease_change_command, strerror(ev.data));
+ break;
+
++ case EVENT_SCRIPT_LOG:
++ my_syslog(MS_SCRIPT | LOG_DEBUG, "%s", msg ? msg : "");
++ free(msg);
++ msg = NULL;
++ break;
++
+ /* necessary for fatal errors in helper */
+ case EVENT_USER_ERR:
+ case EVENT_DIE:
+ case EVENT_LUA_ERR:
+ fatal_event(&ev, msg);
+ break;
++#endif
+
+ case EVENT_REOPEN:
+ /* Note: this may leave TCP-handling processes with the old file still open.
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 1896a64..0cfd3c6 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -145,30 +145,31 @@ struct event_desc {
+ int event, data, msg_sz;
+ };
+
+-#define EVENT_RELOAD 1
+-#define EVENT_DUMP 2
+-#define EVENT_ALARM 3
+-#define EVENT_TERM 4
+-#define EVENT_CHILD 5
+-#define EVENT_REOPEN 6
+-#define EVENT_EXITED 7
+-#define EVENT_KILLED 8
+-#define EVENT_EXEC_ERR 9
+-#define EVENT_PIPE_ERR 10
+-#define EVENT_USER_ERR 11
+-#define EVENT_CAP_ERR 12
+-#define EVENT_PIDFILE 13
+-#define EVENT_HUSER_ERR 14
+-#define EVENT_GROUP_ERR 15
+-#define EVENT_DIE 16
+-#define EVENT_LOG_ERR 17
+-#define EVENT_FORK_ERR 18
+-#define EVENT_LUA_ERR 19
+-#define EVENT_TFTP_ERR 20
+-#define EVENT_INIT 21
+-#define EVENT_NEWADDR 22
+-#define EVENT_NEWROUTE 23
+-#define EVENT_TIME_ERR 24
++#define EVENT_RELOAD 1
++#define EVENT_DUMP 2
++#define EVENT_ALARM 3
++#define EVENT_TERM 4
++#define EVENT_CHILD 5
++#define EVENT_REOPEN 6
++#define EVENT_EXITED 7
++#define EVENT_KILLED 8
++#define EVENT_EXEC_ERR 9
++#define EVENT_PIPE_ERR 10
++#define EVENT_USER_ERR 11
++#define EVENT_CAP_ERR 12
++#define EVENT_PIDFILE 13
++#define EVENT_HUSER_ERR 14
++#define EVENT_GROUP_ERR 15
++#define EVENT_DIE 16
++#define EVENT_LOG_ERR 17
++#define EVENT_FORK_ERR 18
++#define EVENT_LUA_ERR 19
++#define EVENT_TFTP_ERR 20
++#define EVENT_INIT 21
++#define EVENT_NEWADDR 22
++#define EVENT_NEWROUTE 23
++#define EVENT_TIME_ERR 24
++#define EVENT_SCRIPT_LOG 25
+
+ /* Exit codes. */
+ #define EC_GOOD 0
+@@ -242,8 +243,9 @@ struct event_desc {
+
+ /* 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
+-#define MS_DHCP LOG_DAEMON
++#define MS_TFTP LOG_USER
++#define MS_DHCP LOG_DAEMON
++#define MS_SCRIPT LOG_MAIL
+
+ struct all_addr {
+ union {
+diff --git a/src/helper.c b/src/helper.c
+index 9c37e37..de31383 100644
+--- a/src/helper.c
++++ b/src/helper.c
+@@ -14,6 +14,7 @@
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++#include <stdio.h>
+ #include "dnsmasq.h"
+
+ #ifdef HAVE_SCRIPT
+@@ -135,7 +136,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+ max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
+ max_fd != event_fd && max_fd != err_fd)
+ close(max_fd);
+-
++
+ #ifdef HAVE_LUASCRIPT
+ if (daemon->luascript)
+ {
+@@ -189,6 +190,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+ unsigned char *buf = (unsigned char *)daemon->namebuff;
+ unsigned char *end, *extradata, *alloc_buff = NULL;
+ int is6, err = 0;
++ int pipeout[2];
+
+ free(alloc_buff);
+
+@@ -472,16 +474,54 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+ if (!daemon->lease_change_command)
+ continue;
+
++ /* Pipe to capture stdout and stderr from script */
++ if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1)
++ continue;
++
+ /* possible fork errors are all temporary resource problems */
+ while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
+ sleep(2);
+
+ if (pid == -1)
+- continue;
++ {
++ if (!option_bool(OPT_DEBUG))
++ {
++ close(pipeout[0]);
++ close(pipeout[1]);
++ }
++ continue;
++ }
+
+ /* wait for child to complete */
+ if (pid != 0)
+ {
++ if (!option_bool(OPT_DEBUG))
++ {
++ FILE *fp;
++
++ close(pipeout[1]);
++
++ /* Read lines sent to stdout/err by the script and pass them back to be logged */
++ if (!(fp = fdopen(pipeout[0], "r")))
++ close(pipeout[0]);
++ else
++ {
++ while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
++ {
++ /* do not include new lines, log will append them */
++ size_t len = strlen(daemon->packet);
++ if (len > 0)
++ {
++ --len;
++ if (daemon->packet[len] == '\n')
++ daemon->packet[len] = 0;
++ }
++ send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
++ }
++ fclose(fp);
++ }
++ }
++
+ /* reap our children's children, if necessary */
+ while (1)
+ {
+@@ -504,6 +544,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+
+ continue;
+ }
++
++ if (!option_bool(OPT_DEBUG))
++ {
++ /* map stdout/stderr of script to pipeout */
++ close(pipeout[0]);
++ dup2(pipeout[1], STDOUT_FILENO);
++ dup2(pipeout[1], STDERR_FILENO);
++ close(pipeout[1]);
++ }
+
+ if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
+ {
+@@ -579,7 +628,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+ hostname = NULL;
+
+ my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
+- }
++ }
++
+ /* we need to have the event_fd around if exec fails */
+ if ((i = fcntl(event_fd, F_GETFD)) != -1)
+ fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
+diff --git a/src/lease.c b/src/lease.c
+index 20cac90..64047f9 100644
+--- a/src/lease.c
++++ b/src/lease.c
+@@ -21,94 +21,62 @@
+ static struct dhcp_lease *leases = NULL, *old_leases = NULL;
+ static int dns_dirty, file_dirty, leases_left;
+
+-void lease_init(time_t now)
++static int read_leases(time_t now, FILE *leasestream)
+ {
+ unsigned long ei;
+ struct all_addr addr;
+ struct dhcp_lease *lease;
+ int clid_len, hw_len, hw_type;
+- FILE *leasestream;
+-
+- leases_left = daemon->dhcp_max;
+-
+- if (option_bool(OPT_LEASE_RO))
+- {
+- /* run "<lease_change_script> init" once to get the
+- initial state of the database. If leasefile-ro is
+- set without a script, we just do without any
+- lease database. */
+-#ifdef HAVE_SCRIPT
+- if (daemon->lease_change_command)
+- {
+- strcpy(daemon->dhcp_buff, daemon->lease_change_command);
+- strcat(daemon->dhcp_buff, " init");
+- leasestream = popen(daemon->dhcp_buff, "r");
+- }
+- else
++ int items;
++ char *domain = NULL;
++
++ *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
++
++ /* client-id max length is 255 which is 255*2 digits + 254 colons
++ 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 leasefile parsing.
+ #endif
+- {
+- file_dirty = dns_dirty = 0;
+- return;
+- }
+
+- }
+- else
+- {
+- /* NOTE: need a+ mode to create file if it doesn't exist */
+- leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
+-
+- if (!leasestream)
+- die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
+-
+- /* a+ mode leaves pointer at end. */
+- rewind(leasestream);
+- }
+-
+- /* client-id max length is 255 which is 255*2 digits + 254 colons
+- borrow DNS packet buffer which is always larger than 1000 bytes */
+- if (leasestream)
+- while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
++ while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
+ {
++ *daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
++ hw_len = hw_type = clid_len = 0;
++
+ #ifdef HAVE_DHCP6
+ if (strcmp(daemon->dhcp_buff3, "duid") == 0)
+ {
+ daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
++ if (daemon->duid_len < 0)
++ return 0;
+ daemon->duid = safe_malloc(daemon->duid_len);
+ memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
+ continue;
+ }
+ #endif
+-
+- ei = atol(daemon->dhcp_buff3);
+
+ if (fscanf(leasestream, " %64s %255s %764s",
+ daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
+- break;
++ return 0;
+
+- clid_len = 0;
+- if (strcmp(daemon->packet, "*") != 0)
+- clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
+-
+- if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
+- (lease = lease4_allocate(addr.addr.addr4)))
++ if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4))
+ {
++ if ((lease = lease4_allocate(addr.addr.addr4)))
++ domain = get_domain(lease->addr);
++
+ hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
+ /* For backwards compatibility, no explict MAC address type means ether. */
+ if (hw_type == 0 && hw_len != 0)
+ hw_type = ARPHRD_ETHER;
+-
+- lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
+- hw_len, hw_type, clid_len, now, 0);
+-
+- if (strcmp(daemon->dhcp_buff, "*") != 0)
+- lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
+ }
+ #ifdef HAVE_DHCP6
+ else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
+ {
+ char *s = daemon->dhcp_buff2;
+ int lease_type = LEASE_NA;
+- int iaid;
+
+ if (s[0] == 'T')
+ {
+@@ -116,23 +84,30 @@ void lease_init(time_t now)
+ s++;
+ }
+
+- iaid = strtoul(s, NULL, 10);
+-
+ if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
+ {
+- lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
+- lease_set_iaid(lease, iaid);
+- if (strcmp(daemon->dhcp_buff, "*") != 0)
+- lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
++ lease_set_iaid(lease, strtoul(s, NULL, 10));
++ domain = get_domain6((struct in6_addr *)lease->hwaddr);
+ }
+ }
+ #endif
+ else
+- break;
++ return 0;
+
+ if (!lease)
+ die (_("too many stored leases"), NULL, EC_MISC);
+-
++
++ if (strcmp(daemon->packet, "*") != 0)
++ clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
++
++ lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
++ hw_len, hw_type, clid_len, now, 0);
++
++ if (strcmp(daemon->dhcp_buff, "*") != 0)
++ lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
++
++ ei = atol(daemon->dhcp_buff3);
++
+ #ifdef HAVE_BROKEN_RTC
+ if (ei != 0)
+ lease->expires = (time_t)ei + now;
+@@ -148,7 +123,62 @@ void lease_init(time_t now)
+ /* set these correctly: the "old" events are generated later from
+ the startup synthesised SIGHUP. */
+ lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
++
++ *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
+ }
++
++ return (items == 0 || items == EOF);
++}
++
++void lease_init(time_t now)
++{
++ FILE *leasestream;
++
++ leases_left = daemon->dhcp_max;
++
++ if (option_bool(OPT_LEASE_RO))
++ {
++ /* run "<lease_change_script> init" once to get the
++ initial state of the database. If leasefile-ro is
++ set without a script, we just do without any
++ lease database. */
++#ifdef HAVE_SCRIPT
++ if (daemon->lease_change_command)
++ {
++ strcpy(daemon->dhcp_buff, daemon->lease_change_command);
++ strcat(daemon->dhcp_buff, " init");
++ leasestream = popen(daemon->dhcp_buff, "r");
++ }
++ else
++#endif
++ {
++ file_dirty = dns_dirty = 0;
++ return;
++ }
++
++ }
++ else
++ {
++ /* NOTE: need a+ mode to create file if it doesn't exist */
++ leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
++
++ if (!leasestream)
++ die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
++
++ /* a+ mode leaves pointer at end. */
++ rewind(leasestream);
++ }
++
++ 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);
++
++ if (ferror(leasestream))
++ die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
++ }
+
+ #ifdef HAVE_SCRIPT
+ if (!daemon->lease_stream)
+@@ -162,6 +192,7 @@ void lease_init(time_t now)
+ errno = ENOENT;
+ else if (WEXITSTATUS(rc) == 126)
+ errno = EACCES;
++
+ die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
+ }
+
+diff --git a/src/log.c b/src/log.c
+index 8e66629..5fc860b 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -288,7 +288,9 @@ void my_syslog(int priority, const char *format, ...)
+ func = "-tftp";
+ else if ((LOG_FACMASK & priority) == MS_DHCP)
+ func = "-dhcp";
+-
++ else if ((LOG_FACMASK & priority) == MS_SCRIPT)
++ func = "-script";
++
+ #ifdef LOG_PRI
+ priority = LOG_PRI(priority);
+ #else
+diff --git a/src/rfc3315.c b/src/rfc3315.c
+index 3f4d69c..a3715cd 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
+--
+2.9.3
+
--- /dev/null
+From 2675f2061525bc954be14988d64384b74aa7bf8b Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Sun, 28 Aug 2016 20:44:05 +0100
+Subject: [PATCH] Handle binding upstream servers to an interface
+ (--server=1.2.3.4@eth0) when the named interface is destroyed and recreated
+ in the kernel.
+
+---
+ CHANGELOG | 5 +++++
+ src/dnsmasq.h | 1 +
+ src/network.c | 31 +++++++++++++++++++++++++++++--
+ 3 files changed, 35 insertions(+), 2 deletions(-)
+
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 27385a9..f239ce5 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -488,6 +488,7 @@ struct serverfd {
+ int fd;
+ union mysockaddr source_addr;
+ char interface[IF_NAMESIZE+1];
++ unsigned int ifindex, used;
+ struct serverfd *next;
+ };
+
+diff --git a/src/network.c b/src/network.c
+index e7722fd..ddf8d31 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -1204,6 +1204,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
+ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
+ {
+ struct serverfd *sfd;
++ unsigned int ifindex = 0;
+ int errsave;
+
+ /* when using random ports, servers which would otherwise use
+@@ -1224,11 +1225,15 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
+ return NULL;
+ #endif
+ }
++
++ if (intname && strlen(intname) != 0)
++ ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */
+
+ /* may have a suitable one already */
+ for (sfd = daemon->sfds; sfd; sfd = sfd->next )
+ if (sockaddr_isequal(&sfd->source_addr, addr) &&
+- strcmp(intname, sfd->interface) == 0)
++ strcmp(intname, sfd->interface) == 0 &&
++ ifindex == sfd->ifindex)
+ return sfd;
+
+ /* need to make a new one. */
+@@ -1250,11 +1255,13 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
+ errno = errsave;
+ return NULL;
+ }
+-
++
+ strcpy(sfd->interface, intname);
+ sfd->source_addr = *addr;
+ sfd->next = daemon->sfds;
++ sfd->ifindex = ifindex;
+ daemon->sfds = sfd;
++
+ return sfd;
+ }
+
+@@ -1429,12 +1436,16 @@ void check_servers(void)
+ {
+ struct irec *iface;
+ struct server *serv;
++ struct serverfd *sfd, *tmp, **up;
+ int port = 0, count;
+
+ /* interface may be new since startup */
+ if (!option_bool(OPT_NOWILD))
+ enumerate_interfaces(0);
+
++ for (sfd = daemon->sfds; sfd; sfd = sfd->next)
++ sfd->used = 0;
++
+ #ifdef HAVE_DNSSEC
+ /* Disable DNSSEC validation when using server=/domain/.... servers
+ unless there's a configured trust anchor. */
+@@ -1505,6 +1516,8 @@ void check_servers(void)
+ serv->flags |= SERV_MARK;
+ continue;
+ }
++
++ serv->sfd->used = 1;
+ }
+
+ if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
+@@ -1547,6 +1560,20 @@ void check_servers(void)
+ if (count - 1 > SERVERS_LOGGED)
+ my_syslog(LOG_INFO, _("using %d more nameservers"), count - SERVERS_LOGGED - 1);
+
++ /* Remove unused sfds */
++ for (sfd = daemon->sfds, up = &daemon->sfds; sfd; sfd = tmp)
++ {
++ tmp = sfd->next;
++ if (!sfd->used)
++ {
++ *up = sfd->next;
++ close(sfd->fd);
++ free(sfd);
++ }
++ else
++ up = &sfd->next;
++ }
++
+ cleanup_servers();
+ }
+
+--
+2.7.4
+
--- /dev/null
+diff --git a/src/helper.c b/src/helper.c
+index de31383..a843b41 100644
+--- a/src/helper.c
++++ b/src/helper.c
+@@ -14,7 +14,6 @@
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+-#include <stdio.h>
+ #include "dnsmasq.h"
+
+ #ifdef HAVE_SCRIPT
--- /dev/null
+From 16800ea072dd0cdf14d951c4bb8d2808b3dfe53d Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Tue, 30 Aug 2016 23:07:06 +0100
+Subject: [PATCH] Fix crash introduced in
+ 2675f2061525bc954be14988d64384b74aa7bf8b
+
+---
+ src/network.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/network.c b/src/network.c
+index ddf8d31..d87d08f 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -1516,8 +1516,9 @@ void check_servers(void)
+ serv->flags |= SERV_MARK;
+ continue;
+ }
+-
+- serv->sfd->used = 1;
++
++ if (serv->sfd)
++ serv->sfd->used = 1;
+ }
+
+ if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
+--
+2.9.3
+
--- /dev/null
+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;
+--
+2.9.3
+
--- /dev/null
+From 2c1aec1e979a209eb2f2b035314a8c973b4ac269 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Thu, 7 Sep 2017 20:45:00 +0100
+Subject: [PATCH 7/9] Don't return arcount=1 if EDNS0 RR won't fit in the
+ packet.
+
+ Omitting the EDNS0 RR but setting arcount gives a malformed packet.
+ Also, don't accept UDP packet size less than 512 in recieved EDNS0.
+---
+ src/edns0.c | 5 ++++-
+ src/forward.c | 2 ++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/edns0.c b/src/edns0.c
+index 5bdc133..a8d0167 100644
+--- a/src/edns0.c
++++ b/src/edns0.c
+@@ -221,7 +221,10 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ free(buff);
+ p += rdlen;
+ }
+- header->arcount = htons(ntohs(header->arcount) + 1);
++
++ /* Only bump arcount if RR is going to fit */
++ if (((ssize_t)optlen) <= (limit - (p + 4)))
++ header->arcount = htons(ntohs(header->arcount) + 1);
+ }
+
+ if (((ssize_t)optlen) > (limit - (p + 4)))
+diff --git a/src/forward.c b/src/forward.c
+index 9b464d3..0f8f462 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -1408,6 +1408,8 @@ void receive_query(struct listener *listen, time_t now)
+ defaults to 512 */
+ if (udp_size > daemon->edns_pktsz)
+ udp_size = daemon->edns_pktsz;
++ else if (udp_size < PACKETSZ)
++ udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
+ }
+
+ #ifdef HAVE_AUTH
+--
+2.9.5
+
--- /dev/null
+diff --git a/src/dnsmasq.c b/src/dnsmasq.c
+index e1d3bbd..99e5437 100644
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -358,7 +358,8 @@ int main (int argc, char **argv)
+ }
+
+ #ifdef HAVE_INOTIFY
+- if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
++ if ((daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
++ && (!option_bool(OPT_NO_RESOLV) || daemon->dynamic_dirs))
+ inotify_dnsmasq_init();
+ else
+ daemon->inotifyfd = -1;
--- /dev/null
+From 6eaafb18e56928881bae371ba8bb05ee93f55d54 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
+Date: Tue, 14 Mar 2017 15:24:58 +0100
+Subject: [PATCH 2/2] Document real behaviour of labels with --interface
+
+---
+ man/dnsmasq.8 | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index 523c823..6e93cf1 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -203,12 +203,14 @@ or
+ options are given dnsmasq listens on all available interfaces except any
+ given in
+ .B \--except-interface
+-options. IP alias interfaces (eg "eth1:0") cannot be used with
+-.B --interface
++options. IP alias interface names (eg "eth1:0") can be used only in
++.B \--bind-interfaces
+ or
+-.B --except-interface
+-options, use --listen-address instead. A simple wildcard, consisting
+-of a trailing '*', can be used in
++.B \--bind-dynamic
++mode. Use
++.B \--listen-address
++in the default mode instead. A simple wildcard, consisting of a trailing '*',
++can be used in
+ .B \--interface
+ and
+ .B \--except-interface
+--
+2.9.3
+
--- /dev/null
+From c3d10a1132ada7baa80914f61abb720f94400465 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
+Date: Tue, 14 Mar 2017 15:23:22 +0100
+Subject: [PATCH 1/2] Warn when using label in default mode
+
+---
+ src/dnsmasq.c | 2 ++
+ src/dnsmasq.h | 3 ++-
+ src/network.c | 13 +++++++++++++
+ 3 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/src/dnsmasq.c b/src/dnsmasq.c
+index 456b0e8..d2cc7cc 100644
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -771,6 +771,8 @@ int main (int argc, char **argv)
+
+ if (option_bool(OPT_NOWILD))
+ warn_bound_listeners();
++ else if (!option_bool(OPT_CLEVERBIND))
++ warn_wild_labels();
+
+ warn_int_names();
+
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index a27fbc1..6b44e53 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -522,7 +522,7 @@ struct ipsets {
+ struct irec {
+ union mysockaddr addr;
+ struct in_addr netmask; /* only valid for IPv4 */
+- int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found;
++ int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found, label;
+ char *name;
+ struct irec *next;
+ };
+@@ -1252,6 +1252,7 @@ int enumerate_interfaces(int reset);
+ void create_wildcard_listeners(void);
+ void create_bound_listeners(int die);
+ void warn_bound_listeners(void);
++void warn_wild_labels(void);
+ void warn_int_names(void);
+ int is_dad_listeners(void);
+ int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
+diff --git a/src/network.c b/src/network.c
+index eb41624..e5ceb76 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -244,6 +244,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
+ int tftp_ok = !!option_bool(OPT_TFTP);
+ int dhcp_ok = 1;
+ int auth_dns = 0;
++ int is_label = 0;
+ #if defined(HAVE_DHCP) || defined(HAVE_TFTP)
+ struct iname *tmp;
+ #endif
+@@ -264,6 +265,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
+
+ if (!label)
+ label = ifr.ifr_name;
++ else
++ is_label = strcmp(label, ifr.ifr_name);
+
+ /* maintain a list of all addresses on all interfaces for --local-service option */
+ if (option_bool(OPT_LOCAL_SERVICE))
+@@ -482,6 +485,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
+ iface->found = 1;
+ iface->done = iface->multicast_done = iface->warned = 0;
+ iface->index = if_index;
++ iface->label = is_label;
+ if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
+ {
+ strcpy(iface->name, ifr.ifr_name);
+@@ -1034,6 +1038,15 @@ void warn_bound_listeners(void)
+ my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"));
+ }
+
++void warn_wild_labels(void)
++{
++ struct irec *iface;
++
++ for (iface = daemon->interfaces; iface; iface = iface->next)
++ if (iface->found && iface->name && iface->label)
++ my_syslog(LOG_WARNING, _("warning: using interface %s instead"), iface->name);
++}
++
+ void warn_int_names(void)
+ {
+ struct interface_name *intname;
+--
+2.9.3
+
--- /dev/null
+From 3947ab0069e443e72debe26379b8517fac8f6e41 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 25 Sep 2017 20:19:55 +0100
+Subject: [PATCH 8/9] Misc code cleanups arising from Google analysis.
+ No security impleications or CVEs.
+
+---
+ src/edns0.c | 2 +-
+ src/rfc1035.c | 4 +++-
+ src/rfc2131.c | 2 +-
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/edns0.c b/src/edns0.c
+index a8d0167..0552d38 100644
+--- a/src/edns0.c
++++ b/src/edns0.c
+@@ -159,7 +159,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ /* delete option if we're to replace it. */
+ p -= 4;
+ rdlen -= len + 4;
+- memcpy(p, p+len+4, rdlen - i);
++ memmove(p, p+len+4, rdlen - i);
+ PUTSHORT(rdlen, lenp);
+ lenp -= 2;
+ }
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 78410d6..917bac2 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -37,7 +37,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
+ /* end marker */
+ {
+ /* check that there are the correct no of bytes after the name */
+- if (!CHECK_LEN(header, p, plen, extrabytes))
++ if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
+ return 0;
+
+ if (isExtract)
+@@ -485,6 +485,8 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
+ {
+ unsigned int i, len = *p1;
+ unsigned char *p2 = p1;
++ if ((p1 + len - p) >= rdlen)
++ return 0; /* bad packet */
+ /* make counted string zero-term and sanitise */
+ for (i = 0; i < len; i++)
+ {
+diff --git a/src/rfc2131.c b/src/rfc2131.c
+index 75893a6..71d5846 100644
+--- a/src/rfc2131.c
++++ b/src/rfc2131.c
+@@ -155,7 +155,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+ for (offset = 0; offset < (len - 5); offset += elen + 5)
+ {
+ elen = option_uint(opt, offset + 4 , 1);
+- if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
++ if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len)
+ {
+ unsigned char *x = option_ptr(opt, offset + 5);
+ unsigned char *y = option_ptr(opt, offset + elen + 5);
+--
+2.9.5
+
--- /dev/null
+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;
+--
+2.9.3
+
--- /dev/null
+From d4f2e0b8d8f0b5daa0d468f62a0d5f1df58ac325 Mon Sep 17 00:00:00 2001
+From: Doran Moppert <dmoppert@redhat.com>
+Date: Tue, 26 Sep 2017 14:48:20 +0930
+Subject: [PATCH 9/9] google patch hand-applied
+
+---
+ src/edns0.c | 10 +++++-----
+ src/forward.c | 4 ++++
+ src/rfc1035.c | 6 ++++--
+ 3 files changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/src/edns0.c b/src/edns0.c
+index 0552d38..bec4a36 100644
+--- a/src/edns0.c
++++ b/src/edns0.c
+@@ -212,11 +212,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
+ /* Copy back any options */
+ if (buff)
+ {
+- if (p + rdlen > limit)
+- {
+- free(buff);
+- return plen; /* Too big */
+- }
++ if (p + rdlen > limit)
++ {
++ free(buff);
++ return plen; /* Too big */
++ }
+ memcpy(p, buff, rdlen);
+ free(buff);
+ p += rdlen;
+diff --git a/src/forward.c b/src/forward.c
+index 0f8f462..a729c06 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -1412,6 +1412,10 @@ void receive_query(struct listener *listen, time_t now)
+ udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
+ }
+
++ // Make sure the udp size is not smaller than the incoming message so that we
++ // do not underflow
++ if (udp_size < n) udp_size = n;
++
+ #ifdef HAVE_AUTH
+ if (auth_dns)
+ {
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 917bac2..ae65702 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1182,8 +1182,8 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
+ va_end(ap); /* clean up variable argument pointer */
+
+ j = p - sav - 2;
+- /* this has already been checked against limit before */
+- PUTSHORT(j, sav); /* Now, store real RDLength */
++ /* this has already been checked against limit before */
++ PUTSHORT(j, sav); /* Now, store real RDLength */
+
+ /* check for overflow of buffer */
+ if (limit && ((unsigned char *)limit - p) < 0)
+@@ -1243,6 +1243,8 @@ 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;
++ // Make sure we do not underflow here too.
++ if (qlen > (limit - ((char *)header))) return 0;
+
+ if (ntohs(header->ancount) != 0 ||
+ ntohs(header->nscount) != 0 ||
+--
+2.9.5
+
--- /dev/null
+From 13dee6f49e1d035b8069947be84ee8da2af0c420 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Tue, 28 Feb 2017 16:51:58 +0000
+Subject: [PATCH] Compilation warning fixes.
+
+---
+ src/dbus.c | 9 ++++-----
+ src/option.c | 3 ++-
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/dbus.c b/src/dbus.c
+index 7e0d342..2e1a48e 100644
+--- a/src/dbus.c
++++ b/src/dbus.c
+@@ -549,17 +549,16 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
+ return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid IP address '%s'", ipaddr);
+
+- hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL,
+- &hw_type);
++ hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
+ if (hw_type == 0 && hw_len != 0)
+ hw_type = ARPHRD_ETHER;
+-
+- lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
++
++ lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
+ clid_len, now, 0);
+ lease_set_expires(lease, expires, now);
+ if (hostname_len != 0)
+ lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
+-
++
+ lease_update_file(now);
+ lease_update_dns(0);
+
+diff --git a/src/option.c b/src/option.c
+index 4a5ef5f..e03b1e3 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -4089,7 +4089,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
+ {
+ int white, i;
+ volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
+- char *errmess, *p, *arg = NULL, *start;
++ char *errmess, *p, *arg, *start;
+ size_t len;
+
+ /* Memory allocation failure longjmps here if mem_recover == 1 */
+@@ -4100,6 +4100,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
+ mem_recover = 1;
+ }
+
++ arg = NULL;
+ lineno++;
+ errmess = NULL;
+
+--
+2.9.3
+
--- /dev/null
+From 1a91b72146893dab1cca1354dd3b0a8fa74d6b55 Mon Sep 17 00:00:00 2001
+From: Scott Little <scott.little@windriver.com>
+Date: Tue, 18 Oct 2016 13:07:56 -0400
+Subject: WRS: Patch22: dnsmasq-update-ipv6-leases-from-config.patch
+
+---
+ src/lease.c | 53 +++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 43 insertions(+), 10 deletions(-)
+
+diff --git a/src/lease.c b/src/lease.c
+index 69e698c..bc56c47 100644
+--- a/src/lease.c
++++ b/src/lease.c
+@@ -210,6 +210,18 @@ void lease_init(time_t now)
+ dns_dirty = 1;
+ }
+
++static int lease_match_config_addr(struct dhcp_lease *lease, struct dhcp_config *config)
++{
++ if (!(lease->flags & (LEASE_TA | LEASE_NA)) && (config->flags & CONFIG_ADDR))
++ return (lease->addr.s_addr == config->addr.s_addr);
++#ifdef HAVE_DHCP6
++ else if ((lease->flags & (LEASE_TA | LEASE_NA)) && (config->flags & CONFIG_ADDR6))
++ return IN6_ARE_ADDR_EQUAL(&config->addr6, &lease->addr6);
++#endif
++ else
++ return 0;
++}
++
+ void lease_update_from_configs(void)
+ {
+ /* changes to the config may change current leases. */
+@@ -218,16 +230,37 @@ void lease_update_from_configs(void)
+ struct dhcp_config *config;
+ char *name;
+
+- for (lease = leases; lease; lease = lease->next)
+- if (lease->flags & (LEASE_TA | LEASE_NA))
+- continue;
+- else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
+- lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
+- (config->flags & CONFIG_NAME) &&
+- (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
+- lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
+- else if ((name = host_from_dns(lease->addr)))
+- lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
++ for (lease = leases; lease; lease = lease->next) {
++ if (lease->flags & LEASE_TA)
++ continue; /* we do not update temporary ipv6 leases */
++
++ config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
++ (lease->hwaddr_len > 0 ? lease->hwaddr : NULL),
++ lease->hwaddr_len, lease->hwaddr_type, NULL);
++ if (config)
++ {
++ if ((!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6))) ||
++ lease_match_config_addr(lease, config))
++ {
++ /*
++ * Either we matched on a config that doesn't have an address in
++ * which case we'll just use the hostname, or we matched on a
++ * config that has the same IP address.
++ */
++ if (!(lease->flags & (LEASE_TA | LEASE_NA)))
++ lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
++#ifdef HAVE_DHCP6
++ else
++ lease_set_hostname(lease, config->hostname, 1, get_domain6(&lease->addr6), NULL);
++#endif
++ continue; /* lease updated; move on to next lease */
++ }
++ }
++
++ /* attempt to find a matching DNS cache entry for an IPv4 entry */
++ if (!(lease->flags & (LEASE_TA | LEASE_NA)) && (name = host_from_dns(lease->addr)))
++ lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
++ }
+ }
+
+ static void ourprintf(int *errp, char *format, ...)
+--
+2.7.4
+
--- /dev/null
+[Unit]
+Description=DNS caching server.
+After=network.target
+
+[Service]
+ExecStart=/usr/bin/dnsmasq -k
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+SUMMARY = "Lightweight, easy to configure DNS forwarder and DHCP server"
+DESCRIPTION = "\
+Dnsmasq is lightweight, easy to configure DNS forwarder and DHCP server. \
+It is designed to provide DNS and, optionally, DHCP, to a small network. \
+It can serve the names of local machines which are not in the global \
+DNS. The DHCP server integrates with the DNS server and allows machines \
+with DHCP-allocated addresses to appear in the DNS with names configured \
+either in each host or in a central configuration file. Dnsmasq supports \
+static and dynamic DHCP leases and BOOTP for network booting of diskless \
+machines. \
+"
+HOMEPAGE = "http://www.thekelleys.org.uk/dnsmasq"
+SECTION = "net"
+
+# GPLv3 was added in version 2.41 as license option
+LICENSE = "GPLv2 | GPLv3"
+LIC_FILES_CHKSUM = "\
+ file://COPYING;md5=0636e73ff0215e8d672dc4c32c317bb3 \
+ file://COPYING-v3;md5=d32239bcb673463ab874e80d47fae504 \
+"
+
+SRC_URI = " \
+ http://www.thekelleys.org.uk/${BPN}/${BP}.tar.gz \
+ file://init \
+ file://dnsmasq-resolvconf.service \
+ file://lua.patch \
+ \
+ file://stx/dnsmasq-2.76-dns-sleep-resume.patch \
+ file://stx/dnsmasq-2.76-fix-dhcp-option-arrangements.patch \
+ file://stx/dnsmasq-2.76-pftables.patch \
+ file://stx/dnsmasq-2.76-fix-crash-dns-resume.patch \
+ file://stx/dnsmasq-2.76-warning-fixes.patch \
+ file://stx/dnsmasq-2.76-label-warning.patch \
+ file://stx/dnsmasq-2.76-label-man.patch \
+ file://stx/dnsmasq-2.76-coverity.patch \
+ file://stx/dnsmasq-2.76-dhcp-script-log.patch \
+ file://stx/dnsmasq-2.76-file_offset32.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14491.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14492.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14493.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14494.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14496.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14495.patch \
+ file://stx/dnsmasq-2.76-gita3303e196.patch \
+ file://stx/dnsmasq-2.76-underflow.patch \
+ file://stx/dnsmasq-2.76-misc-cleanups.patch \
+ file://stx/dnsmasq-2.76-CVE-2017-14491-2.patch \
+ file://stx/dnsmasq-2.76-inotify.patch \
+ file://stx/dnsmasq-update-ipv6-leases-from-config.patch \
+ file://stx/close-tftp-sockets-immediately.patch \
+ file://stx/dnsmasq.service \
+"
+SRC_URI[md5sum] = "6610f8233ca89b15a1bb47c788ffb84f"
+SRC_URI[sha256sum] = "777c4762d2fee3738a0380401f2d087b47faa41db2317c60660d69ad10a76c32"
+
+inherit pkgconfig update-rc.d systemd
+
+INITSCRIPT_NAME = "dnsmasq"
+INITSCRIPT_PARAMS = "defaults"
+
+PACKAGECONFIG ?= "dbus idn"
+PACKAGECONFIG[dbus] = ",,dbus"
+PACKAGECONFIG[idn] = ",,libidn"
+PACKAGECONFIG[conntrack] = ",,libnetfilter-conntrack"
+PACKAGECONFIG[lua] = ",,lua"
+PACKAGECONFIG[resolvconf] = ",,,resolvconf"
+
+EXTRA_OEMAKE = "\
+ 'COPTS=${@bb.utils.contains('PACKAGECONFIG', 'dbus', '-DHAVE_DBUS', '', d)} \
+ ${@bb.utils.contains('PACKAGECONFIG', 'idn', '-DHAVE_IDN', '', d)} \
+ ${@bb.utils.contains('PACKAGECONFIG', 'conntrack', '-DHAVE_CONNTRACK', '', d)} \
+ ${@bb.utils.contains('PACKAGECONFIG', 'lua', '-DHAVE_LUASCRIPT', '', d)}' \
+ 'CFLAGS=${CFLAGS}' \
+ 'LDFLAGS=${LDFLAGS}' \
+"
+
+SRC_URI += "${@bb.utils.contains('PACKAGECONFIG', 'resolvconf', 'file://dnsmasq.resolvconf file://99_dnsmasq file://dnsmasq-resolvconf-helper', '', d)}"
+
+do_compile_append() {
+ # build dhcp_release
+ cd ${S}/contrib/lease-tools
+ oe_runmake
+}
+
+do_install () {
+ oe_runmake "PREFIX=${D}${prefix}" \
+ "BINDIR=${D}${bindir}" \
+ "MANDIR=${D}${mandir}" \
+ install
+
+ install -d ${D}${sysconfdir}/
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${sysconfdir}/dnsmasq.d
+
+ install -m 644 ${S}/dnsmasq.conf.example ${D}${sysconfdir}/dnsmasq.conf
+ cat << EOF >> ${D}${sysconfdir}/dnsmasq.conf
+
+# Include all files in /etc/dnsmasq.d except RPM backup files
+conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig
+EOF
+
+ install -m 755 ${WORKDIR}/init ${D}${sysconfdir}/init.d/dnsmasq
+
+ install -d ${D}${systemd_system_unitdir}
+
+ if [ "${@bb.utils.filter('PACKAGECONFIG', 'resolvconf', d)}" ]; then
+ install -m 0644 ${WORKDIR}/dnsmasq-resolvconf.service ${D}${systemd_system_unitdir}/dnsmasq.service
+ else
+ install -m 0644 ${WORKDIR}/stx/dnsmasq.service ${D}${systemd_system_unitdir}/dnsmasq.service
+ fi
+
+ install -m 0755 ${S}/contrib/lease-tools/dhcp_release ${D}${bindir}
+ install -m 0755 ${S}/contrib/lease-tools/dhcp_release6 ${D}${bindir}
+ install -m 0755 ${S}/contrib/lease-tools/dhcp_lease_time ${D}${bindir}
+
+ if [ "${@bb.utils.filter('PACKAGECONFIG', 'dbus', d)}" ]; then
+ install -d ${D}${sysconfdir}/dbus-1/system.d
+ install -m 644 dbus/dnsmasq.conf ${D}${sysconfdir}/dbus-1/system.d/
+ fi
+ if [ "${@bb.utils.filter('PACKAGECONFIG', 'resolvconf', d)}" ]; then
+ install -d ${D}${sysconfdir}/resolvconf/update.d/
+ install -m 0755 ${WORKDIR}/dnsmasq.resolvconf ${D}${sysconfdir}/resolvconf/update.d/dnsmasq
+
+ install -d ${D}${sysconfdir}/default/volatiles
+ install -m 0644 ${WORKDIR}/99_dnsmasq ${D}${sysconfdir}/default/volatiles
+ install -m 0755 ${WORKDIR}/dnsmasq-resolvconf-helper ${D}${bindir}
+ fi
+}
+
+CONFFILES_${PN} = "${sysconfdir}/dnsmasq.conf"
+
+RPROVIDES_${PN} += "${PN}-systemd"
+RREPLACES_${PN} += "${PN}-systemd"
+RCONFLICTS_${PN} += "${PN}-systemd"
+SYSTEMD_SERVICE_${PN} = "dnsmasq.service"