dnsmasq: 2.75 with latest patches 030-041 (2016-01-04)
Message ID | 1451927214-28404-1-git-send-email-matthias.fischer@ipfire.org |
---|---|
State | Superseded |
Headers |
Return-Path: <development-bounces@lists.ipfire.org> Received: from mail01.ipfire.org (mail01.tremer.info [172.28.1.200]) by septima.ipfire.org (Postfix) with ESMTP id 90CFD60D75 for <patchwork@ipfire.org>; Mon, 4 Jan 2016 18:07:09 +0100 (CET) Received: from hedwig.ipfire.org (localhost [IPv6:::1]) by mail01.ipfire.org (Postfix) with ESMTP id 3E4223F7D; Mon, 4 Jan 2016 18:07:09 +0100 (CET) Received: from Devel.localdomain (p5DD824BB.dip0.t-ipconnect.de [93.216.36.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by mail01.ipfire.org (Postfix) with ESMTPSA id C910D161 for <development@lists.ipfire.org>; Mon, 4 Jan 2016 18:06:58 +0100 (CET) From: Matthias Fischer <matthias.fischer@ipfire.org> To: development@lists.ipfire.org Subject: [PATCH] dnsmasq: 2.75 with latest patches 030-041 (2016-01-04) Date: Mon, 4 Jan 2016 18:06:54 +0100 Message-Id: <1451927214-28404-1-git-send-email-matthias.fischer@ipfire.org> X-Mailer: git-send-email 2.6.4 X-BeenThere: development@lists.ipfire.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: IPFire development talk <development.lists.ipfire.org> List-Unsubscribe: <http://lists.ipfire.org/mailman/options/development>, <mailto:development-request@lists.ipfire.org?subject=unsubscribe> List-Archive: <http://lists.ipfire.org/pipermail/development/> List-Post: <mailto:development@lists.ipfire.org> List-Help: <mailto:development-request@lists.ipfire.org?subject=help> List-Subscribe: <http://lists.ipfire.org/mailman/listinfo/development>, <mailto:development-request@lists.ipfire.org?subject=subscribe> Errors-To: development-bounces@lists.ipfire.org Sender: "Development" <development-bounces@lists.ipfire.org> |
Message
Matthias Fischer
Jan. 5, 2016, 4:06 a.m. UTC
Only for testing - this won't compile! Hi, On 04.01.2016 17:42, Michael Tremer wrote: > is this still an issue? For me: definitely YES. > The nightly builds seem to build fine... I think this is because the nightly builds contain patches No. 001-29. The problems came up after I integrated patch No. 030-041, as shown below. Even the testrelease '2.76test2' wouldn't build (I haven't tested '276test3' yet, which came up a few hours ago). Can anyone confirm? Best, Matthias Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org> --- lfs/dnsmasq | 12 + ...q-Add-support-to-read-ISC-DHCP-lease-file.patch | 6 +- ...plit_EDNS0_stuff_into_its_own_source_file.patch | 777 ++++++++++++++++ .../031-Handle_extending_EDNS0_OPT_RR.patch | 295 +++++++ ..._512_bytes_that_the_client_isnt_expecting.patch | 65 ++ ...ix_build_failure_when_DNSSEC_code_omitted.patch | 55 ++ ...go_with_DNSKEY_and_DS_also_digest_with_DS.patch | 81 ++ .../035-More_EDNS0_packet_size_tweaks.patch | 138 +++ ...036-Cache_access_to_the_kernels_ARP_table.patch | 414 +++++++++ ...DNS-client-id_EDNS0_and_ARP_tracking_code.patch | 976 +++++++++++++++++++++ ...38-Correct_logic_for_when_to_start_helper.patch | 25 + src/patches/dnsmasq/039-Trivial_code_tweak.patch | 33 + .../040-Extra_check_in_NSEC3_processing.patch | 60 ++ ...x_linked-list_botch_in_new_ARP-cache_code.patch | 55 ++ 14 files changed, 2989 insertions(+), 3 deletions(-) create mode 100644 src/patches/dnsmasq/030-Split_EDNS0_stuff_into_its_own_source_file.patch create mode 100644 src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch create mode 100644 src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting.patch create mode 100644 src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitted.patch create mode 100644 src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch create mode 100644 src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch create mode 100644 src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch create mode 100644 src/patches/dnsmasq/037-First_complete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch create mode 100644 src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.patch create mode 100644 src/patches/dnsmasq/039-Trivial_code_tweak.patch create mode 100644 src/patches/dnsmasq/040-Extra_check_in_NSEC3_processing.patch create mode 100644 src/patches/dnsmasq/041-Fix_linked-list_botch_in_new_ARP-cache_code.patch
Comments
On Mon, 2016-01-04 at 18:06 +0100, Matthias Fischer wrote: > Only for testing - this won't compile! > > Hi, > > On 04.01.2016 17:42, Michael Tremer wrote: > > is this still an issue? > > For me: definitely YES. > > > The nightly builds seem to build fine... > > I think this is because the nightly builds contain patches No. 001 > -29. > > The problems came up after I integrated patch No. 030-041, as shown > below. > > Even the testrelease '2.76test2' wouldn't build (I haven't tested > '276test3' yet, > which came up a few hours ago). > > Can anyone confirm? Yes I can confirm. It won't build. Best, -Michael > > Best, > Matthias > > Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org> > --- > lfs/dnsmasq | 12 + > ...q-Add-support-to-read-ISC-DHCP-lease-file.patch | 6 +- > ...plit_EDNS0_stuff_into_its_own_source_file.patch | 777 > ++++++++++++++++ > .../031-Handle_extending_EDNS0_OPT_RR.patch | 295 +++++++ > ..._512_bytes_that_the_client_isnt_expecting.patch | 65 ++ > ...ix_build_failure_when_DNSSEC_code_omitted.patch | 55 ++ > ...go_with_DNSKEY_and_DS_also_digest_with_DS.patch | 81 ++ > .../035-More_EDNS0_packet_size_tweaks.patch | 138 +++ > ...036-Cache_access_to_the_kernels_ARP_table.patch | 414 +++++++++ > ...DNS-client-id_EDNS0_and_ARP_tracking_code.patch | 976 > +++++++++++++++++++++ > ...38-Correct_logic_for_when_to_start_helper.patch | 25 + > src/patches/dnsmasq/039-Trivial_code_tweak.patch | 33 + > .../040-Extra_check_in_NSEC3_processing.patch | 60 ++ > ...x_linked-list_botch_in_new_ARP-cache_code.patch | 55 ++ > 14 files changed, 2989 insertions(+), 3 deletions(-) > create mode 100644 src/patches/dnsmasq/030 > -Split_EDNS0_stuff_into_its_own_source_file.patch > create mode 100644 src/patches/dnsmasq/031 > -Handle_extending_EDNS0_OPT_RR.patch > create mode 100644 src/patches/dnsmasq/032 > -Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting > .patch > create mode 100644 src/patches/dnsmasq/033 > -Fix_build_failure_when_DNSSEC_code_omitted.patch > create mode 100644 src/patches/dnsmasq/034 > -Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch > create mode 100644 src/patches/dnsmasq/035 > -More_EDNS0_packet_size_tweaks.patch > create mode 100644 src/patches/dnsmasq/036 > -Cache_access_to_the_kernels_ARP_table.patch > create mode 100644 src/patches/dnsmasq/037 > -First_complete_version_of_DNS-client > -id_EDNS0_and_ARP_tracking_code.patch > create mode 100644 src/patches/dnsmasq/038 > -Correct_logic_for_when_to_start_helper.patch > create mode 100644 src/patches/dnsmasq/039-Trivial_code_tweak.patch > create mode 100644 src/patches/dnsmasq/040 > -Extra_check_in_NSEC3_processing.patch > create mode 100644 src/patches/dnsmasq/041-Fix_linked > -list_botch_in_new_ARP-cache_code.patch > > diff --git a/lfs/dnsmasq b/lfs/dnsmasq > index 8058663..d12a54a 100644 > --- a/lfs/dnsmasq > +++ b/lfs/dnsmasq > @@ -102,6 +102,18 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) > cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by > -one_in_DNSSEC_hostname_cmp.patch > cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/028 > -Minor_tweak_to_previous_commit.patch > cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/030 > -Split_EDNS0_stuff_into_its_own_source_file.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/031 > -Handle_extending_EDNS0_OPT_RR.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/032 > -Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting > .patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/033 > -Fix_build_failure_when_DNSSEC_code_omitted.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/034 > -Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/035 > -More_EDNS0_packet_size_tweaks.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/036 > -Cache_access_to_the_kernels_ARP_table.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/037-First_complete_version_of_DNS > -client-id_EDNS0_and_ARP_tracking_code.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/038 > -Correct_logic_for_when_to_start_helper.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/039-Trivial_code_tweak.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/040 > -Extra_check_in_NSEC3_processing.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/041-Fix_linked-list_botch_in_new_ARP > -cache_code.patch > cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease > -file.patch > > cd $(DIR_APP) && sed -i src/config.h \ > diff --git a/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease > -file.patch b/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease > -file.patch > index f55ebe8..60514f1 100644 > --- a/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease > -file.patch > +++ b/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease > -file.patch > @@ -56,7 +56,7 @@ > > --- a/src/dnsmasq.h Wed Dec 16 19:24:12 2015 > +++ b/src/dnsmasq.h Wed Dec 16 19:40:11 2015 > -@@ -1513,8 +1513,12 @@ > +@@ -1509,6 +1509,11 @@ > void poll_listen(int fd, short event); > int do_poll(int timeout); > > @@ -341,8 +341,8 @@ > 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 > -+ poll.o rrfilter.o isc.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 > diff --git a/src/patches/dnsmasq/030 > -Split_EDNS0_stuff_into_its_own_source_file.patch > b/src/patches/dnsmasq/030 > -Split_EDNS0_stuff_into_its_own_source_file.patch > new file mode 100644 > index 0000000..0cef987 > --- /dev/null > +++ b/src/patches/dnsmasq/030 > -Split_EDNS0_stuff_into_its_own_source_file.patch > @@ -0,0 +1,777 @@ > +From 1d03016bbcb78962305cca20cbf7441423ff897d Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Mon, 21 Dec 2015 14:17:06 +0000 > +Subject: [PATCH] Split EDNS0 stuff into its own source file. > + > +--- > + Makefile | 2 +- > + bld/Android.mk | 2 +- > + src/dnsmasq.h | 17 +-- > + src/edns0.c | 351 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > + src/rfc1035.c | 334 --------------------------------------------- > -------- > + 5 files changed, 362 insertions(+), 344 deletions(-) > + create mode 100644 src/edns0.c > + > +diff --git a/Makefile b/Makefile > +index b664160..dfb0347 100644 > +--- a/Makefile > ++++ b/Makefile > +@@ -74,7 +74,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o > network.o \ > + helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ > + dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ > + domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \ > +- poll.o rrfilter.o > ++ poll.o rrfilter.o edns0.o > + > + hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ > + dns-protocol.h radv-protocol.h ip6addr.h > +diff --git a/bld/Android.mk b/bld/Android.mk > +index 67b9c4b..87966d2 100644 > +--- a/bld/Android.mk > ++++ b/bld/Android.mk > +@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c > dnsmasq.c \ > + dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ > + radv.c slaac.c auth.c ipset.c domain.c \ > + dnssec.c dnssec-openssl.c blockdata.c tables.c > \ > +- loop.c inotify.c poll.c rrfilter.c > ++ loop.c inotify.c poll.c rrfilter.c edns0.c > + > + LOCAL_MODULE := dnsmasq > + > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index abb34c5..a41c8cc 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -1123,14 +1123,6 @@ int check_for_local_domain(char *name, time_t > now); > + unsigned int questions_crc(struct dns_header *header, size_t plen, > char *buff); > + size_t resize_packet(struct dns_header *header, size_t plen, > + unsigned char *pheader, size_t hlen); > +-size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > +- unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do); > +-size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3); > +-size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source); > +-#ifdef HAVE_DNSSEC > +-size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit); > +-#endif > +-int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer); > + 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, ...); > +@@ -1521,3 +1513,12 @@ 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); > + > ++/* edns0.c */ > ++size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > ++ unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do); > ++size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3); > ++size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source); > ++#ifdef HAVE_DNSSEC > ++size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit); > ++#endif > ++int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer); > +diff --git a/src/edns0.c b/src/edns0.c > +new file mode 100644 > +index 0000000..f348b01 > +--- /dev/null > ++++ b/src/edns0.c > +@@ -0,0 +1,351 @@ > ++/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley > ++ > ++ This program is free software; you can redistribute it and/or > modify > ++ it under the terms of the GNU General Public License as > published by > ++ the Free Software Foundation; version 2 dated June, 1991, or > ++ (at your option) version 3 dated 29 June, 2007. > ++ > ++ This program is distributed in the hope that it will be useful, > ++ but WITHOUT ANY WARRANTY; without even the implied warranty of > ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > ++ GNU General Public License for more details. > ++ > ++ You should have received a copy of the GNU General Public > License > ++ along with this program. If not, see < > http://www.gnu.org/licenses/>. > ++*/ > ++ > ++#include "dnsmasq.h" > ++ > ++unsigned char *find_pseudoheader(struct dns_header *header, size_t > plen, size_t *len, unsigned char **p, int *is_sign) > ++{ > ++ /* See if packet has an RFC2671 pseudoheader, and if so return a > pointer to it. > ++ also return length of pseudoheader in *len and pointer to the > UDP size in *p > ++ Finally, check to see if a packet is signed. If it is we > cannot change a single bit before > ++ forwarding. We look for SIG and TSIG in the addition section, > and TKEY queries (for GSS-TSIG) */ > ++ > ++ int i, arcount = ntohs(header->arcount); > ++ unsigned char *ansp = (unsigned char *)(header+1); > ++ unsigned short rdlen, type, class; > ++ unsigned char *ret = NULL; > ++ > ++ if (is_sign) > ++ { > ++ *is_sign = 0; > ++ > ++ if (OPCODE(header) == QUERY) > ++ { > ++ for (i = ntohs(header->qdcount); i != 0; i--) > ++ { > ++ if (!(ansp = skip_name(ansp, header, plen, 4))) > ++ return NULL; > ++ > ++ GETSHORT(type, ansp); > ++ GETSHORT(class, ansp); > ++ > ++ if (class == C_IN && type == T_TKEY) > ++ *is_sign = 1; > ++ } > ++ } > ++ } > ++ else > ++ { > ++ if (!(ansp = skip_questions(header, plen))) > ++ return NULL; > ++ } > ++ > ++ if (arcount == 0) > ++ return NULL; > ++ > ++ if (!(ansp = skip_section(ansp, ntohs(header->ancount) + > ntohs(header->nscount), header, plen))) > ++ return NULL; > ++ > ++ for (i = 0; i < arcount; i++) > ++ { > ++ unsigned char *save, *start = ansp; > ++ if (!(ansp = skip_name(ansp, header, plen, 10))) > ++ return NULL; > ++ > ++ GETSHORT(type, ansp); > ++ save = ansp; > ++ GETSHORT(class, ansp); > ++ ansp += 4; /* TTL */ > ++ GETSHORT(rdlen, ansp); > ++ if (!ADD_RDLEN(header, ansp, plen, rdlen)) > ++ return NULL; > ++ if (type == T_OPT) > ++ { > ++ if (len) > ++ *len = ansp - start; > ++ if (p) > ++ *p = save; > ++ ret = start; > ++ } > ++ else if (is_sign && > ++ i == arcount - 1 && > ++ class == C_ANY && > ++ type == T_TSIG) > ++ *is_sign = 1; > ++ } > ++ > ++ return ret; > ++} > ++ > ++struct macparm { > ++ unsigned char *limit; > ++ struct dns_header *header; > ++ size_t plen; > ++ union mysockaddr *l3; > ++}; > ++ > ++size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > ++ unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do) > ++{ > ++ unsigned char *lenp, *datap, *p; > ++ int rdlen, is_sign; > ++ > ++ if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign))) > ++ { > ++ if (is_sign) > ++ return plen; > ++ > ++ /* We are adding the pseudoheader */ > ++ if (!(p = skip_questions(header, plen)) || > ++ !(p = skip_section(p, > ++ ntohs(header->ancount) + ntohs(header > ->nscount) + ntohs(header->arcount), > ++ header, plen))) > ++ return plen; > ++ *p++ = 0; /* empty name */ > ++ PUTSHORT(T_OPT, p); > ++ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given > in EDNS0 header */ > ++ PUTSHORT(0, p); /* extended RCODE and version */ > ++ PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ > ++ lenp = p; > ++ PUTSHORT(0, p); /* RDLEN */ > ++ rdlen = 0; > ++ if (((ssize_t)optlen) > (limit - (p + 4))) > ++ return plen; /* Too big */ > ++ header->arcount = htons(ntohs(header->arcount) + 1); > ++ datap = p; > ++ } > ++ else > ++ { > ++ int i; > ++ unsigned short code, len, flags; > ++ > ++ /* Must be at the end, if exists */ > ++ if (ntohs(header->arcount) != 1 || > ++ is_sign || > ++ (!(p = skip_name(p, header, plen, 10)))) > ++ return plen; > ++ > ++ p += 6; /* skip UDP length and RCODE */ > ++ GETSHORT(flags, p); > ++ if (set_do) > ++ { > ++ p -=2; > ++ PUTSHORT(flags | 0x8000, p); > ++ } > ++ > ++ lenp = p; > ++ GETSHORT(rdlen, p); > ++ if (!CHECK_LEN(header, p, plen, rdlen)) > ++ return plen; /* bad packet */ > ++ datap = p; > ++ > ++ /* no option to add */ > ++ if (optno == 0) > ++ return plen; > ++ > ++ /* check if option already there */ > ++ for (i = 0; i + 4 < rdlen; i += len + 4) > ++ { > ++ GETSHORT(code, p); > ++ GETSHORT(len, p); > ++ if (code == optno) > ++ return plen; > ++ p += len; > ++ } > ++ > ++ if (((ssize_t)optlen) > (limit - (p + 4))) > ++ return plen; /* Too big */ > ++ } > ++ > ++ if (optno != 0) > ++ { > ++ PUTSHORT(optno, p); > ++ PUTSHORT(optlen, p); > ++ memcpy(p, opt, optlen); > ++ p += optlen; > ++ } > ++ > ++ PUTSHORT(p - datap, lenp); > ++ return p - (unsigned char *)header; > ++ > ++} > ++ > ++static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > ++{ > ++ struct macparm *parm = parmv; > ++ int match = 0; > ++ > ++ if (family == parm->l3->sa.sa_family) > ++ { > ++ if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, > addrp, INADDRSZ) == 0) > ++ match = 1; > ++#ifdef HAVE_IPV6 > ++ else > ++ if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, > addrp, IN6ADDRSZ) == 0) > ++ match = 1; > ++#endif > ++ } > ++ > ++ if (!match) > ++ return 1; /* continue */ > ++ > ++ parm->plen = add_pseudoheader(parm->header, parm->plen, parm > ->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, > 0); > ++ > ++ return 0; /* done */ > ++} > ++ > ++size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3) > ++{ > ++ struct macparm parm; > ++ > ++ parm.header = header; > ++ parm.limit = (unsigned char *)limit; > ++ parm.plen = plen; > ++ parm.l3 = l3; > ++ > ++ iface_enumerate(AF_UNSPEC, &parm, filter_mac); > ++ > ++ return parm.plen; > ++} > ++ > ++struct subnet_opt { > ++ u16 family; > ++ u8 source_netmask, scope_netmask; > ++#ifdef HAVE_IPV6 > ++ u8 addr[IN6ADDRSZ]; > ++#else > ++ u8 addr[INADDRSZ]; > ++#endif > ++}; > ++ > ++static void *get_addrp(union mysockaddr *addr, const short family) > ++{ > ++#ifdef HAVE_IPV6 > ++ if (family == AF_INET6) > ++ return &addr->in6.sin6_addr; > ++#endif > ++ > ++ return &addr->in.sin_addr; > ++} > ++ > ++static size_t calc_subnet_opt(struct subnet_opt *opt, union > mysockaddr *source) > ++{ > ++ /* > http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ > ++ > ++ int len; > ++ void *addrp; > ++ int sa_family = source->sa.sa_family; > ++ > ++#ifdef HAVE_IPV6 > ++ if (source->sa.sa_family == AF_INET6) > ++ { > ++ opt->source_netmask = daemon->add_subnet6->mask; > ++ if (daemon->add_subnet6->addr_used) > ++ { > ++ sa_family = daemon->add_subnet6->addr.sa.sa_family; > ++ addrp = get_addrp(&daemon->add_subnet6->addr, sa_family); > ++ } > ++ else > ++ addrp = &source->in6.sin6_addr; > ++ } > ++ else > ++#endif > ++ { > ++ opt->source_netmask = daemon->add_subnet4->mask; > ++ if (daemon->add_subnet4->addr_used) > ++ { > ++ sa_family = daemon->add_subnet4->addr.sa.sa_family; > ++ addrp = get_addrp(&daemon->add_subnet4->addr, sa_family); > ++ } > ++ else > ++ addrp = &source->in.sin_addr; > ++ } > ++ > ++ opt->scope_netmask = 0; > ++ len = 0; > ++ > ++ if (opt->source_netmask != 0) > ++ { > ++#ifdef HAVE_IPV6 > ++ opt->family = htons(sa_family == AF_INET6 ? 2 : 1); > ++#else > ++ opt->family = htons(1); > ++#endif > ++ len = ((opt->source_netmask - 1) >> 3) + 1; > ++ memcpy(opt->addr, addrp, len); > ++ if (opt->source_netmask & 7) > ++ opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & > 7)); > ++ } > ++ > ++ return len + 4; > ++} > ++ > ++size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source) > ++{ > ++ /* > http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ > ++ > ++ int len; > ++ struct subnet_opt opt; > ++ > ++ len = calc_subnet_opt(&opt, source); > ++ return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > ++} > ++ > ++#ifdef HAVE_DNSSEC > ++size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > ++{ > ++ return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > ++} > ++#endif > ++ > ++int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer) > ++{ > ++ /* Section 9.2, Check that subnet option in reply matches. */ > ++ > ++ > ++ int len, calc_len; > ++ struct subnet_opt opt; > ++ unsigned char *p; > ++ int code, i, rdlen; > ++ > ++ calc_len = calc_subnet_opt(&opt, peer); > ++ > ++ if (!(p = skip_name(pseudoheader, header, plen, 10))) > ++ return 1; > ++ > ++ p += 8; /* skip UDP length and RCODE */ > ++ > ++ GETSHORT(rdlen, p); > ++ if (!CHECK_LEN(header, p, plen, rdlen)) > ++ return 1; /* bad packet */ > ++ > ++ /* check if option there */ > ++ for (i = 0; i + 4 < rdlen; i += len + 4) > ++ { > ++ GETSHORT(code, p); > ++ GETSHORT(len, p); > ++ if (code == EDNS0_OPTION_CLIENT_SUBNET) > ++ { > ++ /* make sure this doesn't mismatch. */ > ++ opt.scope_netmask = p[3]; > ++ if (len != calc_len || memcmp(p, &opt, len) != 0) > ++ return 0; > ++ } > ++ p += len; > ++ } > ++ > ++ return 1; > ++} > +diff --git a/src/rfc1035.c b/src/rfc1035.c > +index 18858a8..5d89287 100644 > +--- a/src/rfc1035.c > ++++ b/src/rfc1035.c > +@@ -408,340 +408,6 @@ size_t resize_packet(struct dns_header > *header, size_t plen, unsigned char *phea > + return ansp - (unsigned char *)header; > + } > + > +-unsigned char *find_pseudoheader(struct dns_header *header, size_t > plen, size_t *len, unsigned char **p, int *is_sign) > +-{ > +- /* See if packet has an RFC2671 pseudoheader, and if so return a > pointer to it. > +- also return length of pseudoheader in *len and pointer to the > UDP size in *p > +- Finally, check to see if a packet is signed. If it is we > cannot change a single bit before > +- forwarding. We look for SIG and TSIG in the addition section, > and TKEY queries (for GSS-TSIG) */ > +- > +- int i, arcount = ntohs(header->arcount); > +- unsigned char *ansp = (unsigned char *)(header+1); > +- unsigned short rdlen, type, class; > +- unsigned char *ret = NULL; > +- > +- if (is_sign) > +- { > +- *is_sign = 0; > +- > +- if (OPCODE(header) == QUERY) > +- { > +- for (i = ntohs(header->qdcount); i != 0; i--) > +- { > +- if (!(ansp = skip_name(ansp, header, plen, 4))) > +- return NULL; > +- > +- GETSHORT(type, ansp); > +- GETSHORT(class, ansp); > +- > +- if (class == C_IN && type == T_TKEY) > +- *is_sign = 1; > +- } > +- } > +- } > +- else > +- { > +- if (!(ansp = skip_questions(header, plen))) > +- return NULL; > +- } > +- > +- if (arcount == 0) > +- return NULL; > +- > +- if (!(ansp = skip_section(ansp, ntohs(header->ancount) + > ntohs(header->nscount), header, plen))) > +- return NULL; > +- > +- for (i = 0; i < arcount; i++) > +- { > +- unsigned char *save, *start = ansp; > +- if (!(ansp = skip_name(ansp, header, plen, 10))) > +- return NULL; > +- > +- GETSHORT(type, ansp); > +- save = ansp; > +- GETSHORT(class, ansp); > +- ansp += 4; /* TTL */ > +- GETSHORT(rdlen, ansp); > +- if (!ADD_RDLEN(header, ansp, plen, rdlen)) > +- return NULL; > +- if (type == T_OPT) > +- { > +- if (len) > +- *len = ansp - start; > +- if (p) > +- *p = save; > +- ret = start; > +- } > +- else if (is_sign && > +- i == arcount - 1 && > +- class == C_ANY && > +- type == T_TSIG) > +- *is_sign = 1; > +- } > +- > +- return ret; > +-} > +- > +-struct macparm { > +- unsigned char *limit; > +- struct dns_header *header; > +- size_t plen; > +- union mysockaddr *l3; > +-}; > +- > +-size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > +- unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do) > +-{ > +- unsigned char *lenp, *datap, *p; > +- int rdlen, is_sign; > +- > +- if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign))) > +- { > +- if (is_sign) > +- return plen; > +- > +- /* We are adding the pseudoheader */ > +- if (!(p = skip_questions(header, plen)) || > +- !(p = skip_section(p, > +- ntohs(header->ancount) + ntohs(header > ->nscount) + ntohs(header->arcount), > +- header, plen))) > +- return plen; > +- *p++ = 0; /* empty name */ > +- PUTSHORT(T_OPT, p); > +- PUTSHORT(udp_sz, p); /* max packet length, 512 if not given > in EDNS0 header */ > +- PUTSHORT(0, p); /* extended RCODE and version */ > +- PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ > +- lenp = p; > +- PUTSHORT(0, p); /* RDLEN */ > +- rdlen = 0; > +- if (((ssize_t)optlen) > (limit - (p + 4))) > +- return plen; /* Too big */ > +- header->arcount = htons(ntohs(header->arcount) + 1); > +- datap = p; > +- } > +- else > +- { > +- int i; > +- unsigned short code, len, flags; > +- > +- /* Must be at the end, if exists */ > +- if (ntohs(header->arcount) != 1 || > +- is_sign || > +- (!(p = skip_name(p, header, plen, 10)))) > +- return plen; > +- > +- p += 6; /* skip UDP length and RCODE */ > +- GETSHORT(flags, p); > +- if (set_do) > +- { > +- p -=2; > +- PUTSHORT(flags | 0x8000, p); > +- } > +- > +- lenp = p; > +- GETSHORT(rdlen, p); > +- if (!CHECK_LEN(header, p, plen, rdlen)) > +- return plen; /* bad packet */ > +- datap = p; > +- > +- /* no option to add */ > +- if (optno == 0) > +- return plen; > +- > +- /* check if option already there */ > +- for (i = 0; i + 4 < rdlen; i += len + 4) > +- { > +- GETSHORT(code, p); > +- GETSHORT(len, p); > +- if (code == optno) > +- return plen; > +- p += len; > +- } > +- > +- if (((ssize_t)optlen) > (limit - (p + 4))) > +- return plen; /* Too big */ > +- } > +- > +- if (optno != 0) > +- { > +- PUTSHORT(optno, p); > +- PUTSHORT(optlen, p); > +- memcpy(p, opt, optlen); > +- p += optlen; > +- } > +- > +- PUTSHORT(p - datap, lenp); > +- return p - (unsigned char *)header; > +- > +-} > +- > +-static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > +-{ > +- struct macparm *parm = parmv; > +- int match = 0; > +- > +- if (family == parm->l3->sa.sa_family) > +- { > +- if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, > addrp, INADDRSZ) == 0) > +- match = 1; > +-#ifdef HAVE_IPV6 > +- else > +- if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, > addrp, IN6ADDRSZ) == 0) > +- match = 1; > +-#endif > +- } > +- > +- if (!match) > +- return 1; /* continue */ > +- > +- parm->plen = add_pseudoheader(parm->header, parm->plen, parm > ->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, > 0); > +- > +- return 0; /* done */ > +-} > +- > +-size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3) > +-{ > +- struct macparm parm; > +- > +- parm.header = header; > +- parm.limit = (unsigned char *)limit; > +- parm.plen = plen; > +- parm.l3 = l3; > +- > +- iface_enumerate(AF_UNSPEC, &parm, filter_mac); > +- > +- return parm.plen; > +-} > +- > +-struct subnet_opt { > +- u16 family; > +- u8 source_netmask, scope_netmask; > +-#ifdef HAVE_IPV6 > +- u8 addr[IN6ADDRSZ]; > +-#else > +- u8 addr[INADDRSZ]; > +-#endif > +-}; > +- > +-static void *get_addrp(union mysockaddr *addr, const short family) > +-{ > +-#ifdef HAVE_IPV6 > +- if (family == AF_INET6) > +- return &addr->in6.sin6_addr; > +-#endif > +- > +- return &addr->in.sin_addr; > +-} > +- > +-static size_t calc_subnet_opt(struct subnet_opt *opt, union > mysockaddr *source) > +-{ > +- /* > http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ > +- > +- int len; > +- void *addrp; > +- int sa_family = source->sa.sa_family; > +- > +-#ifdef HAVE_IPV6 > +- if (source->sa.sa_family == AF_INET6) > +- { > +- opt->source_netmask = daemon->add_subnet6->mask; > +- if (daemon->add_subnet6->addr_used) > +- { > +- sa_family = daemon->add_subnet6->addr.sa.sa_family; > +- addrp = get_addrp(&daemon->add_subnet6->addr, sa_family); > +- } > +- else > +- addrp = &source->in6.sin6_addr; > +- } > +- else > +-#endif > +- { > +- opt->source_netmask = daemon->add_subnet4->mask; > +- if (daemon->add_subnet4->addr_used) > +- { > +- sa_family = daemon->add_subnet4->addr.sa.sa_family; > +- addrp = get_addrp(&daemon->add_subnet4->addr, sa_family); > +- } > +- else > +- addrp = &source->in.sin_addr; > +- } > +- > +- opt->scope_netmask = 0; > +- len = 0; > +- > +- if (opt->source_netmask != 0) > +- { > +-#ifdef HAVE_IPV6 > +- opt->family = htons(sa_family == AF_INET6 ? 2 : 1); > +-#else > +- opt->family = htons(1); > +-#endif > +- len = ((opt->source_netmask - 1) >> 3) + 1; > +- memcpy(opt->addr, addrp, len); > +- if (opt->source_netmask & 7) > +- opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & > 7)); > +- } > +- > +- return len + 4; > +-} > +- > +-size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source) > +-{ > +- /* > http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ > +- > +- int len; > +- struct subnet_opt opt; > +- > +- len = calc_subnet_opt(&opt, source); > +- return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > +-} > +- > +-#ifdef HAVE_DNSSEC > +-size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > +-{ > +- return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > +-} > +-#endif > +- > +-int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer) > +-{ > +- /* Section 9.2, Check that subnet option in reply matches. */ > +- > +- > +- int len, calc_len; > +- struct subnet_opt opt; > +- unsigned char *p; > +- int code, i, rdlen; > +- > +- calc_len = calc_subnet_opt(&opt, peer); > +- > +- if (!(p = skip_name(pseudoheader, header, plen, 10))) > +- return 1; > +- > +- p += 8; /* skip UDP length and RCODE */ > +- > +- GETSHORT(rdlen, p); > +- if (!CHECK_LEN(header, p, plen, rdlen)) > +- return 1; /* bad packet */ > +- > +- /* check if option there */ > +- for (i = 0; i + 4 < rdlen; i += len + 4) > +- { > +- GETSHORT(code, p); > +- GETSHORT(len, p); > +- if (code == EDNS0_OPTION_CLIENT_SUBNET) > +- { > +- /* make sure this doesn't mismatch. */ > +- opt.scope_netmask = p[3]; > +- if (len != calc_len || memcmp(p, &opt, len) != 0) > +- return 0; > +- } > +- p += len; > +- } > +- > +- return 1; > +-} > +- > + /* is addr in the non-globally-routed IP space? */ > + int private_net(struct in_addr addr, int ban_localhost) > + { > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/031 > -Handle_extending_EDNS0_OPT_RR.patch b/src/patches/dnsmasq/031 > -Handle_extending_EDNS0_OPT_RR.patch > new file mode 100644 > index 0000000..386ff69 > --- /dev/null > +++ b/src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch > @@ -0,0 +1,295 @@ > +From 5bb88f096363e66ac08e31761f850a1d5aa22244 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Mon, 21 Dec 2015 16:23:47 +0000 > +Subject: [PATCH] Handle extending EDNS0 OPT RR. > + > +--- > + src/dnsmasq.h | 4 +- > + src/dnssec.c | 2 +- > + src/edns0.c | 113 +++++++++++++++++++++++++++++++++++----------- > ----------- > + src/forward.c | 16 ++++---- > + 4 files changed, 80 insertions(+), 55 deletions(-) > + > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index a41c8cc..9828819 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -1117,8 +1117,6 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > + int check_for_bogus_wildcard(struct dns_header *header, size_t > qlen, char *name, > + struct bogus_addr *addr, time_t now); > + int check_for_ignored_address(struct dns_header *header, size_t > qlen, struct bogus_addr *baddr); > +-unsigned char *find_pseudoheader(struct dns_header *header, size_t > plen, > +- size_t *len, unsigned char **p, > int *is_sign); > + int check_for_local_domain(char *name, time_t now); > + unsigned int questions_crc(struct dns_header *header, size_t plen, > char *buff); > + size_t resize_packet(struct dns_header *header, size_t plen, > +@@ -1514,6 +1512,8 @@ u16 *rrfilter_desc(int type); > + int expand_workspace(unsigned char ***wkspc, int *szp, int new); > + > + /* edns0.c */ > ++unsigned char *find_pseudoheader(struct dns_header *header, size_t > plen, > ++ size_t *len, unsigned char **p, > int *is_sign, int *is_last); > + size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > + unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do); > + size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3); > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 486e422..e0b7f39 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -2206,7 +2206,7 @@ size_t dnssec_generate_query(struct dns_header > *header, char *end, char *name, i > + > + ret = add_do_bit(header, p - (unsigned char *)header, end); > + > +- if (find_pseudoheader(header, ret, NULL, &p, NULL)) > ++ if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL)) > + PUTSHORT(edns_pktsz, p); > + > + return ret; > +diff --git a/src/edns0.c b/src/edns0.c > +index f348b01..d1a11e7 100644 > +--- a/src/edns0.c > ++++ b/src/edns0.c > +@@ -16,12 +16,12 @@ > + > + #include "dnsmasq.h" > + > +-unsigned char *find_pseudoheader(struct dns_header *header, size_t > plen, size_t *len, unsigned char **p, int *is_sign) > ++unsigned char *find_pseudoheader(struct dns_header *header, size_t > plen, size_t *len, unsigned char **p, int *is_sign, int *is_last) > + { > + /* See if packet has an RFC2671 pseudoheader, and if so return a > pointer to it. > + also return length of pseudoheader in *len and pointer to the > UDP size in *p > + Finally, check to see if a packet is signed. If it is we > cannot change a single bit before > +- forwarding. We look for SIG and TSIG in the addition section, > and TKEY queries (for GSS-TSIG) */ > ++ forwarding. We look for TSIG in the addition section, and TKEY > queries (for GSS-TSIG) */ > + > + int i, arcount = ntohs(header->arcount); > + unsigned char *ansp = (unsigned char *)(header+1); > +@@ -76,8 +76,13 @@ unsigned char *find_pseudoheader(struct > dns_header *header, size_t plen, size_t > + { > + if (len) > + *len = ansp - start; > ++ > + if (p) > + *p = save; > ++ > ++ if (is_last) > ++ *is_last = (i == arcount-1); > ++ > + ret = start; > + } > + else if (is_sign && > +@@ -100,50 +105,31 @@ struct macparm { > + size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > + unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do) > + { > +- unsigned char *lenp, *datap, *p; > +- int rdlen, is_sign; > ++ unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL; > ++ int rdlen = 0, is_sign, is_last; > ++ unsigned short flags = set_do ? 0x8000 : 0, rcode = 0; > ++ > ++ p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, > &is_last); > + > +- if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign))) > +- { > +- if (is_sign) > +- return plen; > ++ if (is_sign) > ++ return plen; > + > +- /* We are adding the pseudoheader */ > +- if (!(p = skip_questions(header, plen)) || > +- !(p = skip_section(p, > +- ntohs(header->ancount) + ntohs(header > ->nscount) + ntohs(header->arcount), > +- header, plen))) > +- return plen; > +- *p++ = 0; /* empty name */ > +- PUTSHORT(T_OPT, p); > +- PUTSHORT(udp_sz, p); /* max packet length, 512 if not given > in EDNS0 header */ > +- PUTSHORT(0, p); /* extended RCODE and version */ > +- PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ > +- lenp = p; > +- PUTSHORT(0, p); /* RDLEN */ > +- rdlen = 0; > +- if (((ssize_t)optlen) > (limit - (p + 4))) > +- return plen; /* Too big */ > +- header->arcount = htons(ntohs(header->arcount) + 1); > +- datap = p; > +- } > +- else > ++ if (p) > + { > ++ /* Existing header */ > + int i; > +- unsigned short code, len, flags; > +- > +- /* Must be at the end, if exists */ > +- if (ntohs(header->arcount) != 1 || > +- is_sign || > +- (!(p = skip_name(p, header, plen, 10)))) > +- return plen; > +- > +- p += 6; /* skip UDP length and RCODE */ > ++ unsigned short code, len; > ++ > ++ p = udp_len; > ++ GETSHORT(udp_sz, p); > ++ GETSHORT(rcode, p); > + GETSHORT(flags, p); > ++ > + if (set_do) > + { > + p -=2; > +- PUTSHORT(flags | 0x8000, p); > ++ flags |= 0x8000; > ++ PUTSHORT(flags, p); > + } > + > + lenp = p; > +@@ -165,22 +151,61 @@ size_t add_pseudoheader(struct dns_header > *header, size_t plen, unsigned char *l > + return plen; > + p += len; > + } > +- > +- if (((ssize_t)optlen) > (limit - (p + 4))) > +- return plen; /* Too big */ > ++ > ++ /* If we're going to extend the RR, it has to be the last RR > in the packet */ > ++ if (!is_last) > ++ { > ++ /* First, take a copy of the options. */ > ++ if (rdlen != 0 && (buff = whine_malloc(rdlen))) > ++ memcpy(buff, datap, rdlen); > ++ > ++ /* now, delete OPT RR */ > ++ plen = rrfilter(header, plen, 0); > ++ > ++ /* Now, force addition of a new one */ > ++ p = NULL; > ++ } > ++ } > ++ > ++ if (!p) > ++ { > ++ /* We are (re)adding the pseudoheader */ > ++ if (!(p = skip_questions(header, plen)) || > ++ !(p = skip_section(p, > ++ ntohs(header->ancount) + ntohs(header > ->nscount) + ntohs(header->arcount), > ++ header, plen))) > ++ return plen; > ++ *p++ = 0; /* empty name */ > ++ PUTSHORT(T_OPT, p); > ++ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given > in EDNS0 header */ > ++ PUTSHORT(rcode, p); /* extended RCODE and version */ > ++ PUTSHORT(flags, p); /* DO flag */ > ++ lenp = p; > ++ PUTSHORT(rdlen, p); /* RDLEN */ > ++ datap = p; > ++ /* Copy back any options */ > ++ if (buff) > ++ { > ++ memcpy(p, buff, rdlen); > ++ free(buff); > ++ p += rdlen; > ++ } > ++ header->arcount = htons(ntohs(header->arcount) + 1); > + } > + > ++ if (((ssize_t)optlen) > (limit - (p + 4))) > ++ return plen; /* Too big */ > ++ > ++ /* Add new option */ > + if (optno != 0) > + { > + PUTSHORT(optno, p); > + PUTSHORT(optlen, p); > + memcpy(p, opt, optlen); > + p += optlen; > ++ PUTSHORT(p - datap, lenp); > + } > +- > +- PUTSHORT(p - datap, lenp); > + return p - (unsigned char *)header; > +- > + } > + > + static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > +diff --git a/src/forward.c b/src/forward.c > +index 041353c..2ca3c86 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -276,7 +276,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + blockdata_retrieve(forward->stash, forward->stash_len, > (void *)header); > + plen = forward->stash_len; > + > +- if (find_pseudoheader(header, plen, NULL, &pheader, > &is_sign) && !is_sign) > ++ if (find_pseudoheader(header, plen, NULL, &pheader, > &is_sign, NULL) && !is_sign) > + PUTSHORT(SAFE_PKTSZ, pheader); > + > + if (forward->sentto->addr.sa.sa_family == AF_INET) > +@@ -479,7 +479,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + } > + > + #ifdef HAVE_DNSSEC > +- if (option_bool(OPT_DNSSEC_VALID) && !do_bit) > ++ if (option_bool(OPT_DNSSEC_VALID) && (forward->flags > & FREC_ADDED_PHEADER)) > + { > + /* Difficult one here. If our client didn't send > EDNS0, we will have set the UDP > + packet size to 512. But that won't provide > space for the RRSIGS in many cases. > +@@ -489,7 +489,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + the truncated bit? */ > + unsigned char *pheader; > + int is_sign; > +- if (find_pseudoheader(header, plen, NULL, > &pheader, &is_sign)) > ++ if (find_pseudoheader(header, plen, NULL, > &pheader, &is_sign, NULL) && !is_sign) > + PUTSHORT(start->edns_pktsz, pheader); > + } > + #endif > +@@ -584,7 +584,7 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > + } > + #endif > + > +- if ((pheader = find_pseudoheader(header, n, &plen, &sizep, > &is_sign))) > ++ if ((pheader = find_pseudoheader(header, n, &plen, &sizep, > &is_sign, NULL))) > + { > + if (check_subnet && !check_source(header, plen, pheader, > query_source)) > + { > +@@ -779,7 +779,7 @@ void reply_query(int fd, int family, time_t now) > + int is_sign; > + > + /* recreate query from reply */ > +- pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, > &is_sign); > ++ pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, > &is_sign, NULL); > + if (!is_sign) > + { > + header->ancount = htons(0); > +@@ -1313,7 +1313,7 @@ void receive_query(struct listener *listen, > time_t now) > + #endif > + } > + > +- if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL)) > ++ if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, > NULL)) > + { > + unsigned short flags; > + > +@@ -1569,7 +1569,7 @@ unsigned char *tcp_request(int confd, time_t > now, > + > + do_bit = 0; > + > +- if (find_pseudoheader(header, (size_t)size, NULL, &pheader, > NULL)) > ++ if (find_pseudoheader(header, (size_t)size, NULL, &pheader, > NULL, NULL)) > + { > + unsigned short flags; > + > +@@ -1578,7 +1578,7 @@ unsigned char *tcp_request(int confd, time_t > now, > + GETSHORT(flags, pheader); > + > + if (flags & 0x8000) > +- do_bit = 1;/* do bit */ > ++ do_bit = 1; /* do bit */ > + } > + > + #ifdef HAVE_AUTH > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/032 > -Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting > .patch b/src/patches/dnsmasq/032 > -Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting > .patch > new file mode 100644 > index 0000000..df90a4d > --- /dev/null > +++ b/src/patches/dnsmasq/032 > -Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting > .patch > @@ -0,0 +1,65 @@ > +From 5aa5f0ff2f8227ed743feb089dee421f1ca69943 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Mon, 21 Dec 2015 17:20:35 +0000 > +Subject: [PATCH] Truncate DNS replies >512 bytes that the client > isn't > + expecting. > + > +--- > + src/edns0.c | 5 ++--- > + src/forward.c | 17 +++++++++++++++-- > + 2 files changed, 17 insertions(+), 5 deletions(-) > + > +diff --git a/src/edns0.c b/src/edns0.c > +index d1a11e7..e137992 100644 > +--- a/src/edns0.c > ++++ b/src/edns0.c > +@@ -339,9 +339,8 @@ size_t add_do_bit(struct dns_header *header, > size_t plen, char *limit) > + int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer) > + { > + /* Section 9.2, Check that subnet option in reply matches. */ > +- > +- > +- int len, calc_len; > ++ > ++ int len, calc_len; > + struct subnet_opt opt; > + unsigned char *p; > + int code, i, rdlen; > +diff --git a/src/forward.c b/src/forward.c > +index 2ca3c86..e1766b9 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -485,8 +485,8 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + packet size to 512. But that won't provide > space for the RRSIGS in many cases. > + The RRSIGS will be stripped out before the > answer goes back, so the packet should > + shrink again. So, if we added a do-bit, bump > the udp packet size to the value > +- known to be OK for this server. Maybe check > returned size after stripping and set > +- the truncated bit? */ > ++ known to be OK for this server. We check > returned size after stripping and set > ++ the truncated bit if it's still too big. */ > > + unsigned char *pheader; > + int is_sign; > + if (find_pseudoheader(header, plen, NULL, > &pheader, &is_sign, NULL) && !is_sign) > +@@ -1028,6 +1028,19 @@ void reply_query(int fd, int family, time_t > now) > + { > + header->id = htons(forward->orig_id); > + header->hb4 |= HB4_RA; /* recursion if available */ > ++#ifdef HAVE_DNSSEC > ++ /* We added an EDNSO header for the purpose of getting > DNSSEC RRs, and set the value of the UDP payload size > ++ greater than the no-EDNS0-implied 512 to have if space > for the RRSIGS. If, having stripped them and the EDNS0 > ++ header, the answer is still bigger than 512, truncate > it and mark it so. The client then retries with TCP. */ > ++ if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & > FREC_ADDED_PHEADER) && (nn > PACKETSZ)) > ++ { > ++ header->ancount = htons(0); > ++ header->nscount = htons(0); > ++ header->arcount = htons(0); > ++ header->hb3 |= HB3_TC; > ++ nn = resize_packet(header, nn, NULL, 0); > ++ } > ++#endif > + send_from(forward->fd, option_bool(OPT_NOWILD) || > option_bool (OPT_CLEVERBIND), daemon->packet, nn, > + &forward->source, &forward->dest, forward > ->iface); > + } > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/033 > -Fix_build_failure_when_DNSSEC_code_omitted.patch > b/src/patches/dnsmasq/033 > -Fix_build_failure_when_DNSSEC_code_omitted.patch > new file mode 100644 > index 0000000..eed613b > --- /dev/null > +++ b/src/patches/dnsmasq/033 > -Fix_build_failure_when_DNSSEC_code_omitted.patch > @@ -0,0 +1,55 @@ > +From efef497b890231ba9232d02e7bfaf8273f044622 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Mon, 21 Dec 2015 17:30:44 +0000 > +Subject: [PATCH] Fix build failure when DNSSEC code omitted. > + > +--- > + src/dnsmasq.h | 2 -- > + src/edns0.c | 12 +++++------- > + 2 files changed, 5 insertions(+), 9 deletions(-) > + > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 9828819..1286807 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -1518,7 +1518,5 @@ size_t add_pseudoheader(struct dns_header > *header, size_t plen, unsigned char *l > + unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do); > + size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3); > + size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source); > +-#ifdef HAVE_DNSSEC > + size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit); > +-#endif > + int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer); > +diff --git a/src/edns0.c b/src/edns0.c > +index e137992..f82ba1b 100644 > +--- a/src/edns0.c > ++++ b/src/edns0.c > +@@ -208,6 +208,11 @@ size_t add_pseudoheader(struct dns_header > *header, size_t plen, unsigned char *l > + return p - (unsigned char *)header; > + } > + > ++size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > ++{ > ++ return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > ++} > ++ > + static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > + { > + struct macparm *parm = parmv; > +@@ -329,13 +334,6 @@ size_t add_source_addr(struct dns_header > *header, size_t plen, char *limit, unio > + return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > + } > + > +-#ifdef HAVE_DNSSEC > +-size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > +-{ > +- return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > +-} > +-#endif > +- > + int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer) > + { > + /* Section 9.2, Check that subnet option in reply matches. */ > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/034 > -Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch > b/src/patches/dnsmasq/034 > -Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch > new file mode 100644 > index 0000000..5742d4b > --- /dev/null > +++ b/src/patches/dnsmasq/034 > -Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch > @@ -0,0 +1,81 @@ > +From 15379ea1f252d1f53c5d93ae970b22dedb233642 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Mon, 21 Dec 2015 18:31:55 +0000 > +Subject: [PATCH] Log signature algo with DNSKEY and DS, also digest > with DS. > + > +--- > + src/cache.c | 2 +- > + src/dnsmasq.h | 6 ++++-- > + src/dnssec.c | 15 +++++++++------ > + 3 files changed, 14 insertions(+), 9 deletions(-) > + > +diff --git a/src/cache.c b/src/cache.c > +index 51ba7cc..4da380a 100644 > +--- a/src/cache.c > ++++ b/src/cache.c > +@@ -1580,7 +1580,7 @@ void log_query(unsigned int flags, char *name, > struct all_addr *addr, char *arg) > + if (addr) > + { > + if (flags & F_KEYTAG) > +- sprintf(daemon->addrbuff, arg, addr->addr.keytag); > ++ sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr > ->addr.log.algo, addr->addr.log.digest); > + else > + { > + #ifdef HAVE_IPV6 > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 1286807..4503a2d 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -256,8 +256,10 @@ struct all_addr { > + struct in6_addr addr6; > + #endif > + /* for log_query */ > +- unsigned int keytag; > +- /* for cache_insert if RRSIG, DNSKEY, DS */ > ++ struct { > ++ unsigned short keytag, algo, digest; > ++ } log; > ++ /* for cache_insert of DNSKEY, DS */ > + struct { > + unsigned short class, type; > + } dnssec; > +diff --git a/src/dnssec.c b/src/dnssec.c > +index e0b7f39..ed2d3fe 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -1115,11 +1115,12 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > + } > + else > + { > +- a.addr.keytag = keytag; > ++ a.addr.log.keytag = keytag; > ++ a.addr.log.algo = algo; > + if (verify_func(algo)) > +- log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u"); > ++ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu"); > + else > +- log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)"); > ++ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)"); > + > + recp1->addr.key.keylen = rdlen - 4; > + recp1->addr.key.keydata = key; > +@@ -1241,11 +1242,13 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > + } > + else > + { > +- a.addr.keytag = keytag; > ++ a.addr.log.keytag = keytag; > ++ a.addr.log.algo = algo; > ++ a.addr.log.digest = digest; > + if (hash_find(ds_digest_name(digest)) && > verify_func(algo)) > +- log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u"); > ++ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu"); > + else > +- log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u (not supported)"); > ++ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not > supported)"); > + > + crecp->addr.ds.digest = digest; > + crecp->addr.ds.keydata = key; > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/035 > -More_EDNS0_packet_size_tweaks.patch b/src/patches/dnsmasq/035 > -More_EDNS0_packet_size_tweaks.patch > new file mode 100644 > index 0000000..5c8ebd7 > --- /dev/null > +++ b/src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch > @@ -0,0 +1,138 @@ > +From d3a8b39c7df2f0debf3b5f274a1c37a9e261f94e Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Wed, 23 Dec 2015 12:27:37 +0000 > +Subject: [PATCH] More EDNS0 packet-size tweaks. > + > +--- > + src/dnsmasq.c | 7 +++++-- > + src/dnsmasq.h | 8 +------- > + src/forward.c | 22 +++++++++++++++------- > + 3 files changed, 21 insertions(+), 16 deletions(-) > + > +diff --git a/src/dnsmasq.c b/src/dnsmasq.c > +index 81254f6..45761cc 100644 > +--- a/src/dnsmasq.c > ++++ b/src/dnsmasq.c > +@@ -91,8 +91,11 @@ int main (int argc, char **argv) > + if (daemon->edns_pktsz < PACKETSZ) > + daemon->edns_pktsz = PACKETSZ; > + > +- daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ? > +- daemon->edns_pktsz : DNSMASQ_PACKETSZ; > ++ /* Min buffer size: we check after adding each record, so there > must be > ++ memory for the largest packet, and the largest record so the > ++ min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000. > ++ This might be increased is EDNS packet size if greater than > the minimum. */ > ++ daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + > RRFIXEDSZ; > + daemon->packet = safe_malloc(daemon->packet_buff_sz); > + > + daemon->addrbuff = safe_malloc(ADDRSTRLEN); > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 4503a2d..1c94f2a 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -179,13 +179,6 @@ struct event_desc { > + #define EC_MISC 5 > + #define EC_INIT_OFFSET 10 > + > +-/* Min buffer size: we check after adding each record, so there > must be > +- memory for the largest packet, and the largest record so the > +- min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000. > +- This might be increased is EDNS packet size if greater than the > minimum. > +-*/ > +-#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ > +- > + /* Trust the compiler dead-code eliminator.... */ > + #define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) > : daemon->options2 & (1u << ((x) - 32))) > + > +@@ -594,6 +587,7 @@ struct hostsfile { > + #define FREC_DO_QUESTION 64 > + #define FREC_ADDED_PHEADER 128 > + #define FREC_TEST_PKTSZ 256 > ++#define FREC_HAS_EXTRADATA 512 > + > + #ifdef HAVE_DNSSEC > + #define HASH_SIZE 20 /* SHA-1 digest size */ > +diff --git a/src/forward.c b/src/forward.c > +index e1766b9..c0e4d9a 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -389,13 +389,14 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + { > + struct server *firstsentto = start; > + int forwarded = 0; > +- > ++ size_t edns0_len; > ++ > + /* If a query is retried, use the log_id for the retry when > logging the answer. */ > + forward->log_id = daemon->log_id; > + > + if (option_bool(OPT_ADD_MAC)) > + { > +- size_t new = add_mac(header, plen, ((char *) header) + > daemon->packet_buff_sz, &forward->source); > ++ size_t new = add_mac(header, plen, ((char *) header) + > PACKETSZ, &forward->source); > + if (new != plen) > + { > + plen = new; > +@@ -405,7 +406,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + > + if (option_bool(OPT_CLIENT_SUBNET)) > + { > +- size_t new = add_source_addr(header, plen, ((char *) > header) + daemon->packet_buff_sz, &forward->source); > ++ size_t new = add_source_addr(header, plen, ((char *) > header) + PACKETSZ, &forward->source); > + if (new != plen) > + { > + plen = new; > +@@ -416,7 +417,7 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + #ifdef HAVE_DNSSEC > + if (option_bool(OPT_DNSSEC_VALID)) > + { > +- size_t new = add_do_bit(header, plen, ((char *) header) + > daemon->packet_buff_sz); > ++ size_t new = add_do_bit(header, plen, ((char *) header) + > PACKETSZ); > + > + if (new != plen) > + forward->flags |= FREC_ADDED_PHEADER; > +@@ -430,6 +431,10 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + > + } > + #endif > ++ > ++ /* If we're sending an EDNS0 with any options, we can't > recreate the query from a reply. */ > ++ if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, > NULL) && edns0_len > 11) > ++ forward->flags |= FREC_HAS_EXTRADATA; > + > + while (1) > + { > +@@ -769,9 +774,12 @@ void reply_query(int fd, int family, time_t > now) > + check_for_ignored_address(header, n, daemon->ignore_addr)) > + return; > + > ++ /* Note: if we send extra options in the EDNS0 header, we can't > recreate > ++ the query from the reply. */ > + if (RCODE(header) == REFUSED && > + !option_bool(OPT_ORDER) && > +- forward->forwardall == 0) > ++ forward->forwardall == 0 && > ++ !(forward->flags & FREC_HAS_EXTRADATA)) > + /* for broken servers, attempt to send to another one. */ > + { > + unsigned char *pheader; > +@@ -919,13 +927,13 @@ void reply_query(int fd, int family, time_t > now) > + if (status == STAT_NEED_KEY) > + { > + new->flags |= FREC_DNSKEY_QUERY; > +- nn = dnssec_generate_query(header, ((char > *) header) + daemon->packet_buff_sz, > ++ nn = dnssec_generate_query(header, ((char > *) header) + server->edns_pktsz, > + daemon > ->keyname, forward->class, T_DNSKEY, &server->addr, server > ->edns_pktsz); > + } > + else > + { > + new->flags |= FREC_DS_QUERY; > +- nn = dnssec_generate_query(header,((char > *) header) + daemon->packet_buff_sz, > ++ nn = dnssec_generate_query(header,((char > *) header) + server->edns_pktsz, > + daemon > ->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz); > + } > + if ((hash = hash_questions(header, nn, daemon > ->namebuff))) > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/036 > -Cache_access_to_the_kernels_ARP_table.patch > b/src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch > new file mode 100644 > index 0000000..ec70419 > --- /dev/null > +++ b/src/patches/dnsmasq/036 > -Cache_access_to_the_kernels_ARP_table.patch > @@ -0,0 +1,414 @@ > +From 11867dc28c7bd7c8a509ee7c8c7438cd2bcc1770 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Wed, 23 Dec 2015 16:15:58 +0000 > +Subject: [PATCH] Cache access to the kernel's ARP table. > + > +--- > + Makefile | 2 +- > + bld/Android.mk | 2 +- > + src/arp.c | 201 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > + src/dhcp6.c | 54 ++++----------- > + src/dnsmasq.h | 4 ++ > + src/edns0.c | 37 ++--------- > + 6 files changed, 223 insertions(+), 77 deletions(-) > + create mode 100644 src/arp.c > + > +diff --git a/Makefile b/Makefile > +index dfb0347..41e368f 100644 > +--- a/Makefile > ++++ b/Makefile > +@@ -74,7 +74,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o > network.o \ > + helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ > + dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ > + domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \ > +- poll.o rrfilter.o edns0.o > ++ poll.o rrfilter.o edns0.o arp.o > + > + hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ > + dns-protocol.h radv-protocol.h ip6addr.h > +diff --git a/bld/Android.mk b/bld/Android.mk > +index 87966d2..eafef35 100644 > +--- a/bld/Android.mk > ++++ b/bld/Android.mk > +@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c > dnsmasq.c \ > + dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ > + radv.c slaac.c auth.c ipset.c domain.c \ > + dnssec.c dnssec-openssl.c blockdata.c tables.c > \ > +- loop.c inotify.c poll.c rrfilter.c edns0.c > ++ loop.c inotify.c poll.c rrfilter.c edns0.c > arp.c > + > + LOCAL_MODULE := dnsmasq > + > +diff --git a/src/arp.c b/src/arp.c > +new file mode 100644 > +index 0000000..b624dac > +--- /dev/null > ++++ b/src/arp.c > +@@ -0,0 +1,201 @@ > ++/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley > ++ > ++ This program is free software; you can redistribute it and/or > modify > ++ it under the terms of the GNU General Public License as > published by > ++ the Free Software Foundation; version 2 dated June, 1991, or > ++ (at your option) version 3 dated 29 June, 2007. > ++ > ++ This program is distributed in the hope that it will be useful, > ++ but WITHOUT ANY WARRANTY; without even the implied warranty of > ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > ++ GNU General Public License for more details. > ++ > ++ You should have received a copy of the GNU General Public > License > ++ along with this program. If not, see < > http://www.gnu.org/licenses/>. > ++*/ > ++ > ++#include "dnsmasq.h" > ++ > ++#define ARP_FREE 0 > ++#define ARP_FOUND 1 > ++#define ARP_NEW 2 > ++#define ARP_EMPTY 3 > ++ > ++struct arp_record { > ++ short hwlen, status; > ++ int family; > ++ unsigned char hwaddr[DHCP_CHADDR_MAX]; > ++ struct all_addr addr; > ++ struct arp_record *next; > ++}; > ++ > ++static struct arp_record *arps = NULL, *old = NULL; > ++ > ++static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > ++{ > ++ int match = 0; > ++ struct arp_record *arp; > ++ > ++ if (maclen > DHCP_CHADDR_MAX) > ++ return 1; > ++ > ++ /* Look for existing entry */ > ++ for (arp = arps; arp; arp = arp->next) > ++ { > ++ if (family != arp->family || arp->status == ARP_NEW) > ++ continue; > ++ > ++ if (family == AF_INET) > ++ { > ++ if (arp->addr.addr.addr4.s_addr != ((struct in_addr > *)addrp)->s_addr) > ++ continue; > ++ } > ++#ifdef HAVE_IPV6 > ++ else > ++ { > ++ if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct > in6_addr *)addrp)) > ++ continue; > ++ } > ++#endif > ++ > ++ if (arp->status != ARP_EMPTY && arp->hwlen == maclen && > memcmp(arp->hwaddr, mac, maclen) == 0) > ++ arp->status = ARP_FOUND; > ++ else > ++ { > ++ /* existing address, MAC changed or arrived new. */ > ++ arp->status = ARP_NEW; > ++ arp->hwlen = maclen; > ++ arp->family = family; > ++ memcpy(arp->hwaddr, mac, maclen); > ++ } > ++ > ++ break; > ++ } > ++ > ++ if (!arp) > ++ { > ++ /* New entry */ > ++ if (old) > ++ { > ++ arp = old; > ++ old = old->next; > ++ } > ++ else if (!(arp = whine_malloc(sizeof(struct arp_record)))) > ++ return 1; > ++ > ++ arp->next = arps; > ++ arps = arp; > ++ arp->status = ARP_NEW; > ++ arp->hwlen = maclen; > ++ arp->family = family; > ++ memcpy(arp->hwaddr, mac, maclen); > ++ if (family == AF_INET) > ++ arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp) > ->s_addr; > ++#ifdef HAVE_IPV6 > ++ else > ++ memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ); > ++#endif > ++ } > ++ > ++ return 1; > ++} > ++ > ++/* If in lazy mode, we cache absence of ARP entries. */ > ++int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy) > ++{ > ++ struct arp_record *arp, **up; > ++ int updated = 0; > ++ > ++ again: > ++ > ++ for (arp = arps; arp; arp = arp->next) > ++ { > ++ if (addr->sa.sa_family == arp->family) > ++ { > ++ if (arp->addr.addr.addr4.s_addr != addr > ->in.sin_addr.s_addr) > ++ continue; > ++ } > ++#ifdef HAVE_IPV6 > ++ else > ++ { > ++ if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr > ->in6.sin6_addr)) > ++ continue; > ++ } > ++#endif > ++ > ++ /* Only accept poitive entries unless in lazy mode. */ > ++ if (arp->status != ARP_EMPTY || lazy || updated) > ++ { > ++ if (mac && arp->hwlen != 0) > ++ memcpy(mac, arp->hwaddr, arp->hwlen); > ++ return arp->hwlen; > ++ } > ++ } > ++ > ++ /* Not found, try the kernel */ > ++ if (!updated) > ++ { > ++ updated = 1; > ++ > ++ /* Mark all non-negative entries */ > ++ for (arp = arps, up = &arps; arp; arp = arp->next) > ++ if (arp->status != ARP_EMPTY) > ++ arp->status = ARP_FREE; > ++ > ++ iface_enumerate(AF_UNSPEC, NULL, filter_mac); > ++ > ++ /* Remove all unconfirmed entries to old list, announce new > ones. */ > ++ for (arp = arps, up = &arps; arp; arp = arp->next) > ++ if (arp->status == ARP_FREE) > ++ { > ++ *up = arp->next; > ++ arp->next = old; > ++ old = arp; > ++ } > ++ else > ++ { > ++ up = &arp->next; > ++ if (arp->status == ARP_NEW) > ++ { > ++ char a[ADDRSTRLEN], m[ADDRSTRLEN]; > ++ union mysockaddr pa; > ++ pa.sa.sa_family = arp->family; > ++ pa.in.sin_addr.s_addr = arp > ->addr.addr.addr4.s_addr; > ++ prettyprint_addr(&pa, a); > ++ print_mac(m, arp->hwaddr, arp->hwlen); > ++ my_syslog(LOG_INFO, _("new arp: %s %s"), a, m); > ++ } > ++ } > ++ > ++ goto again; > ++ } > ++ > ++ /* record failure, so we don't consult the kernel each time > ++ we're asked for this address */ > ++ if (old) > ++ { > ++ arp = old; > ++ old = old->next; > ++ } > ++ else > ++ arp = whine_malloc(sizeof(struct arp_record)); > ++ > ++ if (arp) > ++ { > ++ arp->next = arps; > ++ arps = arp; > ++ arp->status = ARP_EMPTY; > ++ arp->family = addr->sa.sa_family; > ++ > ++ if (addr->sa.sa_family == AF_INET) > ++ arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr; > ++#ifdef HAVE_IPV6 > ++ else > ++ memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, > IN6ADDRSZ); > ++#endif > ++ } > ++ > ++ return 0; > ++} > ++ > ++ > +diff --git a/src/dhcp6.c b/src/dhcp6.c > +index 8286ff4..7b1a7c7 100644 > +--- a/src/dhcp6.c > ++++ b/src/dhcp6.c > +@@ -27,17 +27,10 @@ struct iface_param { > + int ind, addr_match; > + }; > + > +-struct mac_param { > +- struct in6_addr *target; > +- unsigned char *mac; > +- unsigned int maclen; > +-}; > +- > + > + static int complete_context6(struct in6_addr *local, int prefix, > + int scope, int if_index, int flags, > + unsigned int preferred, unsigned int > valid, void *vparam); > +-static int find_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv); > + static int make_duid1(int index, unsigned int type, char *mac, > size_t maclen, void *parm); > + > + void dhcp6_init(void) > +@@ -264,9 +257,8 @@ void get_client_mac(struct in6_addr *client, int > iface, unsigned char *mac, unsi > + find the sender. Repeat a few times in case of packet loss. */ > + > + struct neigh_packet neigh; > +- struct sockaddr_in6 addr; > +- struct mac_param mac_param; > +- int i; > ++ union mysockaddr addr; > ++ int i, maclen; > + > + neigh.type = ND_NEIGHBOR_SOLICIT; > + neigh.code = 0; > +@@ -277,55 +269,31 @@ void get_client_mac(struct in6_addr *client, > int iface, unsigned char *mac, unsi > + > + memset(&addr, 0, sizeof(addr)); > + #ifdef HAVE_SOCKADDR_SA_LEN > +- addr.sin6_len = sizeof(struct sockaddr_in6); > ++ addr.in6.sin6_len = sizeof(struct sockaddr_in6); > + #endif > +- addr.sin6_family = AF_INET6; > +- addr.sin6_port = htons(IPPROTO_ICMPV6); > +- addr.sin6_addr = *client; > +- addr.sin6_scope_id = iface; > +- > +- mac_param.target = client; > +- mac_param.maclen = 0; > +- mac_param.mac = mac; > ++ addr.in6.sin6_family = AF_INET6; > ++ addr.in6.sin6_port = htons(IPPROTO_ICMPV6); > ++ addr.in6.sin6_addr = *client; > ++ addr.in6.sin6_scope_id = iface; > + > + for (i = 0; i < 5; i++) > + { > + struct timespec ts; > + > +- iface_enumerate(AF_UNSPEC, &mac_param, find_mac); > +- > +- if (mac_param.maclen != 0) > ++ if ((maclen = find_mac(&addr, mac, 0)) != 0) > + break; > +- > +- sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct > sockaddr *)&addr, sizeof(addr)); > ++ > ++ sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, > sizeof(addr)); > + > + ts.tv_sec = 0; > + ts.tv_nsec = 100000000; /* 100ms */ > + nanosleep(&ts, NULL); > + } > + > +- *maclenp = mac_param.maclen; > ++ *maclenp = maclen; > + *mactypep = ARPHRD_ETHER; > + } > + > +-static int find_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > +-{ > +- struct mac_param *parm = parmv; > +- > +- if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, > (struct in6_addr *)addrp)) > +- { > +- if (maclen <= DHCP_CHADDR_MAX) > +- { > +- parm->maclen = maclen; > +- memcpy(parm->mac, mac, maclen); > +- } > +- > +- return 0; /* found, abort */ > +- } > +- > +- return 1; > +-} > +- > + static int complete_context6(struct in6_addr *local, int prefix, > + int scope, int if_index, int flags, > unsigned int preferred, > + unsigned int valid, void *vparam) > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 1c94f2a..4459594 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -1516,3 +1516,7 @@ size_t add_mac(struct dns_header *header, > size_t plen, char *limit, union mysock > + size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source); > + size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit); > + int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer); > ++ > ++/* arp.c */ > ++int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy); > ++ > +diff --git a/src/edns0.c b/src/edns0.c > +index f82ba1b..9d8c0b9 100644 > +--- a/src/edns0.c > ++++ b/src/edns0.c > +@@ -213,42 +213,15 @@ size_t add_do_bit(struct dns_header *header, > size_t plen, char *limit) > + return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > + } > + > +-static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > +-{ > +- struct macparm *parm = parmv; > +- int match = 0; > +- > +- if (family == parm->l3->sa.sa_family) > +- { > +- if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, > addrp, INADDRSZ) == 0) > +- match = 1; > +-#ifdef HAVE_IPV6 > +- else > +- if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, > addrp, IN6ADDRSZ) == 0) > +- match = 1; > +-#endif > +- } > +- > +- if (!match) > +- return 1; /* continue */ > +- > +- parm->plen = add_pseudoheader(parm->header, parm->plen, parm > ->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, > 0); > +- > +- return 0; /* done */ > +-} > +- > + size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3) > + { > +- struct macparm parm; > +- > +- parm.header = header; > +- parm.limit = (unsigned char *)limit; > +- parm.plen = plen; > +- parm.l3 = l3; > ++ int maclen; > ++ unsigned char mac[DHCP_CHADDR_MAX]; > + > +- iface_enumerate(AF_UNSPEC, &parm, filter_mac); > ++ if ((maclen = find_mac(l3, mac, 1)) != 0) > ++ plen = add_pseudoheader(header, plen, limit, PACKETSZ, > EDNS0_OPTION_MAC, mac, maclen, 0); > + > +- return parm.plen; > ++ return plen; > + } > + > + struct subnet_opt { > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/037-First_complete_version_of_DNS > -client-id_EDNS0_and_ARP_tracking_code.patch > b/src/patches/dnsmasq/037-First_complete_version_of_DNS-client > -id_EDNS0_and_ARP_tracking_code.patch > new file mode 100644 > index 0000000..c89984a > --- /dev/null > +++ b/src/patches/dnsmasq/037-First_complete_version_of_DNS-client > -id_EDNS0_and_ARP_tracking_code.patch > @@ -0,0 +1,976 @@ > +From 33702ab1f829789183cbaf6b1c39eee7ff15d744 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Mon, 28 Dec 2015 23:17:15 +0000 > +Subject: [PATCH] First complete version of DNS-client-id EDNS0 and > ARP > + tracking code. > + > +--- > + src/arp.c | 148 +++++++++++++++++++++++++++++++---------- > ----------- > + src/config.h | 2 +- > + src/dhcp6.c | 6 +-- > + src/dns-protocol.h | 2 + > + src/dnsmasq.c | 23 ++++---- > + src/dnsmasq.h | 25 +++++---- > + src/dnssec.c | 2 +- > + src/edns0.c | 72 ++++++++++++++++++++----- > + src/forward.c | 107 ++++++++++++++++++------------------- > + src/helper.c | 66 ++++++++++++++++++++--- > + src/option.c | 9 ++++ > + src/rfc3315.c | 7 +-- > + 12 files changed, 308 insertions(+), 161 deletions(-) > + > +diff --git a/src/arp.c b/src/arp.c > +index b624dac..f41cdec 100644 > +--- a/src/arp.c > ++++ b/src/arp.c > +@@ -16,26 +16,31 @@ > + > + #include "dnsmasq.h" > + > +-#define ARP_FREE 0 > +-#define ARP_FOUND 1 > +-#define ARP_NEW 2 > +-#define ARP_EMPTY 3 > ++/* Time between forced re-loads from kernel. */ > ++#define INTERVAL 90 > ++ > ++#define ARP_MARK 0 > ++#define ARP_FOUND 1 /* Confirmed */ > ++#define ARP_NEW 2 /* Newly created */ > ++#define ARP_EMPTY 3 /* No MAC addr */ > + > + struct arp_record { > +- short hwlen, status; > ++ unsigned short hwlen, status; > + int family; > + unsigned char hwaddr[DHCP_CHADDR_MAX]; > + struct all_addr addr; > + struct arp_record *next; > + }; > + > +-static struct arp_record *arps = NULL, *old = NULL; > ++static struct arp_record *arps = NULL, *old = NULL, *freelist = > NULL; > ++static time_t last = 0; > + > + static int filter_mac(int family, char *addrp, char *mac, size_t > maclen, void *parmv) > + { > +- int match = 0; > + struct arp_record *arp; > + > ++ (void)parmv; > ++ > + if (maclen > DHCP_CHADDR_MAX) > + return 1; > + > +@@ -58,16 +63,18 @@ static int filter_mac(int family, char *addrp, > char *mac, size_t maclen, void *p > + } > + #endif > + > +- if (arp->status != ARP_EMPTY && arp->hwlen == maclen && > memcmp(arp->hwaddr, mac, maclen) == 0) > +- arp->status = ARP_FOUND; > +- else > ++ if (arp->status == ARP_EMPTY) > + { > +- /* existing address, MAC changed or arrived new. */ > ++ /* existing address, was negative. */ > + arp->status = ARP_NEW; > + arp->hwlen = maclen; > +- arp->family = family; > + memcpy(arp->hwaddr, mac, maclen); > + } > ++ else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, > maclen) == 0) > ++ /* Existing entry matches - confirm. */ > ++ arp->status = ARP_FOUND; > ++ else > ++ continue; > + > + break; > + } > +@@ -75,10 +82,10 @@ static int filter_mac(int family, char *addrp, > char *mac, size_t maclen, void *p > + if (!arp) > + { > + /* New entry */ > +- if (old) > ++ if (freelist) > + { > +- arp = old; > +- old = old->next; > ++ arp = freelist; > ++ freelist = freelist->next; > + } > + else if (!(arp = whine_malloc(sizeof(struct arp_record)))) > + return 1; > +@@ -101,81 +108,72 @@ static int filter_mac(int family, char *addrp, > char *mac, size_t maclen, void *p > + } > + > + /* If in lazy mode, we cache absence of ARP entries. */ > +-int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy) > ++int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, > time_t now) > + { > + struct arp_record *arp, **up; > + int updated = 0; > + > + again: > + > +- for (arp = arps; arp; arp = arp->next) > +- { > +- if (addr->sa.sa_family == arp->family) > +- { > +- if (arp->addr.addr.addr4.s_addr != addr > ->in.sin_addr.s_addr) > +- continue; > +- } > ++ /* If the database is less then INTERVAL old, look in there */ > ++ if (difftime(now, last) < INTERVAL) > ++ for (arp = arps; arp; arp = arp->next) > ++ { > ++ if (addr->sa.sa_family == arp->family) > ++ { > ++ if (arp->addr.addr.addr4.s_addr != addr > ->in.sin_addr.s_addr) > ++ continue; > ++ } > + #ifdef HAVE_IPV6 > +- else > +- { > +- if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr > ->in6.sin6_addr)) > +- continue; > +- } > ++ else > ++ { > ++ if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr > ->in6.sin6_addr)) > ++ continue; > ++ } > + #endif > +- > +- /* Only accept poitive entries unless in lazy mode. */ > +- if (arp->status != ARP_EMPTY || lazy || updated) > +- { > +- if (mac && arp->hwlen != 0) > +- memcpy(mac, arp->hwaddr, arp->hwlen); > +- return arp->hwlen; > +- } > +- } > +- > ++ > ++ /* Only accept poitive entries unless in lazy mode. */ > ++ if (arp->status != ARP_EMPTY || lazy || updated) > ++ { > ++ if (mac && arp->hwlen != 0) > ++ memcpy(mac, arp->hwaddr, arp->hwlen); > ++ return arp->hwlen; > ++ } > ++ } > ++ > + /* Not found, try the kernel */ > + if (!updated) > + { > + updated = 1; > +- > ++ last = now; > ++ > + /* Mark all non-negative entries */ > + for (arp = arps, up = &arps; arp; arp = arp->next) > + if (arp->status != ARP_EMPTY) > +- arp->status = ARP_FREE; > ++ arp->status = ARP_MARK; > + > + iface_enumerate(AF_UNSPEC, NULL, filter_mac); > + > +- /* Remove all unconfirmed entries to old list, announce new > ones. */ > ++ /* Remove all unconfirmed entries to old list. */ > + for (arp = arps, up = &arps; arp; arp = arp->next) > +- if (arp->status == ARP_FREE) > ++ if (arp->status == ARP_MARK) > + { > + *up = arp->next; > + arp->next = old; > + old = arp; > + } > + else > +- { > +- up = &arp->next; > +- if (arp->status == ARP_NEW) > +- { > +- char a[ADDRSTRLEN], m[ADDRSTRLEN]; > +- union mysockaddr pa; > +- pa.sa.sa_family = arp->family; > +- pa.in.sin_addr.s_addr = arp > ->addr.addr.addr4.s_addr; > +- prettyprint_addr(&pa, a); > +- print_mac(m, arp->hwaddr, arp->hwlen); > +- my_syslog(LOG_INFO, _("new arp: %s %s"), a, m); > +- } > +- } > +- > ++ up = &arp->next; > ++ > + goto again; > + } > + > + /* record failure, so we don't consult the kernel each time > + we're asked for this address */ > +- if (old) > ++ if (freelist) > + { > +- arp = old; > +- old = old->next; > ++ arp = freelist; > ++ freelist = freelist->next; > + } > + else > + arp = whine_malloc(sizeof(struct arp_record)); > +@@ -198,4 +196,36 @@ int find_mac(union mysockaddr *addr, unsigned > char *mac, int lazy) > + return 0; > + } > + > ++int do_arp_script_run(void) > ++{ > ++ struct arp_record *arp; > ++ > ++ /* Notify any which went, then move to free list */ > ++ if (old) > ++ { > ++#ifdef HAVE_SCRIPT > ++ if (option_bool(OPT_DNS_CLIENT)) > ++ queue_arp(ACTION_ARP_OLD, old->hwaddr, old->hwlen, old > ->family, &old->addr); > ++#endif > ++ arp = old; > ++ old = arp->next; > ++ arp->next = freelist; > ++ freelist = arp; > ++ return 1; > ++ } > ++ > ++ for (arp = arps; arp; arp = arp->next) > ++ if (arp->status == ARP_NEW) > ++ { > ++#ifdef HAVE_SCRIPT > ++ if (option_bool(OPT_DNS_CLIENT)) > ++ queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp > ->family, &arp->addr); > ++#endif > ++ arp->status = ARP_FOUND; > ++ return 1; > ++ } > ++ > ++ return 0; > ++} > ++ > + > +diff --git a/src/config.h b/src/config.h > +index f75fe9d..309be6b 100644 > +--- a/src/config.h > ++++ b/src/config.h > +@@ -337,7 +337,7 @@ HAVE_SOCKADDR_SA_LEN > + #define HAVE_DHCP > + #endif > + > +-#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK) > ++#if defined(NO_SCRIPT) || defined(NO_FORK) > + #undef HAVE_SCRIPT > + #undef HAVE_LUASCRIPT > + #endif > +diff --git a/src/dhcp6.c b/src/dhcp6.c > +index 7b1a7c7..0e2e171 100644 > +--- a/src/dhcp6.c > ++++ b/src/dhcp6.c > +@@ -220,7 +220,7 @@ void dhcp6_packet(time_t now) > + inet_pton(AF_INET6, ALL_SERVERS, &all_servers); > + > + if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers)) > +- relay_upstream6(parm.relay, sz, &from.sin6_addr, > from.sin6_scope_id); > ++ relay_upstream6(parm.relay, sz, &from.sin6_addr, > from.sin6_scope_id, now); > + return; > + } > + > +@@ -250,7 +250,7 @@ void dhcp6_packet(time_t now) > + } > + } > + > +-void get_client_mac(struct in6_addr *client, int iface, unsigned > char *mac, unsigned int *maclenp, unsigned int *mactypep) > ++void get_client_mac(struct in6_addr *client, int iface, unsigned > char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now) > + { > + /* Recieving a packet from a host does not populate the neighbour > + cache, so we send a neighbour discovery request if we can't > +@@ -280,7 +280,7 @@ void get_client_mac(struct in6_addr *client, int > iface, unsigned char *mac, unsi > + { > + struct timespec ts; > + > +- if ((maclen = find_mac(&addr, mac, 0)) != 0) > ++ if ((maclen = find_mac(&addr, mac, 0, now)) != 0) > + break; > + > + sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, > sizeof(addr)); > +diff --git a/src/dns-protocol.h b/src/dns-protocol.h > +index 6cf5158..addfa9e 100644 > +--- a/src/dns-protocol.h > ++++ b/src/dns-protocol.h > +@@ -77,6 +77,8 @@ > + > + #define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary > assignment */ > + #define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */ > ++#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary > assignment */ > ++#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary > assignment */ > + > + struct dns_header { > + u16 id; > +diff --git a/src/dnsmasq.c b/src/dnsmasq.c > +index 45761cc..229693f 100644 > +--- a/src/dnsmasq.c > ++++ b/src/dnsmasq.c > +@@ -245,8 +245,11 @@ int main (int argc, char **argv) > + /* Note that order matters here, we must call lease_init before > + creating any file descriptors which shouldn't be leaked > + to the lease-script init process. We need to call common_init > +- before lease_init to allocate buffers it uses.*/ > +- if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || > daemon->relay6) > ++ before lease_init to allocate buffers it uses. > ++ The script subsystrm relies on DHCP buffers, hence the last > two > ++ conditions below. */ > ++ if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || > ++ daemon->relay6 || option_bool(OPT_TFTP) || > option_bool(OPT_ADD_MAC)) > + { > + dhcp_common_init(); > + if (daemon->dhcp || daemon->doing_dhcp6) > +@@ -553,8 +556,9 @@ int main (int argc, char **argv) > + /* if we are to run scripts, we need to fork a helper before > dropping root. */ > + daemon->helperfd = -1; > + #ifdef HAVE_SCRIPT > +- if ((daemon->dhcp || daemon->dhcp6) && (daemon > ->lease_change_command || daemon->luascript)) > +- daemon->helperfd = create_helper(pipewrite, err_pipe[1], > script_uid, script_gid, max_fd); > ++ if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || > option_bool(OPT_ADD_MAC)) && > ++ (daemon->lease_change_command || daemon->luascript)) > ++ daemon->helperfd = create_helper(pipewrite, err_pipe[1], > script_uid, script_gid, max_fd); > + #endif > + > + if (!option_bool(OPT_DEBUG) && getuid() == 0) > +@@ -914,9 +918,9 @@ int main (int argc, char **argv) > + > + poll_listen(piperead, POLLIN); > + > +-#ifdef HAVE_DHCP > +-# ifdef HAVE_SCRIPT > +- while (helper_buf_empty() && do_script_run(now)); > ++#ifdef HAVE_SCRIPT > ++ while (helper_buf_empty() && do_script_run(now)); > ++ while (helper_buf_empty() && do_arp_script_run()); > + > + # ifdef HAVE_TFTP > + while (helper_buf_empty() && do_tftp_script_run()); > +@@ -924,16 +928,17 @@ int main (int argc, char **argv) > + > + if (!helper_buf_empty()) > + poll_listen(daemon->helperfd, POLLOUT); > +-# else > ++#else > + /* need this for other side-effects */ > + while (do_script_run(now)); > ++ while (do_arp_script_run(now)); > + > + # ifdef HAVE_TFTP > + while (do_tftp_script_run()); > + # endif > + > +-# endif > + #endif > ++ > + > + /* must do this just before select(), when we know no > + more calls to my_syslog() can occur */ > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 4459594..fec0f8d 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -235,7 +235,8 @@ struct event_desc { > + #define OPT_LOOP_DETECT 50 > + #define OPT_EXTRALOG 51 > + #define OPT_TFTP_NO_FAIL 52 > +-#define OPT_LAST 53 > ++#define OPT_DNS_CLIENT 53 > ++#define OPT_LAST 54 > + > + /* 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. */ > +@@ -633,6 +634,8 @@ struct frec { > + #define ACTION_OLD 3 > + #define ACTION_ADD 4 > + #define ACTION_TFTP 5 > ++#define ACTION_ARP 6 > ++#define ACTION_ARP_OLD 7 > + > + #define LEASE_NEW 1 /* newly created */ > + #define LEASE_CHANGED 2 /* modified */ > +@@ -948,6 +951,7 @@ extern struct daemon { > + int cachesize, ftabsize; > + int port, query_port, min_port; > + unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, > max_cache_ttl, auth_ttl; > ++ char *dns_client_id; > + struct hostsfile *addn_hosts; > + struct dhcp_context *dhcp, *dhcp6; > + struct ra_interface *ra_interfaces; > +@@ -1135,7 +1139,7 @@ int in_zone(struct auth_zone *zone, char > *name, char **cut); > + #endif > + > + /* dnssec.c */ > +-size_t dnssec_generate_query(struct dns_header *header, char *end, > char *name, int class, int type, union mysockaddr *addr, int > edns_pktsz); > ++size_t dnssec_generate_query(struct dns_header *header, unsigned > char *end, char *name, int class, int type, union mysockaddr *addr, > int edns_pktsz); > + int dnssec_validate_by_ds(time_t now, struct dns_header *header, > size_t n, char *name, char *keyname, int class); > + int dnssec_validate_ds(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int class); > + int dnssec_validate_reply(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int *class, > +@@ -1372,6 +1376,8 @@ void queue_script(int action, struct > dhcp_lease *lease, > + #ifdef HAVE_TFTP > + void queue_tftp(off_t file_len, char *filename, union mysockaddr > *peer); > + #endif > ++void queue_arp(int action, unsigned char *mac, int maclen, > ++ int family, struct all_addr *addr); > + int helper_buf_empty(void); > + #endif > + > +@@ -1408,7 +1414,7 @@ struct dhcp_config > *config_find_by_address6(struct dhcp_config *configs, struct > + void make_duid(time_t now); > + void dhcp_construct_contexts(time_t now); > + void get_client_mac(struct in6_addr *client, int iface, unsigned > char *mac, > +- unsigned int *maclenp, unsigned int *mactypep); > ++ unsigned int *maclenp, unsigned int *mactypep, > time_t now); > + #endif > + > + /* rfc3315.c */ > +@@ -1416,7 +1422,8 @@ void get_client_mac(struct in6_addr *client, > int iface, unsigned char *mac, > + unsigned short dhcp6_reply(struct dhcp_context *context, int > interface, char *iface_name, > + struct in6_addr *fallback, struct > in6_addr *ll_addr, struct in6_addr *ula_addr, > + size_t sz, struct in6_addr *client_addr, > time_t now); > +-void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct > in6_addr *peer_address, u32 scope_id); > ++void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct > in6_addr *peer_address, > ++ u32 scope_id, time_t now); > + > + unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, > char *arrival_interface); > + #endif > +@@ -1512,11 +1519,11 @@ unsigned char *find_pseudoheader(struct > dns_header *header, size_t plen, > + size_t *len, unsigned char **p, > int *is_sign, int *is_last); > + size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > + unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do); > +-size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3); > +-size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source); > +-size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit); > ++size_t add_do_bit(struct dns_header *header, size_t plen, unsigned > char *limit); > ++size_t add_edns0_config(struct dns_header *header, size_t plen, > unsigned char *limit, > ++ union mysockaddr *source, time_t now, int > *check_subnet); > + int check_source(struct dns_header *header, size_t plen, unsigned > char *pseudoheader, union mysockaddr *peer); > + > + /* arp.c */ > +-int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy); > +- > ++int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, > time_t now); > ++int do_arp_script_run(void); > +diff --git a/src/dnssec.c b/src/dnssec.c > +index ed2d3fe..918a2dc 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -2173,7 +2173,7 @@ int dnskey_keytag(int alg, int flags, unsigned > char *key, int keylen) > + } > + } > + > +-size_t dnssec_generate_query(struct dns_header *header, char *end, > char *name, int class, > ++size_t dnssec_generate_query(struct dns_header *header, unsigned > char *end, char *name, int class, > + int type, union mysockaddr *addr, int > edns_pktsz) > + { > + unsigned char *p; > +diff --git a/src/edns0.c b/src/edns0.c > +index 9d8c0b9..12e0210 100644 > +--- a/src/edns0.c > ++++ b/src/edns0.c > +@@ -94,13 +94,6 @@ unsigned char *find_pseudoheader(struct > dns_header *header, size_t plen, size_t > + > + return ret; > + } > +- > +-struct macparm { > +- unsigned char *limit; > +- struct dns_header *header; > +- size_t plen; > +- union mysockaddr *l3; > +-}; > + > + size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > + unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do) > +@@ -208,19 +201,54 @@ size_t add_pseudoheader(struct dns_header > *header, size_t plen, unsigned char *l > + return p - (unsigned char *)header; > + } > + > +-size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > ++size_t add_do_bit(struct dns_header *header, size_t plen, unsigned > char *limit) > + { > + return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > + } > + > +-size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3) > ++static unsigned char char64(unsigned char c) > ++{ > ++ return > "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c > & 0x3f]; > ++} > ++ > ++static void encoder(unsigned char *in, char *out) > ++{ > ++ out[0] = char64(in[0]>>2); > ++ out[1] = char64((in[0]<<4) | (in[1]>>4)); > ++ out[2] = char64((in[1]<<2) | (in[2]>>6)); > ++ out[3] = char64(in[2]); > ++} > ++ > ++static size_t add_dns_client(struct dns_header *header, size_t > plen, unsigned char *limit, union mysockaddr *l3, time_t now) > + { > + int maclen; > + unsigned char mac[DHCP_CHADDR_MAX]; > ++ char encode[8]; /* handle 6 byte MACs */ > ++ > ++ if ((maclen = find_mac(l3, mac, 1, now)) == 6) > ++ { > ++ encoder(mac, encode); > ++ encoder(mac+3, encode+4); > ++ > ++ plen = add_pseudoheader(header, plen, limit, PACKETSZ, > EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, 8, 0); > ++ } > ++ > ++ if (daemon->dns_client_id) > ++ plen = add_pseudoheader(header, plen, limit, PACKETSZ, > EDNS0_OPTION_NOMCPEID, > ++ (unsigned char *)daemon->dns_client_id, > strlen(daemon->dns_client_id), 0); > ++ > ++ return plen; > ++} > ++ > + > +- if ((maclen = find_mac(l3, mac, 1)) != 0) > ++static size_t add_mac(struct dns_header *header, size_t plen, > unsigned char *limit, union mysockaddr *l3, time_t now) > ++{ > ++ int maclen; > ++ unsigned char mac[DHCP_CHADDR_MAX]; > ++ > ++ if ((maclen = find_mac(l3, mac, 1, now)) != 0) > + plen = add_pseudoheader(header, plen, limit, PACKETSZ, > EDNS0_OPTION_MAC, mac, maclen, 0); > +- > ++ > + return plen; > + } > + > +@@ -296,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt > *opt, union mysockaddr *source) > + return len + 4; > + } > + > +-size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source) > ++static size_t add_source_addr(struct dns_header *header, size_t > plen, unsigned char *limit, union mysockaddr *source) > + { > + /* > http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ > + > +@@ -344,3 +372,23 @@ int check_source(struct dns_header *header, > size_t plen, unsigned char *pseudohe > + > + return 1; > + } > ++ > ++size_t add_edns0_config(struct dns_header *header, size_t plen, > unsigned char *limit, > ++ union mysockaddr *source, time_t now, int > *check_subnet) > ++{ > ++ *check_subnet = 0; > ++ > ++ if (option_bool(OPT_ADD_MAC)) > ++ plen = add_mac(header, plen, limit, source, now); > ++ > ++ if (option_bool(OPT_DNS_CLIENT)) > ++ plen = add_dns_client(header, plen, limit, source, now); > ++ > ++ if (option_bool(OPT_CLIENT_SUBNET)) > ++ { > ++ plen = add_source_addr(header, plen, limit, source); > ++ *check_subnet = 1; > ++ } > ++ > ++ return plen; > ++} > +diff --git a/src/forward.c b/src/forward.c > +index c0e4d9a..911f46e 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -388,36 +388,27 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > + if (!flags && forward) > + { > + struct server *firstsentto = start; > +- int forwarded = 0; > ++ int subnet, forwarded = 0; > + size_t edns0_len; > + > + /* If a query is retried, use the log_id for the retry when > logging the answer. */ > + forward->log_id = daemon->log_id; > + > +- if (option_bool(OPT_ADD_MAC)) > +- { > +- size_t new = add_mac(header, plen, ((char *) header) + > PACKETSZ, &forward->source); > +- if (new != plen) > +- { > +- plen = new; > +- forward->flags |= FREC_ADDED_PHEADER; > +- } > +- } > +- > +- if (option_bool(OPT_CLIENT_SUBNET)) > ++ edns0_len = add_edns0_config(header, plen, ((unsigned char > *)header) + PACKETSZ, &forward->source, now, &subnet); > ++ > ++ if (edns0_len != plen) > + { > +- size_t new = add_source_addr(header, plen, ((char *) > header) + PACKETSZ, &forward->source); > +- if (new != plen) > +- { > +- plen = new; > +- forward->flags |= FREC_HAS_SUBNET | > FREC_ADDED_PHEADER; > +- } > ++ plen = edns0_len; > ++ forward->flags |= FREC_ADDED_PHEADER; > ++ > ++ if (subnet) > ++ forward->flags |= FREC_HAS_SUBNET; > + } > +- > ++ > + #ifdef HAVE_DNSSEC > + if (option_bool(OPT_DNSSEC_VALID)) > + { > +- size_t new = add_do_bit(header, plen, ((char *) header) + > PACKETSZ); > ++ size_t new = add_do_bit(header, plen, ((unsigned char *) > header) + PACKETSZ); > + > + if (new != plen) > + forward->flags |= FREC_ADDED_PHEADER; > +@@ -607,15 +598,30 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > + } > + else > + { > ++ unsigned short udpsz; > ++ > + /* If upstream is advertising a larger UDP packet > size > + than we allow, trim it so that we don't get > overlarge > + requests for the client. We can't do this for > signed packets. */ > +- unsigned short udpsz; > +- unsigned char *psave = sizep; > +- > + GETSHORT(udpsz, sizep); > + if (udpsz > daemon->edns_pktsz) > +- PUTSHORT(daemon->edns_pktsz, psave); > ++ { > ++ sizep -= 2; > ++ PUTSHORT(daemon->edns_pktsz, sizep); > ++ } > ++ > ++#ifdef HAVE_DNSSEC > ++ /* If the client didn't set the do bit, but we did, > reset it. */ > ++ if (option_bool(OPT_DNSSEC_VALID) && !do_bit) > ++ { > ++ unsigned short flags; > ++ sizep += 2; /* skip RCODE */ > ++ GETSHORT(flags, sizep); > ++ flags &= ~0x8000; > ++ sizep -= 2; > ++ PUTSHORT(flags, sizep); > ++ } > ++#endif > + } > + } > + } > +@@ -674,14 +680,11 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > + } > + > + #ifdef HAVE_DNSSEC > +- if (bogusanswer && !(header->hb4 & HB4_CD)) > ++ if (bogusanswer && !(header->hb4 & HB4_CD) && > !option_bool(OPT_DNSSEC_DEBUG)) > + { > +- if (!option_bool(OPT_DNSSEC_DEBUG)) > +- { > +- /* Bogus reply, turn into SERVFAIL */ > +- SET_RCODE(header, SERVFAIL); > +- munged = 1; > +- } > ++ /* Bogus reply, turn into SERVFAIL */ > ++ SET_RCODE(header, SERVFAIL); > ++ munged = 1; > + } > + > + if (option_bool(OPT_DNSSEC_VALID)) > +@@ -802,7 +805,7 @@ void reply_query(int fd, int family, time_t now) > + if (forward->flags |= FREC_AD_QUESTION) > + header->hb4 |= HB4_AD; > + if (forward->flags & FREC_DO_QUESTION) > +- add_do_bit(header, nn, (char *)pheader + plen); > ++ add_do_bit(header, nn, (unsigned char *)pheader + > plen); > + forward_query(-1, NULL, NULL, 0, header, nn, now, > forward, forward->flags & FREC_AD_QUESTION, forward->flags & > FREC_DO_QUESTION); > + return; > + } > +@@ -927,13 +930,13 @@ void reply_query(int fd, int family, time_t > now) > + if (status == STAT_NEED_KEY) > + { > + new->flags |= FREC_DNSKEY_QUERY; > +- nn = dnssec_generate_query(header, ((char > *) header) + server->edns_pktsz, > ++ nn = dnssec_generate_query(header, > ((unsigned char *) header) + server->edns_pktsz, > + daemon > ->keyname, forward->class, T_DNSKEY, &server->addr, server > ->edns_pktsz); > + } > + else > + { > + new->flags |= FREC_DS_QUERY; > +- nn = dnssec_generate_query(header,((char > *) header) + server->edns_pktsz, > ++ nn = > dnssec_generate_query(header,((unsigned char *) header) + server > ->edns_pktsz, > + daemon > ->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz); > + } > + if ((hash = hash_questions(header, nn, daemon > ->namebuff))) > +@@ -1434,7 +1437,7 @@ static int tcp_key_recurse(time_t now, int > status, struct dns_header *header, si > + break; > + } > + > +- m = dnssec_generate_query(new_header, ((char *) new_header) + > 65536, keyname, class, > ++ m = dnssec_generate_query(new_header, ((unsigned char *) > new_header) + 65536, keyname, class, > + new_status == STAT_NEED_KEY ? > T_DNSKEY : T_DS, &server->addr, server->edns_pktsz); > + > + *length = htons(m); > +@@ -1548,8 +1551,6 @@ unsigned char *tcp_request(int confd, time_t > now, > + daemon->log_display_id = ++daemon->log_id; > + daemon->log_source_addr = &peer_addr; > + > +- check_subnet = 0; > +- > + /* save state of "cd" flag in query */ > + if ((checking_disabled = header->hb4 & HB4_CD)) > + no_cache_dnssec = 1; > +@@ -1627,20 +1628,14 @@ unsigned char *tcp_request(int confd, time_t > now, > + struct all_addr *addrp = NULL; > + int type = 0; > + char *domain = NULL; > +- > +- if (option_bool(OPT_ADD_MAC)) > +- size = add_mac(header, size, ((char *) header) + > 65536, &peer_addr); > +- > +- if (option_bool(OPT_CLIENT_SUBNET)) > ++ size_t new_size = add_edns0_config(header, size, > ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet); > ++ > ++ if (size != new_size) > + { > +- size_t new = add_source_addr(header, size, ((char > *) header) + 65536, &peer_addr); > +- if (size != new) > +- { > +- size = new; > +- check_subnet = 1; > +- } > ++ added_pheader = 1; > ++ size = new_size; > + } > +- > ++ > + if (gotname) > + flags = search_servers(now, &addrp, gotname, daemon > ->namebuff, &type, &domain, &norebind); > + > +@@ -1715,20 +1710,20 @@ unsigned char *tcp_request(int confd, time_t > now, > + } > + > + #ifdef HAVE_DNSSEC > +- added_pheader = 0; > > + if (option_bool(OPT_DNSSEC_VALID)) > + { > +- size_t new_size = add_do_bit(header, > size, ((char *) header) + 65536); > ++ new_size = add_do_bit(header, size, > ((unsigned char *) header) + 65536); > ++ > ++ if (size != new_size) > ++ { > ++ added_pheader = 1; > ++ size = new_size; > ++ } > + > + /* For debugging, set Checking > Disabled, otherwise, have the upstream check too, > + this allows it to select auth > servers when one is returning bad data. */ > + if (option_bool(OPT_DNSSEC_DEBUG)) > + header->hb4 |= HB4_CD; > +- > +- if (size != new_size) > +- added_pheader = 1; > +- > +- size = new_size; > + } > + #endif > + } > +diff --git a/src/helper.c b/src/helper.c > +index 1fee72d..517cfd9 100644 > +--- a/src/helper.c > ++++ b/src/helper.c > +@@ -219,7 +219,18 @@ int create_helper(int event_fd, int err_fd, > uid_t uid, gid_t gid, long max_fd) > + action_str = "tftp"; > + is6 = (data.flags != AF_INET); > + } > +- else > ++ else if (data.action == ACTION_ARP) > ++ { > ++ action_str = "arp"; > ++ is6 = (data.flags != AF_INET); > ++ } > ++ else if (data.action == ACTION_ARP_OLD) > ++ { > ++ action_str = "arp-old"; > ++ is6 = (data.flags != AF_INET); > ++ data.action = ACTION_ARP; > ++ } > ++ else > + continue; > + > + > +@@ -321,6 +332,22 @@ int create_helper(int event_fd, int err_fd, > uid_t uid, gid_t gid, long max_fd) > + lua_call(lua, 2, 0); /* pass 2 values, > expect 0 */ > + } > + } > ++ else if (data.action == ACTION_ARP) > ++ { > ++ lua_getglobal(lua, "arp"); > ++ if (lua_type(lua, -1) != LUA_TFUNCTION) > ++ lua_pop(lua, 1); /* arp function optional */ > ++ else > ++ { > ++ lua_pushstring(lua, action_str); /* arg1 - action > */ > ++ lua_newtable(lua); /* arg2 - data > table */ > ++ lua_pushstring(lua, daemon->addrbuff); > ++ lua_setfield(lua, -2, "client_address"); > ++ lua_pushstring(lua, daemon->dhcp_buff); > ++ lua_setfield(lua, -2, "mac_address"); > ++ lua_call(lua, 2, 0); /* pass 2 values, > expect 0 */ > ++ } > ++ } > + else > + { > + lua_getglobal(lua, "lease"); /* function to call > */ > +@@ -478,7 +505,7 @@ int create_helper(int event_fd, int err_fd, > uid_t uid, gid_t gid, long max_fd) > + continue; > + } > + > +- if (data.action != ACTION_TFTP) > ++ if (data.action != ACTION_TFTP && data.action != ACTION_ARP) > + { > + #ifdef HAVE_DHCP6 > + my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : > NULL, &err); > +@@ -550,10 +577,9 @@ int create_helper(int event_fd, int err_fd, > uid_t uid, gid_t gid, long max_fd) > + my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == > ACTION_OLD_HOSTNAME ? hostname : NULL, &err); > + if (data.action == ACTION_OLD_HOSTNAME) > + hostname = NULL; > +- } > +- > +- my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" > : NULL, &err); > +- > ++ > ++ 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); > +@@ -563,8 +589,8 @@ int create_helper(int event_fd, int err_fd, > uid_t uid, gid_t gid, long max_fd) > + if (err == 0) > + { > + execl(daemon->lease_change_command, > +- p ? p+1 : daemon->lease_change_command, > +- action_str, is6 ? daemon->packet : daemon > ->dhcp_buff, > ++ p ? p+1 : daemon->lease_change_command, action_str, > ++ (is6 && data.action != ACTION_ARP) ? daemon->packet > : daemon->dhcp_buff, > + daemon->addrbuff, hostname, (char*)NULL); > + err = errno; > + } > +@@ -760,6 +786,30 @@ void queue_tftp(off_t file_len, char *filename, > union mysockaddr *peer) > + } > + #endif > + > ++void queue_arp(int action, unsigned char *mac, int maclen, int > family, struct all_addr *addr) > ++{ > ++ /* no script */ > ++ if (daemon->helperfd == -1) > ++ return; > ++ > ++ buff_alloc(sizeof(struct script_data)); > ++ memset(buf, 0, sizeof(struct script_data)); > ++ > ++ buf->action = action; > ++ buf->hwaddr_len = maclen; > ++ buf->hwaddr_type = ARPHRD_ETHER; > ++ if ((buf->flags = family) == AF_INET) > ++ buf->addr = addr->addr.addr4; > ++#ifdef HAVE_IPV6 > ++ else > ++ buf->addr6 = addr->addr.addr6; > ++#endif > ++ > ++ memcpy(buf->hwaddr, mac, maclen); > ++ > ++ bytes_in_buf = sizeof(struct script_data); > ++} > ++ > + int helper_buf_empty(void) > + { > + return bytes_in_buf == 0; > +diff --git a/src/option.c b/src/option.c > +index 71beb98..f359bc5 100644 > +--- a/src/option.c > ++++ b/src/option.c > +@@ -154,6 +154,7 @@ struct myoption { > + #define LOPT_HOST_INOTIFY 342 > + #define LOPT_DNSSEC_STAMP 343 > + #define LOPT_TFTP_NO_FAIL 344 > ++#define LOPT_DNS_CLIENT_ID 355 > + > + #ifdef HAVE_GETOPT_LONG > + static const struct option opts[] = > +@@ -281,6 +282,7 @@ static const struct myoption opts[] = > + { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, > + { "add-mac", 0, 0, LOPT_ADD_MAC }, > + { "add-subnet", 2, 0, LOPT_ADD_SBNET }, > ++ { "add-dns-client", 2, 0 , LOPT_DNS_CLIENT_ID }, > + { "proxy-dnssec", 0, 0, LOPT_DNSSEC }, > + { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, > + { "conntrack", 0, 0, LOPT_CONNTRACK }, > +@@ -446,6 +448,7 @@ static struct { > + { LOPT_TEST, 0, NULL, gettext_noop("Check configuration > syntax."), NULL }, > + { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's > MAC address to forwarded DNS queries."), NULL }, > + { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", > gettext_noop("Add specified IP subnet to forwarded DNS queries."), > NULL }, > ++ { LOPT_DNS_CLIENT_ID, ARG_ONE, "<proxyname>", gettext_noop("Add > client identification to forwarded DNS queries."), NULL }, > + { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC > validation results from upstream nameservers."), NULL }, > + { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to > allocate sequential IP addresses to DHCP clients."), NULL }, > + { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy > connection-track mark from queries to upstream connections."), NULL > }, > +@@ -2150,6 +2153,12 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > + } > + break; > + > ++ case LOPT_DNS_CLIENT_ID: /* --add-dns-client */ > ++ set_option_bool(OPT_DNS_CLIENT); > ++ if (arg) > ++ daemon->dns_client_id = opt_string_alloc(arg); > ++ break; > ++ > + case 'u': /* --user */ > + daemon->username = opt_string_alloc(arg); > + break; > +diff --git a/src/rfc3315.c b/src/rfc3315.c > +index 3ed8623..31bb41b 100644 > +--- a/src/rfc3315.c > ++++ b/src/rfc3315.c > +@@ -130,7 +130,7 @@ static int dhcp6_maybe_relay(struct state > *state, void *inbuff, size_t sz, > + MAC address from the local ND cache. */ > + > + if (!state->link_address) > +- get_client_mac(client_addr, state->interface, state->mac, > &state->mac_len, &state->mac_type); > ++ get_client_mac(client_addr, state->interface, state->mac, > &state->mac_len, &state->mac_type, now); > + else > + { > + struct dhcp_context *c; > +@@ -2054,7 +2054,8 @@ static unsigned int opt6_uint(unsigned char > *opt, int offset, int size) > + return ret; > + } > + > +-void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct > in6_addr *peer_address, u32 scope_id) > ++void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, > ++ struct in6_addr *peer_address, u32 scope_id, > time_t now) > + { > + /* ->local is same value for all relays on ->current chain */ > + > +@@ -2068,7 +2069,7 @@ void relay_upstream6(struct dhcp_relay *relay, > ssize_t sz, struct in6_addr *peer > + unsigned char mac[DHCP_CHADDR_MAX]; > + > + inet_pton(AF_INET6, ALL_SERVERS, &multicast); > +- get_client_mac(peer_address, scope_id, mac, &maclen, &mactype); > ++ get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, > now); > + > + /* source address == relay address */ > + from.addr.addr6 = relay->local.addr.addr6; > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/038 > -Correct_logic_for_when_to_start_helper.patch > b/src/patches/dnsmasq/038 > -Correct_logic_for_when_to_start_helper.patch > new file mode 100644 > index 0000000..2c25d30 > --- /dev/null > +++ b/src/patches/dnsmasq/038 > -Correct_logic_for_when_to_start_helper.patch > @@ -0,0 +1,25 @@ > +From 8e39c34077cdad5b8e7cc799443bf8d1f22a1e80 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Thu, 31 Dec 2015 16:18:11 +0000 > +Subject: [PATCH] Correct logic for when to start helper. > + > +--- > + src/dnsmasq.c | 2 +- > + 1 file changed, 1 insertion(+), 1 deletion(-) > + > +diff --git a/src/dnsmasq.c b/src/dnsmasq.c > +index 229693f..009d357 100644 > +--- a/src/dnsmasq.c > ++++ b/src/dnsmasq.c > +@@ -556,7 +556,7 @@ int main (int argc, char **argv) > + /* if we are to run scripts, we need to fork a helper before > dropping root. */ > + daemon->helperfd = -1; > + #ifdef HAVE_SCRIPT > +- if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || > option_bool(OPT_ADD_MAC)) && > ++ if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || > option_bool(OPT_DNS_CLIENT)) && > + (daemon->lease_change_command || daemon->luascript)) > + daemon->helperfd = create_helper(pipewrite, err_pipe[1], > script_uid, script_gid, max_fd); > + #endif > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/039-Trivial_code_tweak.patch > b/src/patches/dnsmasq/039-Trivial_code_tweak.patch > new file mode 100644 > index 0000000..ce0d23b > --- /dev/null > +++ b/src/patches/dnsmasq/039-Trivial_code_tweak.patch > @@ -0,0 +1,33 @@ > +From ec0628c4b2a06e1fc21216091bb040d61a43b271 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Thu, 31 Dec 2015 20:55:39 +0000 > +Subject: [PATCH] Trivial code tweak. > + > +--- > + src/dnssec.c | 8 ++++---- > + 1 file changed, 4 insertions(+), 4 deletions(-) > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 918a2dc..0e5cbe8 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -1599,12 +1599,12 @@ static int check_nsec3_coverage(struct > dns_header *header, size_t plen, int dige > + if (!CHECK_LEN(header, p, plen, rdlen)) > + return 0; > + > +- /* If we can prove that there's no NS record, > return that information. */ > +- if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & > (0x80 >> T_NS)) != 0) > +- *nons = 0; > +- > + if (rdlen >= 2 && p[0] == 0) > + { > ++ /* If we can prove that there's no NS record, > return that information. */ > ++ if (nons && (p[2] & (0x80 >> T_NS)) != 0) > ++ *nons = 0; > ++ > + /* A CNAME answer would also be valid, so if > there's a CNAME is should > + have been returned. */ > + if ((p[2] & (0x80 >> T_CNAME)) != 0) > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/040 > -Extra_check_in_NSEC3_processing.patch b/src/patches/dnsmasq/040 > -Extra_check_in_NSEC3_processing.patch > new file mode 100644 > index 0000000..d0daa23 > --- /dev/null > +++ b/src/patches/dnsmasq/040-Extra_check_in_NSEC3_processing.patch > @@ -0,0 +1,60 @@ > +From f89391d09844837b7ec4394f1e3008c6f339b4bd Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Fri, 1 Jan 2016 19:44:11 +0000 > +Subject: [PATCH] Extra check in NSEC3 processing. > + > +--- > + src/dnssec.c | 30 +++++++++++++++++++++++++++--- > + 1 file changed, 27 insertions(+), 3 deletions(-) > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 0e5cbe8..cd29d88 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -1665,8 +1665,8 @@ static int check_nsec3_coverage(struct > dns_header *header, size_t plen, int dige > + static int prove_non_existence_nsec3(struct dns_header *header, > size_t plen, unsigned char **nsecs, int nsec_count, > + char *workspace1, char > *workspace2, char *name, int type, char *wildname, int *nons) > + { > +- unsigned char *salt, *p, *digest; > +- int digest_len, i, iterations, salt_len, base32_len, algo = 0; > ++ unsigned char *salt, *p, *digest, *psave; > ++ int digest_len, i, rdlen, iterations, salt_len, hash_len, > base32_len, algo = 0; > + struct nettle_hash const *hash; > + char *closest_encloser, *next_closest, *wildcard; > + > +@@ -1785,7 +1785,31 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > + > + if (!closest_encloser) > + return 0; > +- > ++ > ++ p += 8; /* class, type, TTL */ > ++ GETSHORT(rdlen, p); > ++ psave = p; > ++ p += 4; /* algo, flags, iterations */ > ++ salt_len = *p++; /* salt_len */ > ++ p += salt_len; /* salt */ > ++ hash_len = *p++; /* p now points to next hashed name */ > ++ p += hash_len; /* skip next-domain hash */ > ++ rdlen -= p - psave; > ++ > ++ if (!CHECK_LEN(header, p, plen, rdlen)) > ++ return 0; > ++ > ++ if (rdlen >= 2 && p[0] == 0) > ++ { > ++ /* 5155 8.3: the NS type bit may only be set if the SOA type > bit is set. */ > ++ if ((p[2] & (0x80 >> T_NS)) != 0 && (p[2] & (0x80 >> T_SOA)) > == 0) > ++ return 0; > ++ > ++ /* 5155 8.3: The DNAME type bit must not be set. */ > ++ if (rdlen >= 2 + (T_DNAME/8) && (p[2 + (T_DNAME/8)] & (0x80 > >> (T_DNAME%8))) != 0) > ++ return 0; > ++ } > ++ > + /* Look for NSEC3 that proves the non-existence of the next > -closest encloser */ > + if ((digest_len = hash_name(next_closest, &digest, hash, salt, > salt_len, iterations)) == 0) > + return 0; > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/041-Fix_linked-list_botch_in_new_ARP > -cache_code.patch b/src/patches/dnsmasq/041-Fix_linked > -list_botch_in_new_ARP-cache_code.patch > new file mode 100644 > index 0000000..396171d > --- /dev/null > +++ b/src/patches/dnsmasq/041-Fix_linked-list_botch_in_new_ARP > -cache_code.patch > @@ -0,0 +1,55 @@ > +From 19eeed3b32086ec3bd18cb2841d310ff5953b6d7 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Fri, 1 Jan 2016 20:24:15 +0000 > +Subject: [PATCH] Fix linked-list botch in new ARP-cache code. > + > +--- > + src/arp.c | 25 ++++++++++++++----------- > + 1 file changed, 14 insertions(+), 11 deletions(-) > + > +diff --git a/src/arp.c b/src/arp.c > +index f41cdec..374446c 100644 > +--- a/src/arp.c > ++++ b/src/arp.c > +@@ -110,7 +110,7 @@ static int filter_mac(int family, char *addrp, > char *mac, size_t maclen, void *p > + /* If in lazy mode, we cache absence of ARP entries. */ > + int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, > time_t now) > + { > +- struct arp_record *arp, **up; > ++ struct arp_record *arp, *tmp, **up; > + int updated = 0; > + > + again: > +@@ -155,16 +155,19 @@ int find_mac(union mysockaddr *addr, unsigned > char *mac, int lazy, time_t now) > + iface_enumerate(AF_UNSPEC, NULL, filter_mac); > + > + /* Remove all unconfirmed entries to old list. */ > +- for (arp = arps, up = &arps; arp; arp = arp->next) > +- if (arp->status == ARP_MARK) > +- { > +- *up = arp->next; > +- arp->next = old; > +- old = arp; > +- } > +- else > +- up = &arp->next; > +- > ++ for (arp = arps, up = &arps; arp; arp = tmp) > ++ { > ++ tmp = arp->next; > ++ if (arp->status == ARP_MARK) > ++ { > ++ *up = arp->next; > ++ arp->next = old; > ++ old = arp; > ++ } > ++ else > ++ up = &arp->next; > ++ } > ++ > + goto again; > + } > + > +-- > +1.7.10.4 > +