From mboxrd@z Thu Jan 1 00:00:00 1970 From: Michael Tremer To: development@lists.ipfire.org Subject: Re: [PATCH] dnsmasq 2.75: latest patches from upstream Date: Mon, 28 Dec 2015 15:40:06 +0100 Message-ID: <1451313606.3063.3.camel@ipfire.org> In-Reply-To: <1450948636-31650-1-git-send-email-matthias.fischer@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7307927719851920142==" List-Id: --===============7307927719851920142== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Merged. Can we have these updates like once per Core Update? Best, -Michael On Thu, 2015-12-24 at 10:17 +0100, Matthias Fischer wrote: > Same procedure as... :-) >=20 > Best to all for xmas and 2016! >=20 > Matthias >=20 > Signed-off-by: Matthias Fischer > --- > =C2=A0lfs/dnsmasq=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A05 + > =C2=A0...EDNS0_handling_and_computation_use_of_udp.patch | 643 > +++++++++++++++++++++ > =C2=A0...aks_in_handling_unknown_DNSSEC_algorithms.patch | 262 +++++++++ > =C2=A0...obscure_off-by-one_in_DNSSEC_hostname_cmp.patch |=C2=A0=C2=A027 + > =C2=A0.../028-Minor_tweak_to_previous_commit.patch=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0|=C2=A0=C2=A039 ++ > =C2=A0.../dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch |=C2=A0=C2=A039 ++ > =C2=A06 files changed, 1015 insertions(+) > =C2=A0create mode 100644 src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > =C2=A0create mode 100644 src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > =C2=A0create mode 100644 src/patches/dnsmasq/027- > Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch > =C2=A0create mode 100644 src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch > =C2=A0create mode 100644 src/patches/dnsmasq/029- > NSEC3_check_RFC5155_para_8_2.patch >=20 > diff --git a/lfs/dnsmasq b/lfs/dnsmasq > index c8fd7db..8058663 100644 > --- a/lfs/dnsmasq > +++ b/lfs/dnsmasq > @@ -97,6 +97,11 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) > =C2=A0 cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non- > existence_code_Check_zone_status_is_NSEC_proof_bad.patch > =C2=A0 cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/023- > Fix_brace_botch_in_dnssec_validate_ds.patch > =C2=A0 cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/024- > Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p > atch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > + 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 > =C2=A0 cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease- > file.patch > =C2=A0 > =C2=A0 cd $(DIR_APP) && sed -i src/config.h \ > diff --git a/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > b/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > new file mode 100644 > index 0000000..c016e73 > --- /dev/null > +++ b/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > @@ -0,0 +1,643 @@ > +From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley > +Date: Sun, 20 Dec 2015 17:12:16 +0000 > +Subject: [PATCH] Major tidy up of EDNS0 handling and computation/use > of udp > + packet size. > + > +--- > + src/auth.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A08 ++- > + src/dnsmasq.h=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A07 ++- > + src/dnssec.c=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A01 - > + src/forward.c=C2=A0=C2=A0|=C2=A0=C2=A0184 +++++++++++++++++++++++++++++++= +++++++++----- > ----------- > + src/netlink.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A03 +- > + src/rfc1035.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A081 +++++++------------------ > + src/rrfilter.c |=C2=A0=C2=A0=C2=A0=C2=A02 +- > + 7 files changed, 168 insertions(+), 118 deletions(-) > + > +diff --git a/src/auth.c b/src/auth.c > +index 2b0b7d6..85bd5e7 100644 > +--- a/src/auth.c > ++++ b/src/auth.c > +@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, > char **cut) > + } > +=C2=A0 > +=C2=A0 > +-size_t answer_auth(struct dns_header *header, char *limit, size_t > qlen, time_t now, union mysockaddr *peer_addr, int local_query)=C2=A0 > ++size_t answer_auth(struct dns_header *header, char *limit, size_t > qlen, time_t now, union mysockaddr *peer_addr,=C2=A0 > ++ =C2=A0=C2=A0=C2=A0int local_query, int do_bit, int > have_pseudoheader)=C2=A0 > + { > +=C2=A0=C2=A0=C2=A0char *name =3D daemon->namebuff; > +=C2=A0=C2=A0=C2=A0unsigned char *p, *ansp; > +@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, > char *limit, size_t qlen, time_t n > +=C2=A0=C2=A0=C2=A0header->ancount =3D htons(anscount); > +=C2=A0=C2=A0=C2=A0header->nscount =3D htons(authcount); > +=C2=A0=C2=A0=C2=A0header->arcount =3D htons(0); > ++ > ++=C2=A0=C2=A0/* Advertise our packet size limit in our reply */ > ++=C2=A0=C2=A0if (have_pseudoheader) > ++=C2=A0=C2=A0=C2=A0=C2=A0return add_pseudoheader(header,=C2=A0=C2=A0ansp -= (unsigned char > *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, > do_bit); > ++ > +=C2=A0=C2=A0=C2=A0return ansp - (unsigned char *)header; > + } > +=C2=A0=C2=A0=C2=A0 > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 39a930c..abb34c5 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header > *header, size_t qlen, char *namebuff, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int no_cache, int secure, int = *doctored); > + size_t answer_request(struct dns_header *header, char *limit, > size_t qlen,=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct in_addr local_addr, str= uct in_addr > local_netmask,=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0time_t now, int *ad_reqd, int *do_b= it); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0time_t now, int ad_reqd, int do_bit= , int > have_pseudoheader); > + int check_for_bogus_wildcard(struct dns_header *header, size_t > qlen, char *name,=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct bogus_addr *addr, time_t now= ); > + int check_for_ignored_address(struct dns_header *header, size_t > qlen, struct bogus_addr *baddr); > +@@ -1123,6 +1123,8 @@ 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,=C2=A0 > +=C2=A0 =C2=A0=C2=A0unsigned char *pheader, size_t hlen); > ++size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit,=C2=A0 > ++ 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 > +@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int > ban_localhost); > + /* auth.c */ > + #ifdef HAVE_AUTH > + size_t answer_auth(struct dns_header *header, char *limit, size_t > qlen,=C2=A0 > +- =C2=A0=C2=A0=C2=A0time_t now, union mysockaddr *peer_addr, int > local_query); > ++ =C2=A0=C2=A0=C2=A0time_t now, union mysockaddr *peer_addr, int > local_query, > ++ =C2=A0=C2=A0=C2=A0int do_bit, int have_pseudoheader); > + int in_zone(struct auth_zone *zone, char *name, char **cut); > + #endif > +=C2=A0 > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 82394ee..299ca64 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 12: return "gosthash94"; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 13: return "sha256"; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 14: return "sha384"; > +- > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0default: return NULL; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + } > +diff --git a/src/forward.c b/src/forward.c > +index 3e801c8..041353c 100644 > +--- a/src/forward.c > ++++ b/src/forward.c > +@@ -244,7 +244,6 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > +=C2=A0=C2=A0=C2=A0void *hash =3D &crc; > + #endif > +=C2=A0=C2=A0unsigned int gotname =3D extract_request(header, plen, daemon- > >namebuff, NULL); > +- unsigned char *pheader; > +=C2=A0 > +=C2=A0=C2=A0(void)do_bit; > +=C2=A0 > +@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > +=C2=A0 =C2=A0there's no point retrying the query, retry the key query > instead...... */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (forward->blocking_query) > +=C2=A0 { > +- =C2=A0=C2=A0int fd; > ++ =C2=A0=C2=A0int fd, is_sign; > ++ =C2=A0=C2=A0unsigned char *pheader; > +=C2=A0 =C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0forward->flags &=3D ~FREC_TEST_PKTSZ; > +=C2=A0 =C2=A0=C2=A0 > +@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > +=C2=A0 =C2=A0=C2=A0blockdata_retrieve(forward->stash, forward->stash_len, > (void *)header); > +=C2=A0 =C2=A0=C2=A0plen =3D forward->stash_len; > +=C2=A0 =C2=A0=C2=A0 > +- =C2=A0=C2=A0if (find_pseudoheader(header, plen, NULL, &pheader, > NULL)) > +- =C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? > SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader); > ++ =C2=A0=C2=A0if (find_pseudoheader(header, plen, NULL, &pheader, > &is_sign) && !is_sign) > ++ =C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(SAFE_PKTSZ, pheader); > +=C2=A0 > +=C2=A0 =C2=A0=C2=A0if (forward->sentto->addr.sa.sa_family =3D=3D AF_INET)= =C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "r= etry", > (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); > +@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->log_id =3D daemon->log_= id; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_ADD_MAC)) > +- plen =3D add_mac(header, plen, ((char *) header) + daemon- > >packet_buff_sz, &forward->source); > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++ { > ++ =C2=A0=C2=A0size_t new =3D add_mac(header, plen, ((char *) header) + > daemon->packet_buff_sz, &forward->source); > ++ =C2=A0=C2=A0if (new !=3D plen) > ++ =C2=A0=C2=A0=C2=A0=C2=A0{ > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0plen =3D new; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->flags |=3D FREC_ADDED_PHEAD= ER; > ++ =C2=A0=C2=A0=C2=A0=C2=A0} > ++ } > ++ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_CLIENT_SUBNE= T)) > +=C2=A0 { > +=C2=A0 =C2=A0=C2=A0size_t new =3D add_source_addr(header, plen, ((char *) > header) + daemon->packet_buff_sz, &forward->source);=C2=A0 > +=C2=A0 =C2=A0=C2=A0if (new !=3D plen) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0plen =3D new; > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->flags |=3D FREC_HAS_SUBNET; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->flags |=3D FREC_HAS_SUBNET | > FREC_ADDED_PHEADER; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 } > +=C2=A0 > + #ifdef HAVE_DNSSEC > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_VALID= )) > +=C2=A0 { > +- =C2=A0=C2=A0size_t new_plen =3D add_do_bit(header, plen, ((char *) > header) + daemon->packet_buff_sz); > ++ =C2=A0=C2=A0size_t new =3D add_do_bit(header, plen, ((char *) header) + > daemon->packet_buff_sz); > +=C2=A0 =C2=A0 > ++ =C2=A0=C2=A0if (new !=3D plen) > ++ =C2=A0=C2=A0=C2=A0=C2=A0forward->flags |=3D FREC_ADDED_PHEADER; > ++ > ++ =C2=A0=C2=A0plen =3D new; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0/* For debugging, set Checking Disabled, otherwise, have > the upstream check too, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0this allows it to select auth servers= when one is > returning bad data. */ > +=C2=A0 =C2=A0=C2=A0if (option_bool(OPT_DNSSEC_DEBUG)) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0header->hb4 |=3D HB4_CD; > +=C2=A0 > +- =C2=A0=C2=A0if (new_plen !=3D plen) > +- =C2=A0=C2=A0=C2=A0=C2=A0forward->flags |=3D FREC_ADDED_PHEADER; > +- > +- =C2=A0=C2=A0plen =3D new_plen; > +=C2=A0 } > + #endif > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > + #endif > +=C2=A0 } > +- > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (find_pseudoheader(header, plen, = NULL, &pheader, > NULL)) > +- PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? > SAFE_PKTSZ : start->edns_pktsz, pheader); > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++#ifdef HAVE_DNSSEC > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_VALID) &&= !do_bit) > ++ { > ++ =C2=A0=C2=A0/* Difficult one here. If our client didn't send > EDNS0, we will have set the UDP > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0packet size to 512. But that won't provide > space for the RRSIGS in many cases. > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0The RRSIGS will be stripped out before the > answer goes back, so the packet should > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0shrink again. So, if we added a do-bit, b= ump > the udp packet size to the value > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0known to be OK for this server. Maybe che= ck > returned size after stripping and set > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the truncated bit? */ =C2=A0=C2=A0 > ++ =C2=A0=C2=A0unsigned char *pheader; > ++ =C2=A0=C2=A0int is_sign; > ++ =C2=A0=C2=A0if (find_pseudoheader(header, plen, NULL, > &pheader, &is_sign)) > ++ =C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(start->edns_pktsz, pheader); > ++ } > ++#endif > ++ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (retry_send(sendto(fd, (char= *)header, plen, 0, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0&start->addr.sa, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0sa_len(&start->addr)))) > +@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + #endif > +=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0/* If upstream is advertising a larger UDP packet size > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0than we allow, trim it so that we don't get= overlarge > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0requests for the client. We can't do this f= or signed packets. > */ > +- > +=C2=A0=C2=A0=C2=A0if ((pheader =3D find_pseudoheader(header, n, &plen, &si= zep, > &is_sign))) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned short udpsz; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *psave =3D sizep; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(udpsz, sizep); > +- > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!is_sign && udpsz > daemon->edns_= pktsz) > +- PUTSHORT(daemon->edns_pktsz, psave); > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (check_subnet && !check_sourc= e(header, plen, pheader, > query_source)) > +=C2=A0 { > +=C2=A0 =C2=A0=C2=A0my_syslog(LOG_WARNING, _("discarding DNS reply: subnet > option mismatch")); > +=C2=A0 =C2=A0=C2=A0return 0; > +=C2=A0 } > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (added_pheader) > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!is_sign) > +=C2=A0 { > +- =C2=A0=C2=A0pheader =3D 0;=C2=A0 > +- =C2=A0=C2=A0header->arcount =3D htons(0); > ++ =C2=A0=C2=A0if (added_pheader) > ++ =C2=A0=C2=A0=C2=A0=C2=A0{ > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* client didn't send EDNS0, we adde= d one, strip it > off before returning answer. */ > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0n =3D rrfilter(header, n, 0); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0pheader =3D NULL; > ++ =C2=A0=C2=A0=C2=A0=C2=A0} > ++ =C2=A0=C2=A0else > ++ =C2=A0=C2=A0=C2=A0=C2=A0{ > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* If upstream is advertising a larg= er UDP packet > size > ++ =C2=A0than we allow, trim it so that we don't get > overlarge > ++ =C2=A0requests for the client. We can't do this for > signed packets. */ > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned short udpsz; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *psave =3D sizep; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(udpsz, sizep); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (udpsz > daemon->edns_pktsz) > ++ PUTSHORT(daemon->edns_pktsz, psave); > ++ =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 } > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0=C2=A0=C2=A0 > +@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 > +=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_VALID)) > +-=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 &=3D ~HB4_AD; > +-=C2=A0=C2=A0 > +-=C2=A0=C2=A0if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) > +-=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 |=3D HB4_AD; > +- > +-=C2=A0=C2=A0/* If the requestor didn't set the DO bit, don't return DNSSEC > info. */ > +-=C2=A0=C2=A0if (!do_bit) > +-=C2=A0=C2=A0=C2=A0=C2=A0n =3D rrfilter(header, n, 1); > ++=C2=A0=C2=A0=C2=A0=C2=A0{ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 &=3D ~HB4_AD; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(header->hb4 & HB4_CD) && ad_req= d && cache_secure) > ++ header->hb4 |=3D HB4_AD; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* If the requestor didn't set the DO= bit, don't return > DNSSEC info. */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!do_bit) > ++ n =3D rrfilter(header, n, 1); > ++=C2=A0=C2=A0=C2=A0=C2=A0} > + #endif > +=C2=A0 > +=C2=A0=C2=A0=C2=A0/* do this after extract_addresses. Ensure NODATA reply = and > remove > +@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t > now) > +=C2=A0 =C2=A0=C2=A0if ((nn =3D resize_packet(header, (size_t)n, pheader, > plen))) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->hb3 &=3D ~(HB3_QR | HB3= _AA | HB3_TC); > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 &=3D ~(HB4_RA | HB4_RCOD= E); > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward_query(-1, NULL, NULL, 0, hea= der, nn, now, > forward, 0, 0); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 &=3D ~(HB4_RA | HB4_RCOD= E | HB4_CD | > HB4_AD); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (forward->flags |=3D FREC_CHECKIN= G_DISABLED) > ++ header->hb4 |=3D HB4_CD; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (forward->flags |=3D FREC_AD_QUES= TION) > ++ header->hb4 |=3D HB4_AD; > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (forward->flags & FREC_DO_QUESTIO= N) > ++ add_do_bit(header, nn,=C2=A0=C2=A0(char *)pheader + plen); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward_query(-1, NULL, NULL, 0, hea= der, nn, now, > forward, forward->flags & FREC_AD_QUESTION, forward->flags & > FREC_DO_QUESTION); > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 } > +@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, > time_t now) > + { > +=C2=A0=C2=A0=C2=A0struct dns_header *header =3D (struct dns_header *)daemo= n->packet; > +=C2=A0=C2=A0=C2=A0union mysockaddr source_addr; > +-=C2=A0=C2=A0unsigned short type; > ++=C2=A0=C2=A0unsigned char *pheader; > ++=C2=A0=C2=A0unsigned short type, udp_size =3D PACKETSZ; /* default if no = EDNS0 > */ > +=C2=A0=C2=A0=C2=A0struct all_addr dst_addr; > +=C2=A0=C2=A0=C2=A0struct in_addr netmask, dst_addr_4; > +=C2=A0=C2=A0=C2=A0size_t m; > +=C2=A0=C2=A0=C2=A0ssize_t n; > +-=C2=A0=C2=A0int if_index =3D 0, auth_dns =3D 0; > ++=C2=A0=C2=A0int if_index =3D 0, auth_dns =3D 0, do_bit =3D 0, have_pseudo= header =3D > 0; > + #ifdef HAVE_AUTH > +=C2=A0=C2=A0=C2=A0int local_auth =3D 0; > + #endif > +@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, > time_t now) > + #endif > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL= )) > ++=C2=A0=C2=A0=C2=A0=C2=A0{=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned short flags; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0have_pseudoheader =3D 1; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(udp_size, pheader); > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0pheader +=3D 2; /* ext_rcode */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(flags, pheader); > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (flags & 0x8000) > ++ do_bit =3D 1;/* do bit */=C2=A0 > ++=09 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* If the client provides an EDNS0 UD= P size, use that to > limit our reply. > ++ =C2=A0(bounded by the maximum configured). If no EDNS0, then it > ++ =C2=A0defaults to 512 */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (udp_size > daemon->edns_pktsz) > ++ udp_size =3D daemon->edns_pktsz; > ++=C2=A0=C2=A0=C2=A0=C2=A0} > ++ > + #ifdef HAVE_AUTH > +=C2=A0=C2=A0=C2=A0if (auth_dns) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D answer_auth(header, ((char *) h= eader) + daemon- > >packet_buff_sz, (size_t)n, now, &source_addr, local_auth); > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D answer_auth(header, ((char *) h= eader) + udp_size, > (size_t)n, now, &source_addr,=C2=A0 > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0local_auth, do_bit, have_pseudohead= er); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (m >=3D 1) > +=C2=A0 { > +=C2=A0 =C2=A0=C2=A0send_from(listen->fd, option_bool(OPT_NOWILD) || > option_bool(OPT_CLEVERBIND), > +@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, > time_t now) > +=C2=A0=C2=A0=C2=A0else > + #endif > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ad_reqd, do_bit; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D answer_request(header, ((char *= ) header) + daemon- > >packet_buff_sz, (size_t)n,=C2=A0 > +- =C2=A0dst_addr_4, netmask, now, &ad_reqd, > &do_bit); > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ad_reqd =3D do_bit; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* RFC 6840 5.7 */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (header->hb4 & HB4_AD) > ++ ad_reqd =3D 1; > ++ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D answer_request(header, ((char *= ) header) + udp_size, > (size_t)n,=C2=A0 > ++ =C2=A0dst_addr_4, netmask, now, ad_reqd, do_bit, > have_pseudoheader); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (m >=3D 1) > +=C2=A0 { > +@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t > now, > + #ifdef HAVE_AUTH > +=C2=A0=C2=A0=C2=A0int local_auth =3D 0; > + #endif > +-=C2=A0=C2=A0int checking_disabled, ad_question, do_bit, added_pheader =3D= 0; > ++=C2=A0=C2=A0int checking_disabled, do_bit, added_pheader =3D 0, > have_pseudoheader =3D 0; > +=C2=A0=C2=A0=C2=A0int check_subnet, no_cache_dnssec =3D 0, cache_secure = =3D 0, > bogusanswer =3D 0; > +=C2=A0=C2=A0=C2=A0size_t m; > +=C2=A0=C2=A0=C2=A0unsigned short qtype; > +@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t > now, > +=C2=A0=C2=A0=C2=A0union mysockaddr peer_addr; > +=C2=A0=C2=A0=C2=A0socklen_t peer_len =3D sizeof(union mysockaddr); > +=C2=A0=C2=A0=C2=A0int query_count =3D 0; > ++=C2=A0=C2=A0unsigned char *pheader; > +=C2=A0 > +=C2=A0=C2=A0=C2=A0if (getpeername(confd, (struct sockaddr *)&peer_addr, &p= eer_len) > =3D=3D -1) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return packet; > +@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t > now, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else > +=C2=A0 dst_addr_4.s_addr =3D 0; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0do_bit =3D 0; > ++ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (find_pseudoheader(header, (size_t= )size, NULL, &pheader, > NULL)) > ++ {=C2=A0 > ++ =C2=A0=C2=A0unsigned short flags; > ++ =C2=A0=C2=A0 > ++ =C2=A0=C2=A0have_pseudoheader =3D 1; > ++ =C2=A0=C2=A0pheader +=3D 4; /* udp_size, ext_rcode */ > ++ =C2=A0=C2=A0GETSHORT(flags, pheader); > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++ =C2=A0=C2=A0if (flags & 0x8000) > ++ =C2=A0=C2=A0=C2=A0=C2=A0do_bit =3D 1;/* do bit */=C2=A0 > ++ } > ++ > + #ifdef HAVE_AUTH > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (auth_dns) > +- m =3D answer_auth(header, ((char *) header) + 65536, > (size_t)size, now, &peer_addr, local_auth); > ++ m =3D answer_auth(header, ((char *) header) + 65536, > (size_t)size, now, &peer_addr,=C2=A0 > ++ local_auth, do_bit, have_pseudoheader); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else > + #endif > +=C2=A0 { > +- =C2=A0=C2=A0/* m > 0 if answered from cache */ > +- =C2=A0=C2=A0m =3D answer_request(header, ((char *) header) + 65536, > (size_t)size,=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dst_addr_4, netmask, now, > &ad_question, &do_bit); > ++ =C2=A0=C2=A0=C2=A0int ad_reqd =3D do_bit; > ++ =C2=A0=C2=A0=C2=A0/* RFC 6840 5.7 */ > ++ =C2=A0=C2=A0=C2=A0if (header->hb4 & HB4_AD) > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ad_reqd =3D 1; > ++ =C2=A0=C2=A0=C2=A0 > ++ =C2=A0=C2=A0=C2=A0/* m > 0 if answered from cache */ > ++ =C2=A0=C2=A0=C2=A0m =3D answer_request(header, ((char *) header) + 65536, > (size_t)size,=C2=A0 > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dst_addr_4, netmask, now, ad_reqd, > do_bit, have_pseudoheader); > +=C2=A0 =C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0/* Do this by steam now we're not in the select() loop = */ > +=C2=A0 =C2=A0=C2=A0check_log_writer(1);=C2=A0 > +@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t > now, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 =C2=A0=C2=A0 > + #ifdef HAVE_DNSSEC > ++ =C2=A0=C2=A0added_pheader =3D 0; =09 > =C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0if (option_bool(OPT_DNSSEC_VALID)) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0size_t new_size =3D add_do_bi= t(header, > size, ((char *) header) + 65536); > +@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t > now, > +=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D process_reply(header, no= w, last_server, > (unsigned int)m,=C2=A0 > +=C2=A0 option_bool(OPT_NO_REBIND) > && !norebind, no_cache_dnssec, cache_secure, bogusanswer, > +- ad_question, do_bit, > added_pheader, check_subnet, &peer_addr);=C2=A0 > ++ ad_reqd, do_bit, > added_pheader, check_subnet, &peer_addr);=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +diff --git a/src/netlink.c b/src/netlink.c > +index 753784d..3376d68 100644 > +--- a/src/netlink.c > ++++ b/src/netlink.c > +@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int > (*callback)()) > +=C2=A0 rta =3D RTA_NEXT(rta, len1); > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0if (inaddr && mac && callback_ok) > ++ =C2=A0=C2=A0=C2=A0=C2=A0if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMP= LETE | > NUD_FAILED)) && > ++ inaddr && mac && callback_ok) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!((*callback)(neigh->ndm_fa= mily, inaddr, mac, > maclen, parm))) > +=C2=A0 callback_ok =3D 0; > +=C2=A0 =C2=A0=C2=A0} > +diff --git a/src/rfc1035.c b/src/rfc1035.c > +index 188d05f..18858a8 100644 > +--- a/src/rfc1035.c > ++++ b/src/rfc1035.c > +@@ -489,8 +489,8 @@ struct macparm { > +=C2=A0=C2=A0=C2=A0union mysockaddr *l3; > + }; > +=C2=A0=C2=A0 > +-static size_t add_pseudoheader(struct dns_header *header, size_t > plen, unsigned char *limit,=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int optno, unsigned char *op= t, > size_t optlen, int set_do) > ++size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit,=C2=A0 > ++ unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do) > + {=C2=A0 > +=C2=A0=C2=A0=C2=A0unsigned char *lenp, *datap, *p; > +=C2=A0=C2=A0=C2=A0int rdlen, is_sign; > +@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header > *header, size_t plen, unsigned > +=C2=A0 return plen; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*p++ =3D 0; /* empty name */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(T_OPT, p); > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(SAFE_PKTSZ, p); /* max packe= t length, this will be > overwritten */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(udp_sz, p); /* max packet le= ngth, 512 if not given > in EDNS0 header */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(0, p);=C2=A0=C2=A0=C2= =A0=C2=A0/* extended RCODE and version */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PUTSHORT(set_do ? 0x8000 : 0, p)= ; /* DO flag */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0lenp =3D p; > +@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, > char *mac, size_t maclen, void *p > +=C2=A0=C2=A0=C2=A0if (!match) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 1; /* continue */ > +=C2=A0 > +-=C2=A0=C2=A0parm->plen =3D add_pseudoheader(parm->header, parm->plen, par= m- > >limit,=C2=A0=C2=A0EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); > ++=C2=A0=C2=A0parm->plen =3D add_pseudoheader(parm->header, parm->plen, par= m- > >limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); > +=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0return 0; /* done */ > + } =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, > size_t plen, char *limit, union mysock > + { > +=C2=A0=C2=A0=C2=A0struct macparm parm; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +-/* Must have an existing pseudoheader as the only ar-record,=C2=A0 > +-=C2=A0=C2=A0=C2=A0or have no ar-records. Must also not be signed */ > +-=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0if (ntohs(header->arcount) > 1) > +-=C2=A0=C2=A0=C2=A0=C2=A0return plen; > +- > +=C2=A0=C2=A0=C2=A0parm.header =3D header; > +=C2=A0=C2=A0=C2=A0parm.limit =3D (unsigned char *)limit; > +=C2=A0=C2=A0=C2=A0parm.plen =3D plen; > +@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header > *header, size_t plen, char *limit, unio > +=C2=A0=C2=A0=C2=A0struct subnet_opt opt; > +=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0len =3D calc_subnet_opt(&opt, source); > +-=C2=A0=C2=A0return add_pseudoheader(header, plen, (unsigned char *)limit, > EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > ++=C2=A0=C2=A0return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > + } > +=C2=A0 > + #ifdef HAVE_DNSSEC > + size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > + { > +-=C2=A0=C2=A0return add_pseudoheader(header, plen, (unsigned char *)limit,= 0, > NULL, 0, 1); > ++=C2=A0=C2=A0return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > + } > + #endif > +=C2=A0 > +@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec > *crecp, time_t now) > + /* return zero if we can't answer from cache, or packet size if we > can */ > + size_t answer_request(struct dns_header *header, char *limit, > size_t qlen,=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct in_addr local_addr, str= uct in_addr > local_netmask,=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0time_t now, int *ad_reqd, int *do_b= it)=C2=A0 > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0time_t now, int ad_reqd, int do_bit= , int > have_pseudoheader)=C2=A0 > + { > +=C2=A0=C2=A0=C2=A0char *name =3D daemon->namebuff; > +-=C2=A0=C2=A0unsigned char *p, *ansp, *pheader; > ++=C2=A0=C2=A0unsigned char *p, *ansp; > +=C2=A0=C2=A0=C2=A0unsigned int qtype, qclass; > +=C2=A0=C2=A0=C2=A0struct all_addr addr; > +=C2=A0=C2=A0=C2=A0int nameoffset; > +=C2=A0=C2=A0=C2=A0unsigned short flag; > +=C2=A0=C2=A0=C2=A0int q, ans, anscount =3D 0, addncount =3D 0; > +-=C2=A0=C2=A0int dryrun =3D 0, sec_reqd =3D 0, have_pseudoheader =3D 0; > ++=C2=A0=C2=A0int dryrun =3D 0; > +=C2=A0=C2=A0=C2=A0struct crec *crecp; > +=C2=A0=C2=A0=C2=A0int nxdomain =3D 0, auth =3D 1, trunc =3D 0, sec_data = =3D 1; > +=C2=A0=C2=A0=C2=A0struct mx_srv_record *rec; > +@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > +=C2=A0=C2=A0=C2=A0if (header->hb4 & HB4_CD) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0sec_data =3D 0; > +=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0/* RFC 6840 5.7 */ > +-=C2=A0=C2=A0*ad_reqd =3D header->hb4 & HB4_AD; > +-=C2=A0=C2=A0*do_bit =3D 0; > +- > +=C2=A0=C2=A0=C2=A0/* If there is an=C2=A0=C2=A0additional data section the= n it will be > overwritten by > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0partial replies, so we have to do a dr= y run to see if we can > answer > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the query. */ > +- > +=C2=A0=C2=A0=C2=A0if (ntohs(header->arcount) !=3D 0) > +-=C2=A0=C2=A0=C2=A0=C2=A0{ > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dryrun =3D 1; > +- > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* If there's an additional section, = there might be an > EDNS(0) pseudoheader */ > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (find_pseudoheader(header, qlen, N= ULL, &pheader, NULL)) > +- {=C2=A0 > +- =C2=A0=C2=A0unsigned short flags; > +- =C2=A0=C2=A0 > +- =C2=A0=C2=A0have_pseudoheader =3D 1; > +- =C2=A0=C2=A0 > +- =C2=A0=C2=A0pheader +=3D 4; /* udp size, ext_rcode */ > +- =C2=A0=C2=A0GETSHORT(flags, pheader); > +- =C2=A0=C2=A0 > +- =C2=A0=C2=A0if ((sec_reqd =3D flags & 0x8000)) > +- =C2=A0=C2=A0=C2=A0=C2=A0{ > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*do_bit =3D 1;/* do bit */=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*ad_reqd =3D 1; > +- =C2=A0=C2=A0=C2=A0=C2=A0} > +- } > +-=C2=A0=C2=A0=C2=A0=C2=A0} > ++=C2=A0=C2=A0=C2=A0=C2=A0dryrun =3D 1; > +=C2=A0 > +=C2=A0=C2=A0=C2=A0for (rec =3D daemon->mxnames; rec; rec =3D rec->next) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rec->offset =3D 0; > +@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(qtype, p);=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(qclass, p); > +=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Don't filter RRSIGS from answers t= o ANY queries, even if > do-bit > +- =C2=A0not set. */ > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_ANY) > +- *do_bit =3D 1; > +- > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ans =3D 0; /* have we answered t= his question */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_TXT || qtype = =3D=3D T_ANY) > +@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the zone is unsigned, which implies = that we're > doing > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0validation. */ > +=C2=A0 =C2=A0=C2=A0if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) ||=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!sec_reqd ||=C2=A0 > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!do_bit ||=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(option_bool(OPT_DNSSEC_VALID)= && !(crecp- > >flags & F_DNSSECOK))) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0do=C2=A0 > +@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 > +=C2=A0 =C2=A0=C2=A0/* If the client asked for DNSSEC=C2=A0=C2=A0don't use > cached data. */ > +- =C2=A0=C2=A0if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) > ++ =C2=A0=C2=A0if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK)) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0do > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{=C2=A0 > +=C2=A0 /* don't answer wildcard queries with data > not from /etc/hosts > +@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > +=C2=A0 =09 > +=C2=A0 if (crecp->flags & F_NEG) > +=C2=A0 =C2=A0=C2=A0{ > +- =C2=A0=C2=A0=C2=A0=C2=A0/* We don't cache NSEC records, so if a > DNSSEC-validated negative answer > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0is cached and the client wan= ts > DNSSEC, forward rather than answering from the cache */ > +- =C2=A0=C2=A0=C2=A0=C2=A0if (!sec_reqd || !(crecp->flags & > F_DNSSECOK)) > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +- ans =3D 1; > +- auth =3D 0; > +- if (crecp->flags & F_NXDOMAIN) > +- =C2=A0=C2=A0nxdomain =3D 1; > +- if (!dryrun) > +- =C2=A0=C2=A0log_query(crecp->flags, name, > NULL, NULL); > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > ++ =C2=A0=C2=A0=C2=A0=C2=A0ans =3D 1; > ++ =C2=A0=C2=A0=C2=A0=C2=A0auth =3D 0; > ++ =C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_NXDOMAIN) > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0nxdomain =3D 1; > ++ =C2=A0=C2=A0=C2=A0=C2=A0if (!dryrun) > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0log_query(crecp->flags, name, NULL, > NULL); > +=C2=A0 =C2=A0=C2=A0} > +=C2=A0 else=C2=A0 > +=C2=A0 =C2=A0=C2=A0{ > +@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > +=C2=A0 > +=C2=A0=C2=A0=C2=A0len =3D ansp - (unsigned char *)header; > +=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0/* Advertise our packet size limit in our reply */ > +=C2=A0=C2=A0=C2=A0if (have_pseudoheader) > +-=C2=A0=C2=A0=C2=A0=C2=A0len =3D add_pseudoheader(header, len, (unsigned c= har *)limit, 0, > NULL, 0, sec_reqd); > ++=C2=A0=C2=A0=C2=A0=C2=A0len =3D add_pseudoheader(header, len, (unsigned c= har *)limit, > daemon->edns_pktsz, 0, NULL, 0, do_bit); > +=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0if (*ad_reqd && sec_data) > ++=C2=A0=C2=A0if (ad_reqd && sec_data) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 |=3D HB4_AD; > +=C2=A0=C2=A0=C2=A0else > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->hb4 &=3D ~HB4_AD; > +diff --git a/src/rrfilter.c b/src/rrfilter.c > +index ae12261..b26b39f 100644 > +--- a/src/rrfilter.c > ++++ b/src/rrfilter.c > +@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, > size_t plen, int mode) > +=C2=A0=C2=A0=C2=A0for (p =3D rrs[0], i =3D 1; i < rr_found; i +=3D 2) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *start =3D rrs[i]; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *end =3D (i !=3D rr_fou= nd - 1) ? rrs[i+1] : > ((unsigned char *)(header+1)) + plen; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *end =3D (i !=3D rr_fou= nd - 1) ? rrs[i+1] : > ((unsigned char *)header) + plen; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0memmove(p, start, end-start); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D end-start; > +--=C2=A0 > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > b/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > new file mode 100644 > index 0000000..910921b > --- /dev/null > +++ b/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > @@ -0,0 +1,262 @@ > +From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley > +Date: Sun, 20 Dec 2015 20:44:23 +0000 > +Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms. > + > +--- > + src/dnssec.c |=C2=A0=C2=A0128 +++++++++++++++++++++++++++++--------------= -- > ------------- > + 1 file changed, 63 insertions(+), 65 deletions(-) > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 299ca64..e09f304 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -70,7 +70,17 @@ static char *algo_digest_name(int algo) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0default: return NULL; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + } > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0 > ++/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-n > sec3-parameters.xhtml */ > ++static char *nsec3_digest_name(int digest) > ++{ > ++=C2=A0=C2=A0switch (digest) > ++=C2=A0=C2=A0=C2=A0=C2=A0{ > ++=C2=A0=C2=A0=C2=A0=C2=A0case 1: return "sha1"; > ++=C2=A0=C2=A0=C2=A0=C2=A0default: return NULL; > ++=C2=A0=C2=A0=C2=A0=C2=A0} > ++} > ++=C2=A0 > + /* Find pointer to correct hash function in nettle library */ > + static const struct nettle_hash *hash_find(char *name) > + { > +@@ -667,7 +677,6 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > +=C2=A0=C2=A0=C2=A0static int rrset_sz =3D 0, sig_sz =3D 0;=C2=A0 > +=C2=A0=C2=A0=C2=A0unsigned char *p; > +=C2=A0=C2=A0=C2=A0int rrsetidx, sigidx, j, rdlen, res; > +-=C2=A0=C2=A0int name_labels =3D count_labels(name); /* For 4035 5.3.2 che= ck */ > +=C2=A0=C2=A0=C2=A0int gotkey =3D 0; > +=C2=A0 > +=C2=A0=C2=A0=C2=A0if (!(p =3D skip_questions(header, plen))) > +@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0j !=3D 0; j--)=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *pstart, *pdata; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int stype, sclass, algo, type_covered= , labels, > sig_expiration, sig_inception; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int stype, sclass, type_covered; > +=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0pstart =3D p; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > +=C2=A0 return 0; /* bad packet */=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(type_covered, p); > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0algo =3D *p++; > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0labels =3D *p++; > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* orig_ttl */ > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(sig_expiration, p); > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(sig_inception, p); > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 2; /* key_tag */ > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 16; /* algo, labels, orig_ttl= , sig_expiration, > sig_inception, key_tag */ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (gotkey) > +=C2=A0 { > +@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 } > +=C2=A0 =C2=A0=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Don't count signatures for algos = we don't support > */ > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (check_date_range(sig_inception, = sig_expiration) > && > +- =C2=A0=C2=A0labels <=3D name_labels && > +- =C2=A0=C2=A0type_covered =3D=3D type &&=C2=A0 > +- =C2=A0=C2=A0verify_func(algo)) > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (type_covered =3D=3D type) > +=C2=A0 { > +=C2=A0 =C2=A0=C2=A0if (!expand_workspace(&sigs, &sig_sz, sigidx)) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0 > +@@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > +=C2=A0 =C2=A0=C2=A0char *name, char *keyname, char > **wildcard_out, struct blockdata *key, int keylen, int algo_in, int > keytag_in) > + { > +=C2=A0=C2=A0=C2=A0unsigned char *p; > +-=C2=A0=C2=A0int rdlen, j, name_labels; > ++=C2=A0=C2=A0int rdlen, j, name_labels, sig_expiration, sig_inception; > +=C2=A0=C2=A0=C2=A0struct crec *crecp =3D NULL; > +=C2=A0=C2=A0=C2=A0int algo, labels, orig_ttl, key_tag; > +=C2=A0=C2=A0=C2=A0u16 *rr_desc =3D rrfilter_desc(type); > +@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0algo =3D *p++; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0labels =3D *p++; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(orig_ttl, p); > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 8; /* sig_expiration, sig_ince= ption already checked */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(sig_expiration, p); > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(sig_inception, p); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(key_tag, p); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!extract_name(header, plen, = &p, keyname, 1, 0)) > +=C2=A0 return STAT_BOGUS; > +=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(hash =3D hash_find(algo_digest_= name(algo))) || > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!check_date_range(sig_inception, = sig_expiration) || > ++ =C2=A0=C2=A0labels > name_labels || > ++ =C2=A0=C2=A0!(hash =3D hash_find(algo_digest_name(algo))) || > +=C2=A0 =C2=A0=C2=A0!hash_init(hash, &ctx, &digest)) > +=C2=A0 continue; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else > +=C2=A0 { > +=C2=A0 =C2=A0=C2=A0a.addr.keytag =3D keytag; > +- =C2=A0=C2=A0log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u"); > ++ =C2=A0=C2=A0if (verify_func(algo)) > ++ =C2=A0=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u"); > ++ =C2=A0=C2=A0else > ++ =C2=A0=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)"); > +=C2=A0 =C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0recp1->addr.key.keylen =3D rdlen - 4; > +=C2=A0 =C2=A0=C2=A0recp1->addr.key.keydata =3D key; > +@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > +=C2=A0 =C2=A0=C2=A0else > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.keytag =3D keytag; > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_KEYTAG | F_= UPSTREAM, > name, &a, "DS keytag %u"); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (hash_find(ds_digest_name(digest= )) && > verify_func(algo)) > ++ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u"); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else > ++ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u (not supported)"); > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.digest =3D dige= st; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keydata =3D key; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.algo =3D algo; > +@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 1; > +=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0/* Look though the NSEC3 records to find the first one w= ith=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0an algorithm we support (currently only alg= o =3D=3D 1). > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0an algorithm we support. > +=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Take the algo, iterations, and salt of= that record > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0as the ones we're going to use, and pr= une any=C2=A0 > +@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 10; /* type, class, TTL, = rdlen */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0algo =3D *p++; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (algo =3D=3D 1) > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((hash =3D hash_find(nsec3_digest_= name(algo)))) > +=C2=A0 break; /* known algo */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 > +@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0nsecs[i] =3D nsec3p; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 > +-=C2=A0=C2=A0/* Algo is checked as 1 above */ > +-=C2=A0=C2=A0if (!(hash =3D hash_find("sha1"))) > +-=C2=A0=C2=A0=C2=A0=C2=A0return 0; > +- > +=C2=A0=C2=A0=C2=A0if ((digest_len =3D hash_name(name, &digest, hash, salt,= salt_len, > iterations)) =3D=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 0; > +=C2=A0=C2=A0=C2=A0 > +@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct > dns_header *header, size_t plen, char *key > +=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0if (type_found =3D=3D T_NSEC) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return prove_non_existence_nsec(header, plen= , nsecset, > nsecs_found, daemon->workspacename, keyname, name, qtype, nons); > +-=C2=A0=C2=A0else > ++=C2=A0=C2=A0else if (type_found =3D=3D T_NSEC3) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return prove_non_existence_nsec3(header, ple= n, nsecset, > nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, > nons); > ++=C2=A0=C2=A0else > ++=C2=A0=C2=A0=C2=A0=C2=A0return 0; > + } > +=C2=A0 > + /* Check signing status of name. > +@@ -1857,7 +1866,7 @@ static int prove_non_existence(struct > dns_header *header, size_t plen, char *key > + */ > + static int zone_status(char *name, int class, char *keyname, time_t > now) > + { > +-=C2=A0=C2=A0int secure_ds, name_start =3D strlen(name); > ++=C2=A0=C2=A0int name_start =3D strlen(name); > +=C2=A0=C2=A0=C2=A0struct crec *crecp; > +=C2=A0=C2=A0=C2=A0char *p; > +=C2=A0=C2=A0=C2=A0 > +@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int > class, char *keyname, time_t now) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(crecp =3D cache_find_by_na= me(NULL, keyname, now, F_DS))) > +=C2=A0 return STAT_NEED_DS; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* F_DNSSECOK misused in DS cac= he records to non-existance > of NS record. > ++ =C2=A0=C2=A0F_NEG && !F_DNSSECOK implies that we've proved there's no > DS record here, > ++ =C2=A0=C2=A0but that's because there's no NS record either, ie this > isn't the start > ++ =C2=A0=C2=A0of a zone. We only prove that the DNS tree below a node > is unsigned when > ++ =C2=A0=C2=A0we prove that we're at a zone cut AND there's no DS > record. */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_NEG) > ++ { > ++ =C2=A0=C2=A0if (crecp->flags & F_DNSSECOK) > ++ =C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; /* proved no DS here */ > ++ } > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else > +=C2=A0 { > +- =C2=A0=C2=A0secure_ds =3D 0; > +- =C2=A0=C2=A0 > ++ =C2=A0=C2=A0int gotone =3D 0; > ++ > ++ =C2=A0=C2=A0/* If all the DS records have digest and/or sig algos we > don't support, > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0then the zone is insecure. Note that if an= algo > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0appears in the DS, then RRSIGs for that al= go MUST > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0exist for each RRset: 4035 para 2.2=C2=A0= =C2=A0So if we find > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a DS here with digest and sig we can do, w= e're > entitled > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0to assume we can validate the zone and if = we can't > later, > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0because an RRSIG is missing we return BOGU= S. > ++ =C2=A0=C2=A0*/ > +=C2=A0 =C2=A0=C2=A0do=C2=A0 > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0{ > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D (unsigned int)= class) > +- { > +- =C2=A0=C2=A0/* F_DNSSECOK misused in DS cache records to non- > existance of NS record. > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0F_NEG && !F_DNSSECOK implies that we've p= roved > there's no DS record here, > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0but that's because there's no NS record > either, ie this isn't the start > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0of a zone. We only prove that the DNS tree > below a node is unsigned when > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0we prove that we're at a zone cut AND the= re's > no DS record. > +- =C2=A0=C2=A0*/ =C2=A0=C2=A0 > +- =C2=A0=C2=A0if (crecp->flags & F_NEG) > +- =C2=A0=C2=A0=C2=A0=C2=A0{ > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_DNSSECOK) > +- return STAT_INSECURE; /* proved no DS here > */ > +- =C2=A0=C2=A0=C2=A0=C2=A0} > +- =C2=A0=C2=A0else if (!hash_find(ds_digest_name(crecp- > >addr.ds.digest)) || !verify_func(crecp->addr.ds.algo)) > +- =C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; /* algo we can't use - > insecure */ > +- =C2=A0=C2=A0else > +- =C2=A0=C2=A0=C2=A0=C2=A0secure_ds =3D 1; > +- } > ++ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D (unsigned int)= class && > ++ =C2=A0=C2=A0hash_find(ds_digest_name(crecp->addr.ds.digest)) > && > ++ =C2=A0=C2=A0verify_func(crecp->addr.ds.algo)) > ++ gotone =3D 1; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 =C2=A0=C2=A0while ((crecp =3D cache_find_by_name(crecp, keyname, no= w, > F_DS))); > +- } > +- > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (secure_ds) > +- { > +- =C2=A0=C2=A0/* We've found only DS records that attest to the DNSKEY > RRset in the zone, so we believe > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0that RRset is good. Furthermore the DNSKEY= whose hash > is proved by the DS record is > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0one we can use. However the DNSKEY RRset m= ay contain > more than one key and > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0one of the other keys may use an algorithm= we don't > support. If that's=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the case the zone is insecure for us. */ > +- =C2=A0=C2=A0 > +- =C2=A0=C2=A0if (!(crecp =3D cache_find_by_name(NULL, keyname, now, > F_DNSKEY))) > +- =C2=A0=C2=A0=C2=A0=C2=A0return STAT_NEED_KEY; > +=C2=A0 > +- =C2=A0=C2=A0do=C2=A0 > +- =C2=A0=C2=A0=C2=A0=C2=A0{ > +- =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D (unsigned int)= class && > !verify_func(crecp->addr.key.algo)) > +- return STAT_INSECURE; > +- =C2=A0=C2=A0=C2=A0=C2=A0} > +- =C2=A0=C2=A0while ((crecp =3D cache_find_by_name(crecp, keyname, now, > F_DNSKEY))); > ++ =C2=A0=C2=A0if (!gotone) > ++ =C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; > +=C2=A0 } > +=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (name_start =3D=3D 0) > +--=C2=A0 > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by- > one_in_DNSSEC_hostname_cmp.patch b/src/patches/dnsmasq/027- > Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch > new file mode 100644 > index 0000000..031339e > --- /dev/null > +++ b/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by- > one_in_DNSSEC_hostname_cmp.patch > @@ -0,0 +1,27 @@ > +From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley > +Date: Sun, 20 Dec 2015 20:50:05 +0000 > +Subject: [PATCH] Nasty, rare and obscure off-by-one in DNSSEC > hostname_cmp(). > + > +--- > + src/dnssec.c |=C2=A0=C2=A0=C2=A0=C2=A04 ++-- > + 1 file changed, 2 insertions(+), 2 deletions(-) > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index e09f304..29848e1 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -1394,8 +1394,8 @@ static int hostname_cmp(const char *a, const > char *b) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (sb =3D=3D b) > +=C2=A0 return 1; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ea =3D sa--; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0eb =3D sb--; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ea =3D --sa; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0eb =3D --sb; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + } > +=C2=A0 > +--=C2=A0 > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch b/src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch > new file mode 100644 > index 0000000..f3758fc > --- /dev/null > +++ b/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch > @@ -0,0 +1,39 @@ > +From a86fdf437ecc29398f9715ceb5240442a17ac014 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley > +Date: Sun, 20 Dec 2015 21:19:20 +0000 > +Subject: [PATCH] Minor tweak to previous commit. > + > +--- > + src/dnssec.c |=C2=A0=C2=A0=C2=A0=C2=A06 ++---- > + 1 file changed, 2 insertions(+), 4 deletions(-) > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 29848e1..9fa64b6 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -1889,8 +1889,6 @@ static int zone_status(char *name, int class, > char *keyname, time_t now) > +=C2=A0 } > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else > +=C2=A0 { > +- =C2=A0=C2=A0int gotone =3D 0; > +- > +=C2=A0 =C2=A0=C2=A0/* If all the DS records have digest and/or sig algos we > don't support, > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0then the zone is insecure. Note that = if an algo > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0appears in the DS, then RRSIGs for th= at algo MUST > +@@ -1904,11 +1902,11 @@ static int zone_status(char *name, int > class, char *keyname, time_t now) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D (unsigned= int)class && > +=C2=A0 =C2=A0=C2=A0hash_find(ds_digest_name(crecp->addr.ds.digest)) > && > +=C2=A0 =C2=A0=C2=A0verify_func(crecp->addr.ds.algo)) > +- gotone =3D 1; > ++ break; > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0} > +=C2=A0 =C2=A0=C2=A0while ((crecp =3D cache_find_by_name(crecp, keyname, no= w, > F_DS))); > +=C2=A0 > +- =C2=A0=C2=A0if (!gotone) > ++ =C2=A0=C2=A0if (!crecp) > +=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; > +=C2=A0 } > +=C2=A0 > +--=C2=A0 > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/029- > NSEC3_check_RFC5155_para_8_2.patch b/src/patches/dnsmasq/029- > NSEC3_check_RFC5155_para_8_2.patch > new file mode 100644 > index 0000000..33219d2 > --- /dev/null > +++ b/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch > @@ -0,0 +1,39 @@ > +From ce5732e84fc46d7f99c152f736cfb4ef5ec98a01 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley > +Date: Sun, 20 Dec 2015 21:39:19 +0000 > +Subject: [PATCH] NSEC3 check: RFC5155 para 8.2 > + > +--- > + src/dnssec.c |=C2=A0=C2=A0=C2=A0=C2=A08 ++++++-- > + 1 file changed, 6 insertions(+), 2 deletions(-) > + > +diff --git a/src/dnssec.c b/src/dnssec.c > +index 9fa64b6..486e422 100644 > +--- a/src/dnssec.c > ++++ b/src/dnssec.c > +@@ -1704,7 +1704,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > +=C2=A0=C2=A0=C2=A0for (i =3D 0; i < nsec_count; i++) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *nsec3p =3D nsecs[= i]; > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int this_iter; > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int this_iter, flags; > +=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0nsecs[i] =3D NULL; /* Speculativ= e, will be restored if OK. */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (*p++ !=3D algo) > +=C2=A0 continue; > +=C2=A0=C2=A0 > +-=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p++; /* flags */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0flags =3D *p++; /* flags */ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* 5155 8.2 */ > ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (flags !=3D 0 && flags !=3D 1) > ++ continue; > ++ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(this_iter, p); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (this_iter !=3D iterations) > +=C2=A0 continue; > +--=C2=A0 > +1.7.10.4 > + --===============7307927719851920142== Content-Type: application/pgp-signature Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="signature.asc" MIME-Version: 1.0 LS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS0KVmVyc2lvbjogR251UEcgdjEKCmlRSWNCQUFC Q2dBR0JRSldnVW5IQUFvSkVJQjU4UDl2a0FrSENtb1AvaUVLWFNlekNWcFV5UjdlcUJvMlBsWUQK ZmhJbE9IOGNTNU5pb3RGQ1hKQ0Faa0dMdExFNVFVcnp1OFRNQVRmczVxMWxVdlBTc1NIWWdqbGJC OXk2ZDhxdwo4MFBhZFlFYWh4WkFGeCtBUDZmOUZhTTJMc2xzZFZoaTRkOFJGN3cxVFdHR0M2bTlq ZXJDZGoza0l6UHJUbUVoCm1MZHZ0SFR5ZTBkMW0rY3RQbEQrRkIwZ1AyOUhFeUU3RnF5TGI4Tmxw Wm5WUE16NmRncWh5TjViTFRrWWtoQ0YKRWRsanAwd3g5TkQxWFhyQVlWSDdKZjVLdDNlNitRaVpl MzMxYW5VMThIeDEvZ0dVM1Z4NEZWZWptZXBWQ0x2SQpWT1lhY1Y0VG9JYUpmS1Y5YTU5RlhEZnU3 bEYrR05VMnpVL3YyT05TeVFlMlJTN3JYbnNJV1lWYllOQUMzR2MyCmY2U2EwcHhyT0l2bDdwdnYv OHBxbDdid05sQzM2ZWc3OENDVjY3NmtFclpBNm1xTnFUWHY0a2RvUk5nYzdFcTkKV3BUUHc2eVRh MjczV2p5Sm5FSmRqaGNtcFUzLzJZUS9NWktVdkZLWXJhdVhCdnNTaWg0S1ZYZUtGT1ZmbzkyQQpn TUo1TVdHTkpmc3JjRW93ODlQamNxZ3dPbm1MOGdrWll0UmtLS2c0d0lVdmZIZzVQeDQ5aWRJeExv V29XY0xWCkNlaUliM2V3Q3JZZ2N5MVdlazNTNDJtV3lEbFo2OEFQRDNleEFpZGpwb2RqU3dVM3la V1dmRm4rQVZvc0Q3SXIKZVF2S09XZzdRakVsZVVwRE5ML2ZXVGhtcFBQbEJXU1k1dXI0WU5uZEUy UXFKZUcyWVNWcTJnaUxyRHhwbnFXbQowR0xRVkRpNm8zcGMydzJwaW1sbAo9alJBRAotLS0tLUVO RCBQR1AgU0lHTkFUVVJFLS0tLS0K --===============7307927719851920142==--