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
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 +