From mboxrd@z Thu Jan  1 00:00:00 1970
From: Michael Tremer <michael.tremer@ipfire.org>
To: development@lists.ipfire.org
Subject: Re: [PATCH] dnsmasq: 2.76test10 with latest patches (001-004)
Date: Sun, 28 Feb 2016 12:19:25 -0800
Message-ID: <1456690765.2371.10.camel@ipfire.org>
In-Reply-To: <1456507768-1796-1-git-send-email-matthias.fischer@ipfire.org>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="===============2142730740329272608=="
List-Id: <development.lists.ipfire.org>

--===============2142730740329272608==
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

Hi,

I merged this patch and the one after.

Please give this version a good test as it is a pre-release version.
You can maintain a branch where you integrate all new changes, but I
think it is not required to send every single one to the mailing list.
It creates a bit of noise and I think that unfortunately nobody is
testing every single one any ways. Which is sad.

Can we have maybe one aggregated patch after every release of a Core
Update? So we always have the latest version of dnsmasq in the updates?

Best,
-Michael

On Fri, 2016-02-26 at 18:29 +0100, Matthias Fischer wrote:
> This is 'dnsmasq 2.76test10', based on current 'next', containing
> latest patches.
>=20
> Signed-off-by: Matthias Fischer <matthias.fischer(a)ipfire.org>
> ---
> =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=A039 +-
> =C2=A0...TL_parameter_to_--host-record_and_--cname.patch |=C2=A0=C2=A0265 +=
++
> =C2=A0...01-include_0_0_0_0_8_in_DNS_rebind_checks.patch |=C2=A0=C2=A0=C2=
=A041 -
> =C2=A0.../dnsmasq/002-Add_--dhcp-ttl_option.patch=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0117 ++
> =C2=A0...subnet_to_allow_arbitary_subnet_addresses.patch |=C2=A0=C2=A0271 -=
--
> =C2=A0src/patches/dnsmasq/003-Update_CHANGELOG.patch=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0|=C2=A0=C2=A0=C2=A017 +
> =C2=A0...h_zones_locally_when_localise_queries_set.patch |=C2=A0=C2=A0=C2=
=A034 -
> =C2=A0.../dnsmasq/004-Add_--tftp-mtu_option.patch=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0136 ++
> =C2=A0.../004-fix_behaviour_of_empty_dhcp-option.patch=C2=A0=C2=A0=C2=A0|=
=C2=A0=C2=A0=C2=A038 -
> =C2=A0...ution_to_ENOMEM_error_with_IPv6_multicast.patch |=C2=A0=C2=A0=C2=
=A050 -
> =C2=A0...page_on_RDNSS_set_in_router_advertisement.patch |=C2=A0=C2=A0=C2=
=A035 -
> =C2=A0...gned_dangling_CNAME_replies_to_DS_queries.patch |=C2=A0=C2=A0=C2=
=A030 -
> =C2=A0...6_option_56_does_not_hold_an_address_list.patch |=C2=A0=C2=A0=C2=
=A025 -
> =C2=A0...pect_the_--no_resolv_flag_in_inotify_code.patch |=C2=A0=C2=A0=C2=
=A047 -
> =C2=A0..._5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch |=C2=A0=C2=A0=C2=
=A026 -
> =C2=A0...11-Catch_errors_from_sendmsg_in_DHCP_code.patch |=C2=A0=C2=A0=C2=
=A032 -
> =C2=A0...12-Update_list_of_subnet_for_--bogus-priv.patch |=C2=A0=C2=A0=C2=
=A048 -
> =C2=A0...y_address_from_DNS_overlays_A_record_from.patch |=C2=A0=C2=A0=C2=
=A043 -
> =C2=A0...14-Handle_unknown_DS_hash_algos_correctly.patch |=C2=A0=C2=A0=C2=
=A039 -
> =C2=A0.../015-Fix_crash_at_start_up_with_conf-dir.patch=C2=A0=C2=A0|=C2=A0=
=C2=A0=C2=A038 -
> =C2=A0...ajor_rationalisation_of_DNSSEC_validation.patch | 2209 ----------
> ----------
> =C2=A0...hing_RRSIGs_and_returning_them_from_cache.patch |=C2=A0=C2=A0612 -=
-----
> =C2=A0...caches_DS_records_to_a_more_logical_place.patch |=C2=A0=C2=A0269 -=
--
> =C2=A0...lise_RR-filtering_code_for_use_with_EDNS0.patch |=C2=A0=C2=A0755 -=
------
> =C2=A0.../dnsmasq/020-DNSSEC_validation_tweak.patch=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0|=C2=A0=C2=A0134 --
> =C2=A0...1-Tweaks_to_EDNS0_handling_in_DNS_replies.patch |=C2=A0=C2=A0133 --
> =C2=A0..._code_Check_zone_status_is_NSEC_proof_bad.patch |=C2=A0=C2=A0409 -=
---
> =C2=A0...023-Fix_brace_botch_in_dnssec_validate_ds.patch |=C2=A0=C2=A0=C2=
=A098 -
> =C2=A0...ning_which_DNSSEC_sig_algos_are_supported.patch |=C2=A0=C2=A0145 --
> =C2=A0...EDNS0_handling_and_computation_use_of_udp.patch |=C2=A0=C2=A0643 -=
-----
> =C2=A0...aks_in_handling_unknown_DNSSEC_algorithms.patch |=C2=A0=C2=A0262 -=
--
> =C2=A0...obscure_off-by-one_in_DNSSEC_hostname_cmp.patch |=C2=A0=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=A0=C2=A039 -
> =C2=A0.../dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch |=C2=A0=C2=A0=C2=
=A039 -
> =C2=A034 files changed, 542 insertions(+), 6603 deletions(-)
> =C2=A0create mode 100644 src/patches/dnsmasq/001-Add_TTL_parameter_to_
> --host-record_and_--cname.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/001-
> include_0_0_0_0_8_in_DNS_rebind_checks.patch
> =C2=A0create mode 100644 src/patches/dnsmasq/002-Add_--dhcp-
> ttl_option.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/002-
> enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
> =C2=A0create mode 100644 src/patches/dnsmasq/003-Update_CHANGELOG.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/003-
> dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que
> ries_set.patch
> =C2=A0create mode 100644 src/patches/dnsmasq/004-Add_--tftp-
> mtu_option.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/004-
> fix_behaviour_of_empty_dhcp-option.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/005-
> suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/006-
> clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/007-
> handle_signed_dangling_CNAME_replies_to_DS_queries.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/008-
> DHCPv6_option_56_does_not_hold_an_address_list.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/009-Respect_the_
> --no_resolv_flag_in_inotify_code.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/010-
> Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/011-
> Catch_errors_from_sendmsg_in_DHCP_code.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/012-
> Update_list_of_subnet_for_--bogus-priv.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/013-
> Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/014-
> Handle_unknown_DS_hash_algos_correctly.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/015-
> Fix_crash_at_start_up_with_conf-dir.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/016-
> Major_rationalisation_of_DNSSEC_validation.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/017-
> Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/018-
> Move_code_which_caches_DS_records_to_a_more_logical_place.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/019-Generalise_RR-
> filtering_code_for_use_with_EDNS0.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/020-
> DNSSEC_validation_tweak.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/021-
> Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-
> existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/023-
> Fix_brace_botch_in_dnssec_validate_ds.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/024-
> Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p
> atch
> =C2=A0delete mode 100644 src/patches/dnsmasq/025-
> Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/026-
> More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/027-
> Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/028-
> Minor_tweak_to_previous_commit.patch
> =C2=A0delete mode 100644 src/patches/dnsmasq/029-
> NSEC3_check_RFC5155_para_8_2.patch
>=20
> diff --git a/lfs/dnsmasq b/lfs/dnsmasq
> index 8058663..29d7895 100644
> --- a/lfs/dnsmasq
> +++ b/lfs/dnsmasq
> @@ -1,7 +1,7 @@
> =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=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# IPFire.org - A linux based
> firewall=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#
> -# Copyright (C) 2015=C2=A0=C2=A0Michael Tremer & Christian
> Schmidt=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#
> +# Copyright (C) 2016=C2=A0=C2=A0Michael Tremer & Christian
> Schmidt=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=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=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# This program is free software: you can redistribute it and/or
> modify=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0#
> =C2=A0# it under the terms of the GNU General Public License as published
> by=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0#
> @@ -24,7 +24,7 @@
> =C2=A0
> =C2=A0include Config
> =C2=A0
> -VER=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=3D 2.75
> +VER=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=3D 2.76test10
> =C2=A0
> =C2=A0THISAPP=C2=A0=C2=A0=C2=A0=C2=A0=3D dnsmasq-$(VER)
> =C2=A0DL_FILE=C2=A0=C2=A0=C2=A0=C2=A0=3D $(THISAPP).tar.xz
> @@ -43,7 +43,7 @@ objects =3D $(DL_FILE)
> =C2=A0
> =C2=A0$(DL_FILE) =3D $(DL_FROM)/$(DL_FILE)
> =C2=A0
> -$(DL_FILE)_MD5 =3D 887236f1ddde6eb57cdb9d01916c9f72
> +$(DL_FILE)_MD5 =3D 4b51474ed6081b18c61407077f254cf7
> =C2=A0
> =C2=A0install : $(TARGET)
> =C2=A0
> @@ -73,35 +73,10 @@ $(subst %,%_MD5,$(objects)) :
> =C2=A0$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
> =C2=A0	@$(PREBUILD)
> =C2=A0	@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf
> $(DIR_DL)/$(DL_FILE)
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/001-
> include_0_0_0_0_8_in_DNS_rebind_checks.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/002-
> enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/003-
> dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que
> ries_set.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-
> option.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/005-
> suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/006-
> clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/007-
> handle_signed_dangling_CNAME_replies_to_DS_queries.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/008-
> DHCPv6_option_56_does_not_hold_an_address_list.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/009-Respect_the_
> --no_resolv_flag_in_inotify_code.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/010-
> Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/011-
> Catch_errors_from_sendmsg_in_DHCP_code.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-
> priv.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/013-
> Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/014-
> Handle_unknown_DS_hash_algos_correctly.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-
> dir.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/016-
> Major_rationalisation_of_DNSSEC_validation.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/017-
> Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/018-
> Move_code_which_caches_DS_records_to_a_more_logical_place.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/019-Generalise_RR-
> filtering_code_for_use_with_EDNS0.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/021-
> Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> -	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
> -	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/023-
> Fix_brace_botch_in_dnssec_validate_ds.patch
> -	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
> +	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-
> record_and_--cname.patch
> +	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
> +	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/003-Update_CHANGELOG.patch
> +	cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/004-Add_--tftp-mtu_option.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/001-Add_TTL_parameter_to_--host-
> record_and_--cname.patch b/src/patches/dnsmasq/001-
> Add_TTL_parameter_to_--host-record_and_--cname.patch
> new file mode 100644
> index 0000000..86fbc9c
> --- /dev/null
> +++ b/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-
> record_and_--cname.patch
> @@ -0,0 +1,265 @@
> +From df3d54f776a3c9b60735b45c0b7fd88b66a2d5c4 Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Wed, 24 Feb 2016 21:03:38 +0000
> +Subject: [PATCH] Add TTL parameter to --host-record and --cname.
> +
> +---
> + man/dnsmasq.8 |=C2=A0=C2=A0=C2=A012 ++++++++++--
> + src/cache.c=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A07 +++++++
> + src/dnsmasq.h |=C2=A0=C2=A0=C2=A0=C2=A02 ++
> + src/option.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A046 +++++++++++++++++++++++++++=
+++++++++++--------
> + src/rfc1035.c |=C2=A0=C2=A0=C2=A0=C2=A06 +++++-
> + 5 files changed, 62 insertions(+), 11 deletions(-)
> +
> +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> +index b782eaf..7bc1394 100644
> +--- a/man/dnsmasq.8
> ++++ b/man/dnsmasq.8
> +@@ -529,7 +529,7 @@ zone files: the port, weight and priority
> numbers are in a different
> + order. More than one SRV record for a given service/domain is
> allowed,
> + all that match are returned.
> + .TP
> +-.B --host-record=3D<name>[,<name>....],[<IPv4-address>],[<IPv6-
> address>]
> ++.B --host-record=3D<name>[,<name>....],[<IPv4-address>],[<IPv6-
> address>][,<TTL>]
> + Add A, AAAA and PTR records to the DNS. This adds one or more names
> to
> + the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name
> may
> + appear in more than one=C2=A0
> +@@ -546,6 +546,10 @@ is in effect. Short and long names may appear
> in the same
> + .B host-record,
> + eg.=C2=A0
> + .B --host-record=3Dlaptop,laptop.thekelleys.org,192.168.0.1,1234::100
> ++
> ++If the time-to-live is given, it overrides the default, which is
> zero
> ++or the value of --local-ttl. The value is a positive integer and
> gives=C2=A0
> ++the time-to-live in seconds.
> + .TP
> + .B \-Y, --txt-record=3D<name>[[,<text>],<text>]
> + Return a TXT DNS record. The value of TXT record is a set of
> strings,
> +@@ -559,7 +563,7 @@ Return a PTR DNS record.
> + .B --naptr-
> record=3D<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<repla
> cement>]
> + Return an NAPTR DNS record, as specified in RFC3403.
> + .TP
> +-.B --cname=3D<cname>,<target>
> ++.B --cname=3D<cname>,<target>[,<TTL>]
> + Return a CNAME record which indicates that <cname> is really
> + <target>. There are significant limitations on the target; it must
> be a
> + DNS name which is known to dnsmasq from /etc/hosts (or additional
> +@@ -568,6 +572,10 @@ hosts files), from DHCP, from --interface-name
> or from another
> + If the target does not satisfy this
> + criteria, the whole cname is ignored. The cname must be unique, but
> it
> + is permissable to have more than one cname pointing to the same
> target.
> ++
> ++If the time-to-live is given, it overrides the default, which is
> zero
> ++or the value of -local-ttl. The value is a positive integer and
> gives=C2=A0
> ++the time-to-live in seconds.
> + .TP
> + .B --dns-rr=3D<name>,<RR-number>,[<hex data>]
> + Return an arbitrary DNS Resource Record. The number is the type of
> the
> +diff --git a/src/cache.c b/src/cache.c
> +index a9eaa65..4ecd535 100644
> +--- a/src/cache.c
> ++++ b/src/cache.c
> +@@ -778,6 +778,7 @@ static void add_hosts_cname(struct crec *target)
> +=C2=A0	(crec =3D whine_malloc(sizeof(struct crec))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> +=C2=A0	crec->flags =3D F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG |
> F_CNAME;
> ++	crec->ttd =3D a->ttl;
> +=C2=A0	crec->name.namep =3D a->alias;
> +=C2=A0	crec->addr.cname.target.cache =3D target;
> +=C2=A0	crec->addr.cname.uid =3D target->uid;
> +@@ -981,6 +982,7 @@ int read_hostsfile(char *filename, unsigned int
> index, int cache_size, struct cr
> +=C2=A0		=C2=A0=C2=A0strcat(cache->name.sname, ".");
> +=C2=A0		=C2=A0=C2=A0strcat(cache->name.sname, domain_suffix);
> +=C2=A0		=C2=A0=C2=A0cache->flags =3D flags;
> ++		=C2=A0=C2=A0cache->ttd =3D daemon->local_ttl;
> +=C2=A0		=C2=A0=C2=A0add_hosts_entry(cache, &addr, addrlen, index,
> rhash, hashsz);
> +=C2=A0		=C2=A0=C2=A0name_count++;
> +=C2=A0		}
> +@@ -988,6 +990,7 @@ int read_hostsfile(char *filename, unsigned int
> index, int cache_size, struct cr
> +=C2=A0		{
> +=C2=A0		=C2=A0=C2=A0strcpy(cache->name.sname, canon);
> +=C2=A0		=C2=A0=C2=A0cache->flags =3D flags;
> ++		=C2=A0=C2=A0cache->ttd =3D daemon->local_ttl;
> +=C2=A0		=C2=A0=C2=A0add_hosts_entry(cache, &addr, addrlen, index,
> rhash, hashsz);
> +=C2=A0		=C2=A0=C2=A0name_count++;
> +=C2=A0		}
> +@@ -1057,6 +1060,7 @@ void cache_reload(void)
> +=C2=A0	=C2=A0=C2=A0((cache =3D whine_malloc(sizeof(struct crec)))))
> +=C2=A0	{
> +=C2=A0	=C2=A0=C2=A0cache->flags =3D F_FORWARD | F_NAMEP | F_CNAME | F_IMMO=
RTAL
> | F_CONFIG;
> ++	=C2=A0=C2=A0cache->ttd =3D a->ttl;
> +=C2=A0	=C2=A0=C2=A0cache->name.namep =3D a->alias;
> +=C2=A0	=C2=A0=C2=A0cache->addr.cname.target.int_name =3D intr;
> +=C2=A0	=C2=A0=C2=A0cache->addr.cname.uid =3D SRC_INTERFACE;
> +@@ -1071,6 +1075,7 @@ void cache_reload(void)
> +=C2=A0	(cache->addr.ds.keydata =3D blockdata_alloc(ds->digest, ds-
> >digestlen)))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> +=C2=A0	cache->flags =3D F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG |
> F_NAMEP;
> ++	cache->ttd =3D daemon->local_ttl;
> +=C2=A0	cache->name.namep =3D ds->name;
> +=C2=A0	cache->addr.ds.keylen =3D ds->digestlen;
> +=C2=A0	cache->addr.ds.algo =3D ds->algo;
> +@@ -1095,6 +1100,7 @@ void cache_reload(void)
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0(cache =3D whine_malloc(sizeof(struct crec)=
)))
> +=C2=A0	=C2=A0=C2=A0{
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0cache->name.namep =3D nl->name;
> ++	=C2=A0=C2=A0=C2=A0=C2=A0cache->ttd =3D hr->ttl;
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0cache->flags =3D F_HOSTS | F_IMMORTAL | F_F=
ORWARD |
> F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0add_hosts_entry(cache, (struct all_addr *)&=
hr->addr,
> INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
> +=C2=A0	=C2=A0=C2=A0}
> +@@ -1103,6 +1109,7 @@ void cache_reload(void)
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0(cache =3D whine_malloc(sizeof(struct crec)=
)))
> +=C2=A0	=C2=A0=C2=A0{
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0cache->name.namep =3D nl->name;
> ++	=C2=A0=C2=A0=C2=A0=C2=A0cache->ttd =3D hr->ttl;
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0cache->flags =3D F_HOSTS | F_IMMORTAL | F_F=
ORWARD |
> F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0add_hosts_entry(cache, (struct all_addr *)&=
hr->addr6,
> IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
> +=C2=A0	=C2=A0=C2=A0}
> +diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> +index 6d1c5ae..6344df5 100644
> +--- a/src/dnsmasq.h
> ++++ b/src/dnsmasq.h
> +@@ -308,6 +308,7 @@ struct ptr_record {
> + };
> +=C2=A0
> + struct cname {
> ++=C2=A0=C2=A0int ttl;
> +=C2=A0=C2=A0=C2=A0char *alias, *target;
> +=C2=A0=C2=A0=C2=A0struct cname *next;
> + };=C2=A0
> +@@ -344,6 +345,7 @@ struct auth_zone {
> +=C2=A0
> +=C2=A0
> + struct host_record {
> ++=C2=A0=C2=A0int ttl;
> +=C2=A0=C2=A0=C2=A0struct name_list {
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *name;
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct name_list *next;
> +diff --git a/src/option.c b/src/option.c
> +index c98bdc9..7c5e6bc 100644
> +--- a/src/option.c
> ++++ b/src/option.c
> +@@ -448,20 +448,20 @@ static struct {
> +=C2=A0=C2=A0=C2=A0{ LOPT_GEN_NAMES, ARG_DUP, "[=3Dtag:<tag>]", gettext_noo=
p("Generate
> hostnames based on MAC address for nameless clients."), NULL},
> +=C2=A0=C2=A0=C2=A0{ LOPT_PROXY, ARG_DUP, "[=3D<ipaddr>]...", gettext_noop(=
"Use these
> DHCP relays as full proxies."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interfac=
e>]",
> gettext_noop("Relay DHCP requests to a remote server"), NULL},
> +-=C2=A0=C2=A0{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Spec=
ify
> alias name for LOCAL DNS name."), NULL },
> ++=C2=A0=C2=A0{ LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]",
> gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]",
> gettext_noop("Prompt to send to PXE clients."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boo=
t service
> for PXE menu."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration
> syntax."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_ADD_MAC, ARG_DUP, "[=3Dbase64|text]", gettext_noo=
p("Add
> requestor's MAC address to forwarded DNS queries."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]",
> gettext_noop("Add specified IP subnet to forwarded DNS queries."),
> NULL },
> +-=C2=A0=C2=A0=C2=A0{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add cli=
ent
> identification to forwarded DNS queries."), NULL },
> ++=C2=A0=C2=A0{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client
> identification to forwarded DNS queries."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Pro=
xy DNSSEC
> validation results from upstream nameservers."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("A=
ttempt to
> allocate sequential IP addresses to DHCP clients."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy
> connection-track mark from queries to upstream connections."), NULL
> },
> +=C2=A0=C2=A0=C2=A0{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow =
DHCP
> clients to do their own DDNS updates."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-adver=
tisements=20
> for interfaces doing DHCPv6"), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>",
> gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
> +-=C2=A0=C2=A0{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>",
> gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
> ++=C2=A0=C2=A0{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]",
> gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]",
> gettext_noop("Specify arbitrary DNS resource record"), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bi=
nd to
> interfaces in use - check for new interfaces"), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>",
> gettext_noop("Export local names to global DNS"), NULL },
> +@@ -3692,12 +3692,15 @@ static int one_opt(int option, char *arg,
> char *errstr, char *gen_err, int comma
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_CNAME: /* --cname */
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> +=C2=A0	struct cname *new;
> +-	char *alias;
> +-	char *target;
> ++	char *alias, *target, *ttls;
> ++	int ttl =3D -1;
> +=C2=A0
> +=C2=A0	if (!(comma =3D split(arg)))
> +=C2=A0	=C2=A0=C2=A0ret_err(gen_err);
> +=C2=A0=09
> ++	if ((ttls =3D split(comma)) && !atoi_check(ttls, &ttl))
> ++	=C2=A0=C2=A0ret_err(_("bad TTL"));
> ++=09
> +=C2=A0	alias =3D canonicalise_opt(arg);
> +=C2=A0	target =3D canonicalise_opt(comma);
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> +@@ -3713,6 +3716,7 @@ static int one_opt(int option, char *arg, char
> *errstr, char *gen_err, int comma
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0daemon->cnames =3D new;
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0new->alias =3D alias;
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0new->target =3D target;
> ++	=C2=A0=C2=A0=C2=A0=C2=A0new->ttl =3D ttl;
> +=C2=A0	=C2=A0=C2=A0}
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> +=C2=A0	break;
> +@@ -3913,14 +3917,22 @@ static int one_opt(int option, char *arg,
> char *errstr, char *gen_err, int comma
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> +=C2=A0	struct host_record *new =3D opt_malloc(sizeof(struct
> host_record));
> +=C2=A0	memset(new, 0, sizeof(struct host_record));
> +-=09
> ++	new->ttl =3D -1;
> ++
> +=C2=A0	if (!arg || !(comma =3D split(arg)))
> +=C2=A0	=C2=A0=C2=A0ret_err(_("Bad host-record"));
> +=C2=A0=09
> +=C2=A0	while (arg)
> +=C2=A0	=C2=A0=C2=A0{
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr addr;
> +-	=C2=A0=C2=A0=C2=A0=C2=A0if (inet_pton(AF_INET, arg, &addr))
> ++	=C2=A0=C2=A0=C2=A0=C2=A0char *dig;
> ++
> ++	=C2=A0=C2=A0=C2=A0=C2=A0for (dig =3D arg; *dig !=3D 0; dig++)
> ++	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (*dig < '0' || *dig > '9')
> ++		break;
> ++	=C2=A0=C2=A0=C2=A0=C2=A0if (*dig =3D=3D 0)
> ++	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->ttl =3D atoi(arg);
> ++	=C2=A0=C2=A0=C2=A0=C2=A0else if (inet_pton(AF_INET, arg, &addr))
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->addr =3D addr.addr.addr4;
> + #ifdef HAVE_IPV6
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0else if (inet_pton(AF_INET6, arg, &addr))
> +@@ -4601,7 +4613,25 @@ void read_opts(int argc, char **argv, char
> *compile_opts)
> +=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=A0if (daemon->host_records)
> ++=C2=A0=C2=A0=C2=A0=C2=A0{
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct host_record *hr;
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (hr =3D daemon->host_records; hr;=
 hr =3D hr->next)
> ++	if (hr->ttl =3D=3D -1)
> ++	=C2=A0=C2=A0hr->ttl =3D daemon->local_ttl;
> ++=C2=A0=C2=A0=C2=A0=C2=A0}
> ++
> ++=C2=A0=C2=A0if (daemon->cnames)
> ++=C2=A0=C2=A0=C2=A0=C2=A0{
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct cname *cn;
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (cn =3D daemon->cnames; cn; cn =
=3D cn->next)
> ++	if (cn->ttl =3D=3D -1)
> ++	=C2=A0=C2=A0cn->ttl =3D daemon->local_ttl;
> ++=C2=A0=C2=A0=C2=A0=C2=A0}
> ++
> +=C2=A0=C2=A0=C2=A0if (daemon->if_addrs)
> +=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=A0struct iname *tmp;
> +diff --git a/src/rfc1035.c b/src/rfc1035.c
> +index 9c0ddb5..3535a71 100644
> +--- a/src/rfc1035.c
> ++++ b/src/rfc1035.c
> +@@ -1169,9 +1169,13 @@ static unsigned long crec_ttl(struct crec
> *crecp, time_t now)
> +=C2=A0=C2=A0=C2=A0/* Return 0 ttl for DHCP entries, which might change
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0before the lease expires. */
> +=C2=A0
> +-=C2=A0=C2=A0if=C2=A0=C2=A0(crecp->flags & (F_IMMORTAL | F_DHCP))
> ++=C2=A0=C2=A0if (crecp->flags & F_DHCP)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return daemon->local_ttl;
> +=C2=A0=C2=A0=C2=A0
> ++=C2=A0=C2=A0/* Immortal entries other than DHCP are local, and hold TTL in
> TTD field. */
> ++=C2=A0=C2=A0if (crecp->flags & F_IMMORTAL)
> ++=C2=A0=C2=A0=C2=A0=C2=A0return crecp->ttd;
> ++
> +=C2=A0=C2=A0=C2=A0/* Return the Max TTL value if it is lower then the actu=
al TTL */
> +=C2=A0=C2=A0=C2=A0if (daemon->max_ttl =3D=3D 0 || ((unsigned)(crecp->ttd -=
 now) <
> daemon->max_ttl))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return crecp->ttd - now;
> +--=C2=A0
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/001-
> include_0_0_0_0_8_in_DNS_rebind_checks.patch
> b/src/patches/dnsmasq/001-
> include_0_0_0_0_8_in_DNS_rebind_checks.patch
> deleted file mode 100644
> index 8a2557a..0000000
> --- a/src/patches/dnsmasq/001-
> include_0_0_0_0_8_in_DNS_rebind_checks.patch
> +++ /dev/null
> @@ -1,41 +0,0 @@
> -From d2aa7dfbb6d1088dcbea9fecc61b9293b320eb95 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Mon, 3 Aug 2015 21:52:12 +0100
> -Subject: [PATCH] Include 0.0.0.0/8 in DNS rebind checks.
> -
> ----
> - CHANGELOG=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A07 +++++++
> - src/rfc1035.c |=C2=A0=C2=A0=C2=A0=C2=A03 ++-
> - 2 files changed, 9 insertions(+), 1 deletion(-)
> -
> -diff --git a/CHANGELOG b/CHANGELOG
> -index 901da47..3f4026d 100644
> ---- a/CHANGELOG
> -+++ b/CHANGELOG
> -@@ -1,3 +1,10 @@
> -+version 2.76
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0I=
nclude 0.0.0.0/8 in DNS rebind checks. This range=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0translates to hosts on=C2=A0=C2=A0the local netw=
ork, or, at=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0least, 0.0.0.0 accesses the local host, so could
> -+	=C2=A0=C2=A0=C2=A0=C2=A0be targets for DNS rebinding. See RFC 5735 secti=
on 3=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0for details. Thanks to Stephen R=C3=83=C2=B6ttge=
r for the bug
> report.
> -+	=C2=A0=C2=A0=C2=A0=C2=A0
> - version 2.75
> -=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=A0Fix reversion on 2.74 which caused 100% CPU use when a=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0dhcp-script is configured. Thanks to Adrian=
 Davey for
> -diff --git a/src/rfc1035.c b/src/rfc1035.c
> -index 56647b0..29e9e65 100644
> ---- a/src/rfc1035.c
> -+++ b/src/rfc1035.c
> -@@ -728,7 +728,8 @@ int private_net(struct in_addr addr, int
> ban_localhost)
> -=C2=A0=C2=A0=C2=A0in_addr_t ip_addr =3D ntohl(addr.s_addr);
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0return
> --=C2=A0=C2=A0=C2=A0=C2=A0(((ip_addr & 0xFF000000) =3D=3D 0x7F000000) && ba=
n_localhost)=C2=A0=C2=A0/*
> 127.0.0.0/8=C2=A0=C2=A0=C2=A0=C2=A0(loopback) */ ||=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0(((ip_addr & 0xFF000000) =3D=3D 0x7F000000) && ba=
n_localhost)=C2=A0=C2=A0/*
> 127.0.0.0/8=C2=A0=C2=A0=C2=A0=C2=A0(loopback) */ ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFF000000) =3D=3D 0x00000000)=C2=A0=
=C2=A0/* RFC 5735 section 3.
> "here" network */ ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFF0000) =3D=3D 0xC0A80000)=
=C2=A0=C2=A0/* 192.168.0.0/16
> (private)=C2=A0=C2=A0*/ ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFF000000) =3D=3D 0x0A000000)=
=C2=A0=C2=A0/*
> 10.0.0.0/8=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(private)=C2=A0=C2=A0*/ ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFF00000) =3D=3D 0xAC100000)=
=C2=A0=C2=A0/*
> 172.16.0.0/12=C2=A0=C2=A0(private)=C2=A0=C2=A0*/ ||
> ---=C2=A0
> -1.7.10.4
> diff --git a/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
> b/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
> new file mode 100644
> index 0000000..45e3b9b
> --- /dev/null
> +++ b/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
> @@ -0,0 +1,117 @@
> +From 832e47beab95c2918b5264f0504f2fe6fe523e4c Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Wed, 24 Feb 2016 21:24:45 +0000
> +Subject: [PATCH] Add --dhcp-ttl option.
> +
> +---
> + man/dnsmasq.8 |=C2=A0=C2=A0=C2=A0=C2=A05 ++++-
> + src/dnsmasq.h |=C2=A0=C2=A0=C2=A0=C2=A02 +-
> + src/option.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A013 +++++++++++--
> + src/rfc1035.c |=C2=A0=C2=A0=C2=A0=C2=A02 +-
> + 4 files changed, 17 insertions(+), 5 deletions(-)
> +
> +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> +index 7bc1394..2bcce20 100644
> +--- a/man/dnsmasq.8
> ++++ b/man/dnsmasq.8
> +@@ -60,7 +60,7 @@ in the same way as for DHCP-derived names. Note
> that this does not
> + apply to domain names in cnames, PTR records, TXT records etc.
> + .TP
> + .B \-T, --local-ttl=3D<time>
> +-When replying with information from /etc/hosts or the DHCP leases
> ++When replying with information from /etc/hosts or configuration or
> the DHCP leases
> + file dnsmasq by default sets the time-to-live field to zero,
> meaning
> + that the requester should not itself cache the information. This is
> + the correct thing to do in almost all situations. This option
> allows a
> +@@ -68,6 +68,9 @@ time-to-live (in seconds) to be given for these
> replies. This will
> + reduce the load on the server at the expense of clients using stale
> + data under some circumstances.
> + .TP
> ++.B --dhcp-ttl=3D<time>
> ++As for --local-ttl, but affects only replies with information from
> DHCP leases. If both are given, --dhcp-ttl applies for DHCP
> information, and --local-ttl for others. Setting this to zero
> eliminates the effect of --local-ttl for DHCP.
> ++.TP
> + .B --neg-ttl=3D<time>
> + Negative replies from upstream servers normally contain time-to-
> live
> + information in SOA records which dnsmasq uses for caching. If the
> +diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> +index 6344df5..9f73c3b 100644
> +--- a/src/dnsmasq.h
> ++++ b/src/dnsmasq.h
> +@@ -955,7 +955,7 @@ extern struct daemon {
> +=C2=A0=C2=A0=C2=A0int max_logs;=C2=A0=C2=A0/* queue limit */
> +=C2=A0=C2=A0=C2=A0int cachesize, ftabsize;
> +=C2=A0=C2=A0=C2=A0int port, query_port, min_port, max_port;
> +-=C2=A0=C2=A0unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl,
> max_cache_ttl, auth_ttl;
> ++=C2=A0=C2=A0unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl,
> max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
> +=C2=A0=C2=A0=C2=A0char *dns_client_id;
> +=C2=A0=C2=A0=C2=A0struct hostsfile *addn_hosts;
> +=C2=A0=C2=A0=C2=A0struct dhcp_context *dhcp, *dhcp6;
> +diff --git a/src/option.c b/src/option.c
> +index 7c5e6bc..3f6d162 100644
> +--- a/src/option.c
> ++++ b/src/option.c
> +@@ -157,6 +157,7 @@ struct myoption {
> + #define LOPT_MAXPORT=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0345
> + #define LOPT_CPE_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0346
> + #define LOPT_SCRIPT_ARP=C2=A0=C2=A0=C2=A0=C2=A0347
> ++#define LOPT_DHCPTTL=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0348
> +=C2=A0
> + #ifdef HAVE_GETOPT_LONG
> + static const struct option opts[] =3D=C2=A0=C2=A0
> +@@ -319,6 +320,7 @@ static const struct myoption opts[] =3D
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "quiet-ra", 0, 0, LOPT_QUIET_RA },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT =
},
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
> ++=C2=A0=C2=A0=C2=A0=C2=A0{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ NULL, 0, 0, 0 }
> +=C2=A0=C2=A0=C2=A0};
> +=C2=A0
> +@@ -485,9 +487,10 @@ static struct {
> +=C2=A0=C2=A0=C2=A0{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("D=
o not log
> routine DHCP."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop(=
"Do not
> log routine DHCPv6."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do no=
t log
> RA."), NULL },
> +-=C2=A0=C2=A0{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL,
> gettext_noop("Accept queries only from directly-connected networks"),
> NULL },
> +-=C2=A0=C2=A0{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Dete=
ct
> and remove DNS forwarding loops"), NULL },
> ++=C2=A0=C2=A0{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL,
> gettext_noop("Accept queries only from directly-connected
> networks."), NULL },
> ++=C2=A0=C2=A0{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Dete=
ct
> and remove DNS forwarding loops."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("I=
gnore DNS
> responses containing ipaddr."), NULL },=C2=A0
> ++=C2=A0=C2=A0{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS
> responses with DHCP-derived addresses."), NULL },=C2=A0
> +=C2=A0=C2=A0=C2=A0{ 0, 0, NULL, NULL, NULL }
> + };=C2=A0
> +=C2=A0
> +@@ -2580,6 +2583,7 @@ static int one_opt(int option, char *arg, char
> *errstr, char *gen_err, int comma
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_MINCTTL: /* --min-cache-ttl */
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_MAXCTTL: /* --max-cache-ttl */
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_AUTHTTL: /* --auth-ttl */
> ++=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_DHCPTTL: /* --dhcp-ttl */
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> +=C2=A0	int ttl;
> +=C2=A0	if (!atoi_check(arg, &ttl))
> +@@ -2598,6 +2602,11 @@ static int one_opt(int option, char *arg,
> char *errstr, char *gen_err, int comma
> +=C2=A0	=C2=A0=C2=A0daemon->max_cache_ttl =3D (unsigned long)ttl;
> +=C2=A0	else if (option =3D=3D LOPT_AUTHTTL)
> +=C2=A0	=C2=A0=C2=A0daemon->auth_ttl =3D (unsigned long)ttl;
> ++	else if (option =3D=3D LOPT_DHCPTTL)
> ++	=C2=A0=C2=A0{
> ++	=C2=A0=C2=A0=C2=A0=C2=A0daemon->dhcp_ttl =3D (unsigned long)ttl;
> ++	=C2=A0=C2=A0=C2=A0=C2=A0daemon->use_dhcp_ttl =3D 1;
> ++	=C2=A0=C2=A0}
> +=C2=A0	else
> +=C2=A0	=C2=A0=C2=A0daemon->local_ttl =3D (unsigned long)ttl;
> +=C2=A0	break;
> +diff --git a/src/rfc1035.c b/src/rfc1035.c
> +index 3535a71..8f1e3b4 100644
> +--- a/src/rfc1035.c
> ++++ b/src/rfc1035.c
> +@@ -1170,7 +1170,7 @@ static unsigned long crec_ttl(struct crec
> *crecp, time_t now)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0before the lease expires. */
> +=C2=A0
> +=C2=A0=C2=A0=C2=A0if (crecp->flags & F_DHCP)
> +-=C2=A0=C2=A0=C2=A0=C2=A0return daemon->local_ttl;
> ++=C2=A0=C2=A0=C2=A0=C2=A0return daemon->use_dhcp_ttl ? daemon->dhcp_ttl : =
daemon-
> >local_ttl;
> +=C2=A0=C2=A0=C2=A0
> +=C2=A0=C2=A0=C2=A0/* Immortal entries other than DHCP are local, and hold =
TTL in
> TTD field. */
> +=C2=A0=C2=A0=C2=A0if (crecp->flags & F_IMMORTAL)
> +--=C2=A0
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/002-
> enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
> b/src/patches/dnsmasq/002-
> enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
> deleted file mode 100644
> index 2d3d6e4..0000000
> --- a/src/patches/dnsmasq/002-
> enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
> +++ /dev/null
> @@ -1,271 +0,0 @@
> -From a7369bef8abd241c3d85633fa9c870943f091e76 Mon Sep 17 00:00:00
> 2001
> -From: Ed Bardsley <ebardsley(a)google.com>
> -Date: Wed, 5 Aug 2015 21:17:18 +0100
> -Subject: [PATCH] Enhance --add-subnet to allow arbitary subnet
> addresses.
> -
> ----
> - CHANGELOG=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A04 ++++
> - man/dnsmasq.8 |=C2=A0=C2=A0=C2=A032 ++++++++++++++++++++-----------
> - src/dnsmasq.h |=C2=A0=C2=A0=C2=A013 ++++++++++---
> - src/option.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A059
> ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> - src/rfc1035.c |=C2=A0=C2=A0=C2=A039 +++++++++++++++++++++++++++++++-------
> - 5 files changed, 121 insertions(+), 26 deletions(-)
> -
> -diff --git a/CHANGELOG b/CHANGELOG
> -index 3f4026d..bbc2834 100644
> ---- a/CHANGELOG
> -+++ b/CHANGELOG
> -@@ -4,6 +4,10 @@ version 2.76
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0least, 0.0.0.0 accesses the local host, so =
could
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0be targets for DNS rebinding. See RFC 5735 =
section 3=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0for details. Thanks to Stephen R=C3=83=C2=
=B6ttger for the bug
> report.
> -+
> -+	=C2=A0=C2=A0=C2=A0=C2=A0Enhance --add-subnet to allow arbitrary subnet
> addresses.
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T=
hanks to Ed Barsley for the patch.
> -+=09
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> - version 2.75
> -=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=A0Fix reversion on 2.74 which caused 100% CPU use when a=C2=A0
> -diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> -index c8913b5..a23c898 100644
> ---- a/man/dnsmasq.8
> -+++ b/man/dnsmasq.8
> -@@ -604,17 +604,27 @@ experimental. Also note that exposing MAC
> addresses in this way may
> - have security and privacy implications. The warning about caching
> - given for --add-subnet applies to --add-mac too.
> - .TP=C2=A0
> --.B --add-subnet[[=3D<IPv4 prefix length>],<IPv6 prefix length>]
> --Add the subnet address of the requestor to the DNS queries which
> are
> --forwarded upstream. The amount of the address forwarded depends on
> the
> --prefix length parameter: 32 (128 for IPv6) forwards the whole
> address,
> --zero forwards none of it but still marks the request so that no
> --upstream nameserver will add client address information either. The
> --default is zero for both IPv4 and IPv6. Note that upstream
> nameservers
> --may be configured to return different results based on this
> --information, but the dnsmasq cache does not take account. If a
> dnsmasq
> --instance is configured such that different results may be
> encountered,
> --caching should be disabled.
> -+.B --add-subnet[[=3D[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6
> address>/]<IPv6 prefix length>]]
> -+Add a subnet address to the DNS queries which are forwarded
> -+upstream. If an address is specified in the flag, it will be used,
> -+otherwise, the address of the requestor will be used. The amount of
> -+the address forwarded depends on the prefix length parameter: 32
> (128
> -+for IPv6) forwards the whole address, zero forwards none of it but
> -+still marks the request so that no upstream nameserver will add
> client
> -+address information either. The default is zero for both IPv4 and
> -+IPv6. Note that upstream nameservers may be configured to return
> -+different results based on this information, but the dnsmasq cache
> -+does not take account. If a dnsmasq instance is configured such
> that
> -+different results may be encountered, caching should be disabled.
> -+
> -+For example,
> -+.B --add-subnet=3D24,96
> -+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6
> requestors, respectively.
> -+.B --add-subnet=3D1.2.3.4/24
> -+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6
> requestors.
> -+.B --add-subnet=3D1.2.3.4/24,1.2.3.4/24
> -+will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
> -+
> - .TP
> - .B \-c, --cache-size=3D<cachesize>
> - Set the size of dnsmasq's cache. The default is 150 names. Setting
> the cache size to zero disables caching.
> -diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> -index cf1a782..f42acdb 100644
> ---- a/src/dnsmasq.h
> -+++ b/src/dnsmasq.h
> -@@ -541,6 +541,13 @@ struct iname {
> -=C2=A0=C2=A0=C2=A0struct iname *next;
> - };
> -=C2=A0
> -+/* subnet parameters from command line */
> -+struct mysubnet {
> -+=C2=A0=C2=A0union mysockaddr addr;
> -+=C2=A0=C2=A0int addr_used;
> -+=C2=A0=C2=A0int mask;
> -+};
> -+
> - /* resolv-file parms from command-line */
> - struct resolvc {
> -=C2=A0=C2=A0=C2=A0struct resolvc *next;
> -@@ -935,9 +942,9 @@ extern struct daemon {
> -=C2=A0=C2=A0=C2=A0struct auth_zone *auth_zones;
> -=C2=A0=C2=A0=C2=A0struct interface_name *int_names;
> -=C2=A0=C2=A0=C2=A0char *mxtarget;
> --=C2=A0=C2=A0int addr4_netmask;
> --=C2=A0=C2=A0int addr6_netmask;
> --=C2=A0=C2=A0char *lease_file;=C2=A0
> -+=C2=A0=C2=A0struct mysubnet *add_subnet4;
> -+=C2=A0=C2=A0struct mysubnet *add_subnet6;
> -+=C2=A0=C2=A0char *lease_file;
> -=C2=A0=C2=A0=C2=A0char *username, *groupname, *scriptuser;
> -=C2=A0=C2=A0=C2=A0char *luascript;
> -=C2=A0=C2=A0=C2=A0char *authserver, *hostmaster;
> -diff --git a/src/option.c b/src/option.c
> -index ecc2619..746cd11 100644
> ---- a/src/option.c
> -+++ b/src/option.c
> -@@ -445,7 +445,7 @@ static struct {
> -=C2=A0=C2=A0=C2=A0{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boo=
t service
> for PXE menu."), NULL },
> -=C2=A0=C2=A0=C2=A0{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration
> syntax."), NULL },
> -=C2=A0=C2=A0=C2=A0{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add req=
uestor's
> MAC address to forwarded DNS queries."), NULL },
> --=C2=A0=C2=A0{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]",
> gettext_noop("Add requestor's IP subnet to forwarded DNS queries."),
> NULL },
> -+=C2=A0=C2=A0{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]",
> gettext_noop("Add specified IP subnet to forwarded DNS queries."),
> NULL },
> -=C2=A0=C2=A0=C2=A0{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Pro=
xy DNSSEC
> validation results from upstream nameservers."), NULL },
> -=C2=A0=C2=A0=C2=A0{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("A=
ttempt to
> allocate sequential IP addresses to DHCP clients."), NULL },
> -=C2=A0=C2=A0=C2=A0{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy
> connection-track mark from queries to upstream connections."), NULL
> },
> -@@ -722,6 +722,20 @@ static void do_usage(void)
> -=C2=A0
> - #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
> -=C2=A0
> -+static char *parse_mysockaddr(char *arg, union mysockaddr *addr)=C2=A0
> -+{
> -+=C2=A0=C2=A0if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
> -+=C2=A0=C2=A0=C2=A0=C2=A0addr->sa.sa_family =3D AF_INET;
> -+#ifdef HAVE_IPV6
> -+=C2=A0=C2=A0else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
> -+=C2=A0=C2=A0=C2=A0=C2=A0addr->sa.sa_family =3D AF_INET6;
> -+#endif
> -+=C2=A0=C2=A0else
> -+=C2=A0=C2=A0=C2=A0=C2=A0return _("bad address");
> -+=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0return NULL;
> -+}
> -+
> - char *parse_server(char *arg, union mysockaddr *addr, union
> mysockaddr *source_addr, char *interface, int *flags)
> - {
> -=C2=A0=C2=A0=C2=A0int source_port =3D 0, serv_port =3D NAMESERVER_PORT;
> -@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char
> *errstr, char *gen_err, int comma
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0li =3D match_suffix->next;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0free(match_suffix->suffix);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0free(match_suffix);
> --	=C2=A0=C2=A0}=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0}
> -=C2=A0	break;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> -@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg,
> char *errstr, char *gen_err, int comma
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0set_option_bool(OPT_CLIENT_SUBNE=
T);
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (arg)
> -=C2=A0	{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *err, *e=
nd;
> -=C2=A0	=C2=A0=C2=A0comma =3D split(arg);
> --	=C2=A0=C2=A0if (!atoi_check(arg, &daemon->addr4_netmask) ||=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(comma && !atoi_check(comma, &daemon-
> >addr6_netmask)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ret_err(gen_err);
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct mysubn=
et* new =3D opt_malloc(sizeof(struct
> mysubnet));
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((end =3D =
split_chr(arg, '/')))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* has subnet+len */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D parse_mysockaddr(arg, &new->=
addr);
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (err)
> -+		ret_err(err);
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!atoi_check(end, &new->mask))
> -+		ret_err(gen_err);
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->addr_used =3D 1;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> -+	=C2=A0=C2=A0else if (!atoi_check(arg, &new->mask))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0ret_err(gen_err);
> -+	=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=A0daemon->add_s=
ubnet4 =3D new;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new =3D opt_m=
alloc(sizeof(struct mysubnet));
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (comma)
> -+=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=A0if ((end =3D split_chr(comma, '/')))
> -+=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/* has subnet+len */
> -+=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=A0err =3D parse_mysockaddr(comma, &new->add=
r);
> -+=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=A0if (err)
> -+=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=A0ret_err(err);
> -+=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=A0if (!atoi_check(end, &new->mask))
> -+=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=A0ret_err(gen_err);
> -+=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=A0new->addr_used =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=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=A0else
> -+=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=A0if (!atoi_check(comma, &new->mask))
> -+=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=A0ret_err(gen_err);
> -+=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=A0daemon->add_s=
ubnet6 =3D new;
> -=C2=A0	}
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> -=C2=A0
> -diff --git a/src/rfc1035.c b/src/rfc1035.c
> -index 29e9e65..6a51b30 100644
> ---- a/src/rfc1035.c
> -+++ b/src/rfc1035.c
> -@@ -629,26 +629,47 @@ struct subnet_opt {
> - #endif
> - };
> -=C2=A0
> -+static void *get_addrp(union mysockaddr *addr, const short family)=C2=A0
> -+{
> -+#ifdef HAVE_IPV6
> -+=C2=A0=C2=A0if (family =3D=3D AF_INET6)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return &addr->in6.sin6_addr;
> -+#endif
> -+
> -+=C2=A0=C2=A0return &addr->in.sin_addr;
> -+}
> -+
> - static size_t calc_subnet_opt(struct subnet_opt *opt, union
> mysockaddr *source)
> - {
> -=C2=A0=C2=A0=C2=A0/* http://tools.ietf.org/html/draft-vandergaast-edns-cli=
ent-subne
> t-02 */
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0int len;
> -=C2=A0=C2=A0=C2=A0void *addrp;
> -+=C2=A0=C2=A0int sa_family =3D source->sa.sa_family;
> -=C2=A0
> - #ifdef HAVE_IPV6
> -=C2=A0=C2=A0=C2=A0if (source->sa.sa_family =3D=3D AF_INET6)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->family =3D htons(2);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->source_netmask =3D daemon->addr6=
_netmask;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0addrp =3D &source->in6.sin6_addr;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->source_netmask =3D daemon->add_s=
ubnet6->mask;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (daemon->add_subnet6->addr_used)=
=C2=A0
> -+	{
> -+	=C2=A0=C2=A0sa_family =3D daemon->add_subnet6->addr.sa.sa_family;
> -+	=C2=A0=C2=A0addrp =3D get_addrp(&daemon->add_subnet6->addr, sa_family);
> -+	}=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> -+	addrp =3D &source->in6.sin6_addr;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=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=A0opt->family =3D htons(1);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->source_netmask =3D daemon->addr4=
_netmask;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0addrp =3D &source->in.sin_addr;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->source_netmask =3D daemon->add_s=
ubnet4->mask;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (daemon->add_subnet4->addr_used)
> -+	{
> -+	=C2=A0=C2=A0sa_family =3D daemon->add_subnet4->addr.sa.sa_family;
> -+	=C2=A0=C2=A0addrp =3D get_addrp(&daemon->add_subnet4->addr, sa_family);
> -+	}=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> -+	addrp =3D &source->in.sin_addr;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0opt->scope_netmask =3D 0;
> -@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt
> *opt, union mysockaddr *source)
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (opt->source_netmask !=3D 0)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+#ifdef HAVE_IPV6
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->family =3D htons(sa_family =3D=
=3D AF_INET6 ? 2 : 1);
> -+#else
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0opt->family =3D htons(1);
> -+#endif
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0len =3D ((opt->source_netmask - =
1) >> 3) + 1;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0memcpy(opt->addr, addrp, len);
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (opt->source_netmask & 7)
> -@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0return len;
> - }
> --
> ---=C2=A0
> -1.7.10.4
> diff --git a/src/patches/dnsmasq/003-Update_CHANGELOG.patch
> b/src/patches/dnsmasq/003-Update_CHANGELOG.patch
> new file mode 100644
> index 0000000..f04f943
> --- /dev/null
> +++ b/src/patches/dnsmasq/003-Update_CHANGELOG.patch
> @@ -0,0 +1,17 @@
> +X-Git-Url: http://thekelleys.org.uk/gitweb/?p=3Ddnsmasq.git;a=3Dblobdiff
> _plain;f=3DCHANGELOG;h=3D6d9ba490488f80ef565f459cef3c110bdf31212c;hp=3D1435
> 4f2506a7fbf8360cd32c96e1d7ce1bfeb3f9;hb=3De06e6e34bffd781b7cefa49b25fb8
> ae863654ca2;hpb=3D832e47beab95c2918b5264f0504f2fe6fe523e4c
> +
> +diff --git a/CHANGELOG b/CHANGELOG
> +index 14354f2..6d9ba49 100644
> +--- a/CHANGELOG
> ++++ b/CHANGELOG
> +@@ -48,6 +48,10 @@ version 2.76
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0(ie xx::0 to xx::ffff:ffff:ffff:ffff)=C2=A0
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0Thanks to Laurent Bendel for spotting this =
problem.
> +=C2=A0
> ++	=C2=A0=C2=A0=C2=A0=C2=A0Add support for a TTL parameter in --host-record=
 and
> ++	=C2=A0=C2=A0=C2=A0=C2=A0--cname.
> ++
> ++	=C2=A0=C2=A0=C2=A0=C2=A0Add --dhcp-ttl option.
> +=C2=A0
> + version 2.75
> +=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=A0Fix reversion on 2.74 which caused 100% CPU use when a=C2=A0
> diff --git a/src/patches/dnsmasq/003-
> dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que
> ries_set.patch b/src/patches/dnsmasq/003-
> dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que
> ries_set.patch
> deleted file mode 100644
> index cfbcdfb..0000000
> --- a/src/patches/dnsmasq/003-
> dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que
> ries_set.patch
> +++ /dev/null
> @@ -1,34 +0,0 @@
> -From 3a3965ac21b1b759eab8799b6edb09195b671306 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Sun, 9 Aug 2015 17:45:06 +0100
> -Subject: [PATCH] Don't answer non-auth queries for auth zones
> locally when
> - --localise-queries set.
> -
> ----
> - src/forward.c |=C2=A0=C2=A0=C2=A0=C2=A04 ++--
> - 1 file changed, 2 insertions(+), 2 deletions(-)
> -
> -diff --git a/src/forward.c b/src/forward.c
> -index 2731b90..b76a974 100644
> ---- a/src/forward.c
> -+++ b/src/forward.c
> -@@ -1365,7 +1365,7 @@ void receive_query(struct listener *listen,
> time_t now)
> -=C2=A0
> - #ifdef HAVE_AUTH
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* find queries for zones we're =
authoritative for, and answer
> them directly */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!auth_dns)
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!auth_dns && !option_bool(OPT_LOC=
ALISE))
> -=C2=A0	for (zone =3D daemon->auth_zones; zone; zone =3D zone->next)
> -=C2=A0	=C2=A0=C2=A0if (in_zone(zone, daemon->namebuff, NULL))
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> -@@ -1904,7 +1904,7 @@ unsigned char *tcp_request(int confd, time_t
> now,
> -=C2=A0	=C2=A0=C2=A0
> - #ifdef HAVE_AUTH
> -=C2=A0	=C2=A0=C2=A0/* find queries for zones we're authoritative for, and
> answer them directly */
> --	=C2=A0=C2=A0if (!auth_dns)
> -+	=C2=A0=C2=A0if (!auth_dns && !option_bool(OPT_LOCALISE))
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0for (zone =3D daemon->auth_zones; zone; zon=
e =3D zone-
> >next)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (in_zone(zone, daemon->nameb=
uff, NULL))
> -=C2=A0		{
> ---=C2=A0
> -1.7.10.4
> diff --git a/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
> b/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
> new file mode 100644
> index 0000000..c06705a
> --- /dev/null
> +++ b/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
> @@ -0,0 +1,136 @@
> +From bec366b4041df72b559e713f1c924177676e6eb0 Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Wed, 24 Feb 2016 22:03:26 +0000
> +Subject: [PATCH] Add --tftp-mtu option.
> +
> +---
> + CHANGELOG=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A04 ++++
> + man/dnsmasq.8 |=C2=A0=C2=A0=C2=A0=C2=A04 ++++
> + src/dnsmasq.h |=C2=A0=C2=A0=C2=A0=C2=A02 +-
> + src/option.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A010 +++++++++-
> + src/tftp.c=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A014 ++++++++++++--
> + 5 files changed, 30 insertions(+), 4 deletions(-)
> +
> +diff --git a/CHANGELOG b/CHANGELOG
> +index 6d9ba49..9218b8c 100644
> +--- a/CHANGELOG
> ++++ b/CHANGELOG
> +@@ -53,6 +53,10 @@ version 2.76
> +=C2=A0
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0Add --dhcp-ttl option.
> +=C2=A0
> ++	=C2=A0=C2=A0=C2=A0=C2=A0Add --tftp-mtu option. Thanks to Patrick McLean =
for
> the=C2=A0
> ++	=C2=A0=C2=A0=C2=A0=C2=A0initial patch.
> ++
> ++
> + version 2.75
> +=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=A0Fix reversion on 2.74 which caused 100% CPU use when a=C2=A0
> +=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0dhcp-script is configured. Thanks to Adrian=
 Davey for
> +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> +index 2bcce20..3cf48cd 100644
> +--- a/man/dnsmasq.8
> ++++ b/man/dnsmasq.8
> +@@ -1810,6 +1810,10 @@ require about (2*n) + 10 descriptors. If
> + .B --tftp-port-range
> + is given, that can affect the number of concurrent connections.
> + .TP
> ++.B --tftp-mtu=3D<mtu size>
> ++Use size as the ceiling of the MTU supported by the intervening
> network when=C2=A0
> ++negotiating TFTP blocksize, overriding the MTU setting of the local
> interface=C2=A0=C2=A0if it is larger.
> ++.TP
> + .B --tftp-no-blocksize
> + Stop the TFTP server from negotiating the "blocksize" option with a
> + client. Some buggy clients request this option but then behave
> badly
> +diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> +index 9f73c3b..280ad9d 100644
> +--- a/src/dnsmasq.h
> ++++ b/src/dnsmasq.h
> +@@ -975,7 +975,7 @@ extern struct daemon {
> +=C2=A0=C2=A0=C2=A0struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names,
> *dhcp_gen_names;=C2=A0
> +=C2=A0=C2=A0=C2=A0struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
> +=C2=A0=C2=A0=C2=A0struct hostsfile *dhcp_hosts_file, *dhcp_opts_file,
> *dynamic_dirs;
> +-=C2=A0=C2=A0int dhcp_max, tftp_max;
> ++=C2=A0=C2=A0int dhcp_max, tftp_max, tftp_mtu;
> +=C2=A0=C2=A0=C2=A0int dhcp_server_port, dhcp_client_port;
> +=C2=A0=C2=A0=C2=A0int start_tftp_port, end_tftp_port;=C2=A0
> +=C2=A0=C2=A0=C2=A0unsigned int min_leasetime;
> +diff --git a/src/option.c b/src/option.c
> +index 3f6d162..765965f 100644
> +--- a/src/option.c
> ++++ b/src/option.c
> +@@ -158,7 +158,8 @@ struct myoption {
> + #define LOPT_CPE_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0346
> + #define LOPT_SCRIPT_ARP=C2=A0=C2=A0=C2=A0=C2=A0347
> + #define LOPT_DHCPTTL=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0348
> +-
> ++#define LOPT_TFTP_MTU=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0349
> ++=C2=A0
> + #ifdef HAVE_GETOPT_LONG
> + static const struct option opts[] =3D=C2=A0=C2=A0
> + #else
> +@@ -244,6 +245,7 @@ static const struct myoption opts[] =3D
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "tftp-unique-root", 0, 0, LOPT_APREF },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "tftp-root", 1, 0, LOPT_PREFIX },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
> ++=C2=A0=C2=A0=C2=A0=C2=A0{ "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "ptr-record", 1, 0, LOPT_PTR },
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ "naptr-record", 1, 0, LOPT_NAPTR },
> +@@ -432,6 +434,7 @@ static struct {
> +=C2=A0=C2=A0=C2=A0{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allo=
w access
> only to files owned by the user running dnsmasq."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noo=
p("Do not
> terminate the service if TFTP directories are inaccessible."), NULL
> },
> +=C2=A0=C2=A0=C2=A0{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Max=
imum
> number of conncurrent TFTP transfers (defaults to %s)."), "#" },
> ++=C2=A0=C2=A0{ LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum =
MTU
> to use for TFTP transfers."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Di=
sable the
> TFTP blocksize extension."), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert=
 TFTP
> filenames to lowercase"), NULL },
> +=C2=A0=C2=A0=C2=A0{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>",
> gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL
> },
> +@@ -2625,6 +2628,11 @@ static int one_opt(int option, char *arg,
> char *errstr, char *gen_err, int comma
> +=C2=A0	ret_err(gen_err);
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;=C2=A0=C2=A0
> +=C2=A0
> ++=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_TFTP_MTU:=C2=A0=C2=A0/*=C2=A0=C2=A0--tf=
tp-mtu */
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!atoi_check(arg, &daemon->tftp_mt=
u))
> ++	ret_err(gen_err);
> ++=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> ++
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case LOPT_PREFIX: /* --tftp-prefix */
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0comma =3D split(arg);
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (comma)
> +diff --git a/src/tftp.c b/src/tftp.c
> +index 00ed2fc..dc4aa85 100644
> +--- a/src/tftp.c
> ++++ b/src/tftp.c
> +@@ -103,8 +103,10 @@ void tftp_request(struct listener *listen,
> time_t now)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (listen->iface)
> +=C2=A0	{
> +=C2=A0	=C2=A0=C2=A0addr =3D listen->iface->addr;
> +-	=C2=A0=C2=A0mtu =3D listen->iface->mtu;
> +=C2=A0	=C2=A0=C2=A0name =3D listen->iface->name;
> ++	=C2=A0=C2=A0mtu =3D listen->iface->mtu;
> ++	=C2=A0=C2=A0if (daemon->tftp_mtu !=3D 0 && daemon->tftp_mtu < mtu)
> ++	=C2=A0=C2=A0=C2=A0=C2=A0mtu =3D daemon->tftp_mtu;
> +=C2=A0	}
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> +=C2=A0	{
> +@@ -234,9 +236,17 @@ void tftp_request(struct listener *listen,
> time_t now)
> +=C2=A0
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0strncpy(ifr.ifr_name, name, IF_N=
AMESIZE);
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (ioctl(listen->tftpfd, SIOCGI=
FMTU, &ifr) !=3D -1)
> +-	mtu =3D ifr.ifr_mtu;=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> ++	{
> ++	=C2=A0=C2=A0mtu =3D ifr.ifr_mtu;=C2=A0=C2=A0
> ++	=C2=A0=C2=A0if (daemon->tftp_mtu !=3D 0 && daemon->tftp_mtu < mtu)
> ++	=C2=A0=C2=A0=C2=A0=C2=A0mtu =3D daemon->tftp_mtu;=C2=A0=C2=A0=C2=A0=C2=A0
> ++	}
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> +=C2=A0
> ++=C2=A0=C2=A0/* Failed to get interface mtu - can use configured value. */
> ++=C2=A0=C2=A0if (mtu =3D=3D 0)
> ++=C2=A0=C2=A0=C2=A0=C2=A0mtu =3D daemon->tftp_mtu;
> ++
> +=C2=A0=C2=A0=C2=A0if (name)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* check for per-interface prefi=
x */=C2=A0
> +--=C2=A0
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-
> option.patch b/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-
> option.patch
> deleted file mode 100644
> index 492ada9..0000000
> --- a/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-
> option.patch
> +++ /dev/null
> @@ -1,38 +0,0 @@
> -From 5e3e464ac4022ee0b3794513abe510817e2cf3ca Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 25 Aug 2015 23:08:39 +0100
> -Subject: [PATCH] Fix behaviour of empty dhcp-option=3Doption6:dns-
> server, which
> - should inhibit sending option.
> -
> ----
> - src/rfc3315.c |=C2=A0=C2=A0=C2=A0=C2=A09 +++++----
> - 1 file changed, 5 insertions(+), 4 deletions(-)
> -
> -diff --git a/src/rfc3315.c b/src/rfc3315.c
> -index 2665d0d..3f1f9ee 100644
> ---- a/src/rfc3315.c
> -+++ b/src/rfc3315.c
> -@@ -1320,15 +1320,16 @@ static struct dhcp_netid *add_options(struct
> state *state, int do_refresh)
> -=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 (opt_cfg->opt =3D=3D OPTION6_=
REFRESH_TIME)
> -=C2=A0	done_refresh =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=A0=C2=A0if (opt_cfg->opt =3D=3D OPTION6_DNS_S=
ERVER)
> -+	done_dns =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=A0=C2=A0if (opt_cfg->flags & DHOPT_ADDR6)
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Empty DNS_SERVER option will not s=
et DHOPT_ADDR6 */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((opt_cfg->flags & DHOPT_ADDR6) ||=
 opt_cfg->opt =3D=3D
> OPTION6_DNS_SERVER)
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0int len, j;
> -=C2=A0	=C2=A0=C2=A0struct in6_addr *a;
> -=C2=A0	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (opt_cfg->opt =3D=3D OPTION6_DNS_SERVER)
> --	=C2=A0=C2=A0=C2=A0=C2=A0done_dns =3D 1;
> --	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0for (a =3D (struct in6_addr *)opt_cfg->val, len =3D opt=
_cfg-
> >len, j =3D 0;=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0j < opt_cfg->len; j +=3D =
IN6ADDRSZ, a++)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if ((IN6_IS_ADDR_ULA_ZERO(a) &&
> IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/005-
> suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
> b/src/patches/dnsmasq/005-
> suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
> deleted file mode 100644
> index c7cee60..0000000
> --- a/src/patches/dnsmasq/005-
> suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
> +++ /dev/null
> @@ -1,50 +0,0 @@
> -From 9cdcfe9f19ffd45bac4e5b459879bf7c50a287ed Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Wed, 26 Aug 2015 22:38:08 +0100
> -Subject: [PATCH] Suggest solution to ENOMEM error with IPv6
> multicast.
> -
> ----
> - src/network.c |=C2=A0=C2=A0=C2=A013 ++++++++++---
> - 1 file changed, 10 insertions(+), 3 deletions(-)
> -
> -diff --git a/src/network.c b/src/network.c
> -index a1d90c8..819302f 100644
> ---- a/src/network.c
> -+++ b/src/network.c
> -@@ -1076,23 +1076,30 @@ void join_multicast(int dienow)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if ((daemon->doing_dhcp6 || daemon->relay6)=
 &&
> -=C2=A0		setsockopt(daemon->dhcp6fd, IPPROTO_IPV6,
> IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) =3D=3D -1)
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D 1;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D errno;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0inet_pton(AF_INET6, ALL_SERVERS,
> &mreq.ipv6mr_multiaddr);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (daemon->doing_dhcp6 &&=C2=A0
> -=C2=A0		setsockopt(daemon->dhcp6fd, IPPROTO_IPV6,
> IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) =3D=3D -1)
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D 1;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D errno;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0inet_pton(AF_INET6, ALL_ROUTERS,
> &mreq.ipv6mr_multiaddr);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (daemon->doing_ra &&
> -=C2=A0		setsockopt(daemon->icmp6fd, IPPROTO_IPV6,
> IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) =3D=3D -1)
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D 1;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0err =3D errno;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (err)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		char *s =3D _("interface %s failed to join DHCPv6
> multicast group: %s");
> -+		errno =3D err;
> -+
> -+#ifdef HAVE_LINUX_NETWORK
> -+		if (errno =3D=3D ENOMEM)
> -+		=C2=A0=C2=A0my_syslog(LOG_ERR, _("try increasing
> /proc/sys/net/core/optmem_max"));
> -+#endif
> -+
> -=C2=A0		if (dienow)
> -=C2=A0		=C2=A0=C2=A0die(s, iface->name, EC_BADNET);
> -=C2=A0		else
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/006-
> clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
> b/src/patches/dnsmasq/006-
> clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
> deleted file mode 100644
> index 19c76e6..0000000
> --- a/src/patches/dnsmasq/006-
> clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -From 20fd11e11a9d09edcea94de135396ae1541fbbab Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Wed, 26 Aug 2015 22:48:13 +0100
> -Subject: [PATCH] Clarify man page on RDNSS set in router
> advertisement.
> -
> ----
> - man/dnsmasq.8 |=C2=A0=C2=A0=C2=A0=C2=A06 +++---
> - 1 file changed, 3 insertions(+), 3 deletions(-)
> -
> -diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> -index a23c898..d51b10f 100644
> ---- a/man/dnsmasq.8
> -+++ b/man/dnsmasq.8
> -@@ -1687,15 +1687,15 @@ creation are handled by a different
> protocol. When DHCP is in use,
> - only a subset of this is needed, and dnsmasq can handle it, using
> - existing DHCP configuration to provide most data. When RA is
> enabled,
> - dnsmasq will advertise a prefix for each dhcp-range, with default
> --router and recursive DNS server as the relevant link-local address
> on=C2=A0
> --the machine running dnsmasq. By default, he "managed address" bits
> are set, and
> -+router=C2=A0=C2=A0as the relevant link-local address on=C2=A0
> -+the machine running dnsmasq. By default, the "managed address" bits
> are set, and
> - the "use SLAAC" bit is reset. This can be changed for individual
> - subnets with the mode keywords described in
> - .B --dhcp-range.
> - RFC6106 DNS parameters are included in the advertisements. By
> default,
> - the relevant link-local address of the machine running dnsmasq is
> sent
> - as recursive DNS server. If provided, the DHCPv6 options dns-server=20
> and
> --domain-search are used for RDNSS and DNSSL.
> -+domain-search are used for the DNS server (RDNSS) and the domain
> serach list (DNSSL).
> - .TP
> - .B --ra-param=3D<interface>,[high|low],[[<ra-interval>],<router
> lifetime>]
> - Set non-default values for router advertisements sent via an
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/007-
> handle_signed_dangling_CNAME_replies_to_DS_queries.patch
> b/src/patches/dnsmasq/007-
> handle_signed_dangling_CNAME_replies_to_DS_queries.patch
> deleted file mode 100644
> index 832a22e..0000000
> --- a/src/patches/dnsmasq/007-
> handle_signed_dangling_CNAME_replies_to_DS_queries.patch
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -From 6de81f1250fd323c9155de065d5a9dc200a6f20b Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Wed, 9 Sep 2015 22:51:13 +0100
> -Subject: [PATCH] Handle signed dangling CNAME replies to DS queries.
> -
> ----
> - src/dnssec.c |=C2=A0=C2=A0=C2=A0=C2=A07 ++-----
> - 1 file changed, 2 insertions(+), 5 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index 4deda24..67ce486 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -1232,11 +1232,8 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* If we return STAT_NO_SIG, name contains the name of t=
he DS
> query */
> -=C2=A0=C2=A0=C2=A0if (val =3D=3D STAT_NO_SIG)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*keyname =3D 0;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return val;
> --=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0=C2=A0
> --
> -+=C2=A0=C2=A0=C2=A0=C2=A0return val;
> -+=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* If the key needed to validate the DS is on the same d=
omain as
> the DS, we'll
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0loop getting nowhere. Stop that now. T=
his can happen of the DS
> answer comes
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0from the DS's zone, and not the parent=
 zone. */
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/008-
> DHCPv6_option_56_does_not_hold_an_address_list.patch
> b/src/patches/dnsmasq/008-
> DHCPv6_option_56_does_not_hold_an_address_list.patch
> deleted file mode 100644
> index fdccd0e..0000000
> --- a/src/patches/dnsmasq/008-
> DHCPv6_option_56_does_not_hold_an_address_list.patch
> +++ /dev/null
> @@ -1,25 +0,0 @@
> -From 102208df695e886a3086754d32bf7f8c541fbe46 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Thu, 10 Sep 2015 21:50:00 +0100
> -Subject: [PATCH] DHCPv6 option 56 does not hold an address list.
> (RFC 5908).
> -
> ----
> - src/dhcp-common.c |=C2=A0=C2=A0=C2=A0=C2=A02 +-
> - 1 file changed, 1 insertion(+), 1 deletion(-)
> -
> -diff --git a/src/dhcp-common.c b/src/dhcp-common.c
> -index bc48f41..8fc171a 100644
> ---- a/src/dhcp-common.c
> -+++ b/src/dhcp-common.c
> -@@ -599,7 +599,7 @@ static const struct opttab_t opttab6[] =3D {
> -=C2=A0=C2=A0=C2=A0{ "sntp-server", 31,=C2=A0=C2=A0OT_ADDR_LIST },
> -=C2=A0=C2=A0=C2=A0{ "information-refresh-time", 32, OT_TIME },
> -=C2=A0=C2=A0=C2=A0{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
> --=C2=A0=C2=A0{ "ntp-server", 56,=C2=A0=C2=A0OT_ADDR_LIST },
> -+=C2=A0=C2=A0{ "ntp-server", 56,=C2=A0=C2=A00 },
> -=C2=A0=C2=A0=C2=A0{ "bootfile-url", 59, OT_NAME },
> -=C2=A0=C2=A0=C2=A0{ "bootfile-param", 60, OT_CSTRING },
> -=C2=A0=C2=A0=C2=A0{ NULL, 0, 0 }
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/009-Respect_the_
> --no_resolv_flag_in_inotify_code.patch b/src/patches/dnsmasq/009-
> Respect_the_--no_resolv_flag_in_inotify_code.patch
> deleted file mode 100644
> index 2014fdb..0000000
> --- a/src/patches/dnsmasq/009-Respect_the_
> --no_resolv_flag_in_inotify_code.patch
> +++ /dev/null
> @@ -1,47 +0,0 @@
> -From 77607cbea0ad0f876dfb79c8b2c121ee400d57d0 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Thu, 10 Sep 2015 23:08:43 +0100
> -Subject: [PATCH] Respect the --no-resolv flag in inotify code.
> -
> ----
> - CHANGELOG=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=
=A0=C2=A07 ++++++-
> - debian/changelog |=C2=A0=C2=A0=C2=A0=C2=A06 ++++++
> - src/inotify.c=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A03 +++
> - 3 files changed, 15 insertions(+), 1 deletion(-)
> -
> -diff --git a/CHANGELOG b/CHANGELOG
> -index bbc2834..d6e309f 100644
> ---- a/CHANGELOG
> -+++ b/CHANGELOG
> -@@ -7,8 +7,13 @@ version 2.76
> -=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0Enhance --add-subnet to allow arbitrary sub=
net
> addresses.
> -=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=A0Thanks to Ed Barsley for the patch.
> -+
> -+	=C2=A0=C2=A0=C2=A0=C2=A0Respect the --no-resolv flag in inotify code. Fi=
xes bug
> -+	=C2=A0=C2=A0=C2=A0=C2=A0which caused dnsmasq to fail to start if a resol=
v-file=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0was a dangling symbolic link, even of --no-resol=
v set.
> -+	=C2=A0=C2=A0=C2=A0=C2=A0Thanks to Alexander Kurtz for spotting the probl=
em.
> -+
> -=C2=A0=09
> --	=C2=A0=C2=A0=C2=A0=C2=A0
> - version 2.75
> -=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=A0Fix reversion on 2.74 which caused 100% CPU use when a=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0dhcp-script is configured. Thanks to Adrian=
 Davey for
> -diff --git a/src/inotify.c b/src/inotify.c
> -index 52d412f..ef05c58 100644
> ---- a/src/inotify.c
> -+++ b/src/inotify.c
> -@@ -90,6 +90,9 @@ void inotify_dnsmasq_init()
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (daemon->inotifyfd =3D=3D -1)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0die(_("failed to create inotify: %s"), NULL,=
 EC_MISC);
> -+
> -+=C2=A0=C2=A0if (option_bool(OPT_NO_RESOLV))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0for (res =3D daemon->resolv_files; res; res =3D res->nex=
t)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/010-
> Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
> b/src/patches/dnsmasq/010-
> Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
> deleted file mode 100644
> index 281697f..0000000
> --- a/src/patches/dnsmasq/010-
> Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
> +++ /dev/null
> @@ -1,26 +0,0 @@
> -From 27b78d990b7cd901866ad6f1a17b9d633a95fdce Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Sat, 26 Sep 2015 21:40:45 +0100
> -Subject: [PATCH] Rationalise
> 5e3e464ac4022ee0b3794513abe510817e2cf3ca
> -
> ----
> - src/rfc3315.c |=C2=A0=C2=A0=C2=A0=C2=A03 +--
> - 1 file changed, 1 insertion(+), 2 deletions(-)
> -
> -diff --git a/src/rfc3315.c b/src/rfc3315.c
> -index 3f1f9ee..3ed8623 100644
> ---- a/src/rfc3315.c
> -+++ b/src/rfc3315.c
> -@@ -1324,8 +1324,7 @@ static struct dhcp_netid *add_options(struct
> state *state, int do_refresh)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (opt_cfg->opt =3D=3D OPTION6_=
DNS_SERVER)
> -=C2=A0	done_dns =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=A0=C2=A0/* Empty DNS_SERVER option will not s=
et DHOPT_ADDR6 */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((opt_cfg->flags & DHOPT_ADDR6) ||=
 opt_cfg->opt =3D=3D
> OPTION6_DNS_SERVER)
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (opt_cfg->flags & DHOPT_ADDR6)
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0int len, j;
> -=C2=A0	=C2=A0=C2=A0struct in6_addr *a;
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/011-
> Catch_errors_from_sendmsg_in_DHCP_code.patch
> b/src/patches/dnsmasq/011-
> Catch_errors_from_sendmsg_in_DHCP_code.patch
> deleted file mode 100644
> index 631495f..0000000
> --- a/src/patches/dnsmasq/011-
> Catch_errors_from_sendmsg_in_DHCP_code.patch
> +++ /dev/null
> @@ -1,32 +0,0 @@
> -From 98079ea89851da1df4966dfdfa1852a98da02912 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 13 Oct 2015 20:30:32 +0100
> -Subject: [PATCH] Catch errors from sendmsg in DHCP code.=C2=A0=C2=A0Logs,
> eg,=C2=A0=C2=A0iptables
> - DROPS of dest 255.255.255.255
> -
> ----
> - src/dhcp.c |=C2=A0=C2=A0=C2=A0=C2=A07 ++++++-
> - 1 file changed, 6 insertions(+), 1 deletion(-)
> -
> -diff --git a/src/dhcp.c b/src/dhcp.c
> -index e6fceb1..1c85e42 100644
> ---- a/src/dhcp.c
> -+++ b/src/dhcp.c
> -@@ -452,8 +452,13 @@ void dhcp_packet(time_t now, int pxe_fd)
> - #endif
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0while(retry_send(sendmsg(fd, &msg, 0)));
> -+
> -+=C2=A0=C2=A0/* This can fail when, eg, iptables DROPS destination
> 255.255.255.255 */
> -+=C2=A0=C2=A0if (errno !=3D 0)
> -+=C2=A0=C2=A0=C2=A0=C2=A0my_syslog(MS_DHCP | LOG_WARNING, _("Error sending=
 DHCP packet
> to %s: %s"),
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0inet_ntoa(dest.sin_addr), strerror(e=
rrno));
> - }
> --=C2=A0
> -+
> - /* check against secondary interface addresses */
> - static int check_listen_addrs(struct in_addr local, int if_index,
> char *label,
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct in_addr netmask, struct
> in_addr broadcast, void *vparam)
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/012-Update_list_of_subnet_for_
> --bogus-priv.patch b/src/patches/dnsmasq/012-
> Update_list_of_subnet_for_--bogus-priv.patch
> deleted file mode 100644
> index 3ba98fc..0000000
> --- a/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-
> priv.patch
> +++ /dev/null
> @@ -1,48 +0,0 @@
> -From 90477fb79420a34124b66ebd808c578817a30e4c Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 20 Oct 2015 21:21:32 +0100
> -Subject: [PATCH] Update list of subnet for --bogus-priv
> -
> -RFC6303 specifies & recommends following zones not be forwarded
> -to globally facing servers.
> -+------------------------------+-----------------------+
> -| Zone=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| Description=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0|
> -+------------------------------+-----------------------+
> -| 0.IN-ADDR.ARPA=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| IPv4 "THIS" NETWORK=C2=A0=C2=A0=C2=A0|
> -| 127.IN-ADDR.ARPA=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| IPv4 Loopback NETWORK |
> -| 254.169.IN-ADDR.ARPA=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0| IPv4 LINK LOCAL=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|
> -| 2.0.192.IN-ADDR.ARPA=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0| IPv4 TEST-NET-1=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|
> -| 100.51.198.IN-ADDR.ARPA=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0| IPv4 TEST-N=
ET-2=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|
> -| 113.0.203.IN-ADDR.ARPA=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0| IPv4 T=
EST-NET-3=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|
> -| 255.255.255.255.IN-ADDR.ARPA | IPv4 BROADCAST=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0|
> -+------------------------------+-----------------------+
> -
> -Signed-off-by: Kevin Darbyshire-Bryant <kevin(a)darbyshire-bryant.me.u
> k>
> ----
> - src/rfc1035.c |=C2=A0=C2=A0=C2=A0=C2=A08 ++++++--
> - 1 file changed, 6 insertions(+), 2 deletions(-)
> -
> -diff --git a/src/rfc1035.c b/src/rfc1035.c
> -index 6a51b30..4eb1772 100644
> ---- a/src/rfc1035.c
> -+++ b/src/rfc1035.c
> -@@ -756,10 +756,14 @@ int private_net(struct in_addr addr, int
> ban_localhost)
> -=C2=A0=C2=A0=C2=A0return
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(((ip_addr & 0xFF000000) =3D=3D 0x7F000000) =
&& ban_localhost)=C2=A0=C2=A0/*
> 127.0.0.0/8=C2=A0=C2=A0=C2=A0=C2=A0(loopback) */ ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFF000000) =3D=3D 0x00000000)=
=C2=A0=C2=A0/* RFC 5735 section 3.
> "here" network */ ||
> --=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFF0000) =3D=3D 0xC0A80000)=C2=A0=
=C2=A0/* 192.168.0.0/16
> (private)=C2=A0=C2=A0*/ ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFF000000) =3D=3D 0x0A000000)=
=C2=A0=C2=A0/*
> 10.0.0.0/8=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(private)=C2=A0=C2=A0*/ ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFF00000) =3D=3D 0xAC100000)=
=C2=A0=C2=A0/*
> 172.16.0.0/12=C2=A0=C2=A0(private)=C2=A0=C2=A0*/ ||
> --=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFF0000) =3D=3D 0xA9FE0000)=C2=A0=
=C2=A0/* 169.254.0.0/16
> (zeroconf) */ ;
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFF0000) =3D=3D 0xC0A80000)=C2=A0=
=C2=A0/* 192.168.0.0/16
> (private)=C2=A0=C2=A0*/ ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFF0000) =3D=3D 0xA9FE0000)=C2=A0=
=C2=A0/* 169.254.0.0/16
> (zeroconf) */ ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFFFF00) =3D=3D 0xC0000200)=C2=A0=
=C2=A0/*
> 192.0.2.0/24=C2=A0=C2=A0=C2=A0(test-net) */ ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFFFF00) =3D=3D 0xC6336400)=C2=A0=
=C2=A0/*
> 198.51.100.0/24(test-net) */ ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFFFF00) =3D=3D 0xCB007100)=C2=A0=
=C2=A0/* 203.0.113.0/24
> (test-net) */ ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0((ip_addr & 0xFFFFFFFF) =3D=3D 0xFFFFFFFF)=C2=A0=
=C2=A0/* 255.255.255.255/32
> (broadcast)*/ ;
> - }
> -=C2=A0
> - static unsigned char *do_doctor(unsigned char *p, int count, struct
> dns_header *header, size_t qlen, char *name, int *doctored)
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/013-
> Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
> b/src/patches/dnsmasq/013-
> Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
> deleted file mode 100644
> index 736cf38..0000000
> --- a/src/patches/dnsmasq/013-
> Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
> +++ /dev/null
> @@ -1,43 +0,0 @@
> -From 41a8d9e99be9f2cc8b02051dd322cb45e0faac87 Mon Sep 17 00:00:00
> 2001
> -From: =3D?utf8?q?Edwin=3D20T=3DC3=3DB6r=3DC3=3DB6k?=3D <edwin+ml-cerowrt(a=
)etorok.ne
> t>
> -Date: Sat, 14 Nov 2015 17:45:48 +0000
> -Subject: [PATCH] Fix crash when empty address from DNS overlays A
> record from
> - hosts.
> -
> ----
> - CHANGELOG=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A05 +++++
> - src/cache.c |=C2=A0=C2=A0=C2=A0=C2=A02 +-
> - 2 files changed, 6 insertions(+), 1 deletion(-)
> -
> -diff --git a/CHANGELOG b/CHANGELOG
> -index d6e309f..93c73d0 100644
> ---- a/CHANGELOG
> -+++ b/CHANGELOG
> -@@ -13,6 +13,11 @@ version 2.76
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0was a dangling symbolic link, even of --no-=
resolv set.
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0Thanks to Alexander Kurtz for spotting the =
problem.
> -=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0Fix crash when an A or AAAA record is defined lo=
cally,
> -+	=C2=A0=C2=A0=C2=A0=C2=A0in a hosts file, and an upstream server sends a =
reply
> -+	=C2=A0=C2=A0=C2=A0=C2=A0that the same name is empty. Thanks to Edwin T=
=C3=83=C2=B6r=C3=83=C2=B6k
> for
> -+	=C2=A0=C2=A0=C2=A0=C2=A0the patch.
> -+
> -=C2=A0=09
> - version 2.75
> -=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=A0Fix reversion on 2.74 which caused 100% CPU use when a=C2=A0
> -diff --git a/src/cache.c b/src/cache.c
> -index 178d654..1b76b67 100644
> ---- a/src/cache.c
> -+++ b/src/cache.c
> -@@ -481,7 +481,7 @@ struct crec *cache_insert(char *name, struct
> all_addr *addr,
> -=C2=A0	=C2=A0existing record is for an A or AAAA and
> -=C2=A0	=C2=A0the record we're trying to insert is the same,=C2=A0
> -=C2=A0	=C2=A0just drop the insert, but don't error the whole process.
> */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((flags & (F_IPV4 | F_IPV6)) && (f=
lags & F_FORWARD))
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((flags & (F_IPV4 | F_IPV6)) && (f=
lags & F_FORWARD) &&
> addr)
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->addr.addr.addr.addr4.s_add=
r =3D=3D addr-
> >addr.addr4.s_addr)
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/014-
> Handle_unknown_DS_hash_algos_correctly.patch
> b/src/patches/dnsmasq/014-
> Handle_unknown_DS_hash_algos_correctly.patch
> deleted file mode 100644
> index 8b17431..0000000
> --- a/src/patches/dnsmasq/014-
> Handle_unknown_DS_hash_algos_correctly.patch
> +++ /dev/null
> @@ -1,39 +0,0 @@
> -From 67ab3285b5d9a1b1e20e034cf272867fdab8a0f9 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Fri, 20 Nov 2015 23:20:47 +0000
> -Subject: [PATCH] Handle unknown DS hash algos correctly.
> -
> -When we can validate a DS RRset, but don't speak the hash algo it
> -contains, treat that the same as an NSEC/3 proving that the DS
> -doesn't exist. 4025 5.2
> ----
> - src/dnssec.c |=C2=A0=C2=A0=C2=A013 +++++++++++++
> - 1 file changed, 13 insertions(+)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index 67ce486..b4dc14e 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -1005,6 +1005,19 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0=C2=A0=C2=A0if (crecp->flags & F_NEG)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE_DS;
> -=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* 4035 5.2=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0If the validator does not support any of th=
e algorithms listed
> in an
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0authenticated DS RRset, then the resolver h=
as no supported
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0authentication path leading from the parent=
 to the child.=C2=A0=C2=A0The
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0resolver should treat this case as it would=
 the case of an
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0authenticated NSEC RRset proving that no DS=
 RRset exists,=C2=A0=C2=A0*/
> -+=C2=A0=C2=A0for (recp1 =3D crecp; recp1; recp1 =3D cache_find_by_name(rec=
p1,
> name, now, F_DS))
> -+=C2=A0=C2=A0=C2=A0=C2=A0if (hash_find(ds_digest_name(recp1->addr.ds.diges=
t)))
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (!recp1)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE_DS;
> -+
> -=C2=A0=C2=A0=C2=A0/* NOTE, we need to find ONE DNSKEY which matches the DS=
 */
> -=C2=A0=C2=A0=C2=A0for (valid =3D 0, j =3D ntohs(header->ancount); j !=3D 0=
 && !valid; j
> --)=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-
> dir.patch b/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-
> dir.patch
> deleted file mode 100644
> index a9102c1..0000000
> --- a/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-
> dir.patch
> +++ /dev/null
> @@ -1,38 +0,0 @@
> -From 0007ee90646a5a78a96ee729932e89d31c69513a Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Sat, 21 Nov 2015 21:47:41 +0000
> -Subject: [PATCH] Fix crash at start up with conf-dir=3D/path,*
> -
> -Thanks to Brian Carpenter and American Fuzzy Lop for finding the
> bug.
> ----
> - src/option.c |=C2=A0=C2=A0=C2=A014 ++++++++++----
> - 1 file changed, 10 insertions(+), 4 deletions(-)
> -
> -diff --git a/src/option.c b/src/option.c
> -index 746cd11..71beb98 100644
> ---- a/src/option.c
> -+++ b/src/option.c
> -@@ -1515,10 +1515,16 @@ static int one_opt(int option, char *arg,
> char *errstr, char *gen_err, int comma
> -=C2=A0		li =3D opt_malloc(sizeof(struct list));
> -=C2=A0		if (*arg =3D=3D '*')
> -=C2=A0		=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0li->next =3D match_suffix;
> --		=C2=A0=C2=A0=C2=A0=C2=A0match_suffix =3D li;
> --		=C2=A0=C2=A0=C2=A0=C2=A0/* Have to copy: buffer is overwritten */
> --		=C2=A0=C2=A0=C2=A0=C2=A0li->suffix =3D opt_string_alloc(arg+1);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0/* "*" with no suffix is a no-op */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if (arg[1] =3D=3D 0)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(li);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0else
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+			li->next =3D match_suffix;
> -+			match_suffix =3D li;
> -+			/* Have to copy: buffer is overwritten */
> -+			li->suffix =3D opt_string_alloc(arg+1);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0		=C2=A0=C2=A0}
> -=C2=A0		else
> -=C2=A0		=C2=A0=C2=A0{
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/016-
> Major_rationalisation_of_DNSSEC_validation.patch
> b/src/patches/dnsmasq/016-
> Major_rationalisation_of_DNSSEC_validation.patch
> deleted file mode 100644
> index 7f25066..0000000
> --- a/src/patches/dnsmasq/016-
> Major_rationalisation_of_DNSSEC_validation.patch
> +++ /dev/null
> @@ -1,2209 +0,0 @@
> -From 9a31b68b59adcac01016d4026d906b69c4216c01 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 15 Dec 2015 10:20:39 +0000
> -Subject: [PATCH] Major rationalisation of DNSSEC validation.
> -
> -Much gnarly special-case code removed and replaced with correct
> -general implementaion. Checking of zone-status moved to DNSSEC code,
> -where it should be, vastly simplifying query-forwarding code.
> ----
> - src/dnsmasq.h |=C2=A0=C2=A0=C2=A019 +-
> - src/dnssec.c=C2=A0=C2=A0|=C2=A0=C2=A0926 ++++++++++++++++++++++++++++++--=
------------
> -------------
> - src/forward.c |=C2=A0=C2=A0741 ++++++++++--------------------------------=
---
> - 3 files changed, 653 insertions(+), 1033 deletions(-)
> -
> -diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> -index f42acdb..023a1cf 100644
> ---- a/src/dnsmasq.h
> -+++ b/src/dnsmasq.h
> -@@ -586,12 +586,8 @@ struct hostsfile {
> - #define STAT_NEED_KEY=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A05
> - #define STAT_TRUNCATED=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A06
> - #define STAT_SECURE_WILDCARD=C2=A0=C2=A0=C2=A0=C2=A07
> --#define STAT_NO_SIG=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=A08
> --#define STAT_NO_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=C2=A09
> --#define STAT_NO_NS=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=A010
> --#define STAT_NEED_DS_NEG=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A011
> --#define STAT_CHASE_CNAME=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A012
> --#define STAT_INSECURE_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A013
> -+#define STAT_OK=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=A08
> -+#define STAT_ABANDONED=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A09
> -=C2=A0
> - #define FREC_NOREBIND=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A01
> - #define FREC_CHECKING_DISABLED=C2=A0=C2=A02
> -@@ -601,8 +597,7 @@ struct hostsfile {
> - #define FREC_AD_QUESTION=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A032
> - #define FREC_DO_QUESTION=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A064
> - #define FREC_ADDED_PHEADER=C2=A0=C2=A0=C2=A0=C2=A0128
> --#define FREC_CHECK_NOSIGN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0256
> --#define FREC_TEST_PKTSZ=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0512
> -+#define FREC_TEST_PKTSZ=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0256
> -=C2=A0
> - #ifdef HAVE_DNSSEC
> - #define HASH_SIZE 20 /* SHA-1 digest size */
> -@@ -626,9 +621,7 @@ struct frec {
> - #ifdef HAVE_DNSSEC=C2=A0
> -=C2=A0=C2=A0=C2=A0int class, work_counter;
> -=C2=A0=C2=A0=C2=A0struct blockdata *stash; /* Saved reply, whilst we valid=
ate */
> --=C2=A0=C2=A0struct blockdata *orig_domain; /* domain of original query,
> whilst
> --				=C2=A0=C2=A0=C2=A0=C2=A0we're seeing is if in unsigned
> domain */
> --=C2=A0=C2=A0size_t stash_len, name_start, name_len;
> -+=C2=A0=C2=A0size_t stash_len;
> -=C2=A0=C2=A0=C2=A0struct frec *dependent; /* Query awaiting internally-gen=
erated
> DNSKEY or DS query */
> -=C2=A0=C2=A0=C2=A0struct frec *blocking_query; /* Query which is blocking =
us. */
> - #endif
> -@@ -1162,8 +1155,8 @@ int in_zone(struct auth_zone *zone, char
> *name, char **cut);
> - size_t dnssec_generate_query(struct dns_header *header, 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, int *neganswer,
> int *nons);
> --int dnssec_chase_cname(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname);
> -+int dnssec_validate_reply(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname, int *class,
> -+			=C2=A0=C2=A0int check_unsigned, int *neganswer, int
> *nons);
> - int dnskey_keytag(int alg, int flags, unsigned char *rdata, int
> rdlen);
> - size_t filter_rrsigs(struct dns_header *header, size_t plen);
> - unsigned char* hash_questions(struct dns_header *header, size_t
> plen, char *name);
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index b4dc14e..de7b335 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -65,8 +65,10 @@ static char *algo_digest_name(int algo)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 8: return "sha256";
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 10: return "sha512";
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 12: return "gosthash94";
> -+#ifndef NO_NETTLE_ECC
> -=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";
> -+#endif
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0default: return NULL;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> - }
> -@@ -592,30 +594,30 @@ static int get_rdata(struct dns_header
> *header, size_t plen, unsigned char *end,
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> - }
> -=C2=A0
> --static int expand_workspace(unsigned char ***wkspc, int *sz, int
> new)
> -+static int expand_workspace(unsigned char ***wkspc, int *szp, int
> new)
> - {
> -=C2=A0=C2=A0=C2=A0unsigned char **p;
> --=C2=A0=C2=A0int new_sz =3D *sz;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (new_sz > new)
> -+=C2=A0=C2=A0int old =3D *szp;
> -+
> -+=C2=A0=C2=A0if (old >=3D new+1)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (new >=3D 100)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0
> --=C2=A0=C2=A0new_sz +=3D 5;
> -+=C2=A0=C2=A0new +=3D 5;
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0if (!(p =3D whine_malloc((new_sz) * sizeof(unsigned char **))=
))
> -+=C2=A0=C2=A0if (!(p =3D whine_malloc(new * sizeof(unsigned char **))))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0if (*wkspc)
> -+=C2=A0=C2=A0if (old !=3D 0 && *wkspc)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0memcpy(p, *wkspc, *sz * sizeof(unsign=
ed char **));
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0memcpy(p, *wkspc, old * sizeof(unsign=
ed char **));
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(*wkspc);
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0*wkspc =3D p;
> --=C2=A0=C2=A0*sz =3D new_sz;
> -+=C2=A0=C2=A0*szp =3D new;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0return 1;
> - }
> -@@ -706,47 +708,28 @@ static void sort_rrset(struct dns_header
> *header, size_t plen, u16 *rr_desc, int
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} while (swap);
> - }
> -=C2=A0
> --/* Validate a single RRset (class, type, name) in the supplied DNS
> reply=C2=A0
> --=C2=A0=C2=A0=C2=A0Return code:
> --=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0if it validates.
> --=C2=A0=C2=A0=C2=A0STAT_SECURE_WILDCARD if it validates and is the result =
of
> wildcard expansion.
> --=C2=A0=C2=A0=C2=A0(In this case *wildcard_out points to the "body" of the=
 wildcard
> within name.)=C2=A0
> --=C2=A0=C2=A0=C2=A0STAT_NO_SIG no RRsigs found.
> --=C2=A0=C2=A0=C2=A0STAT_INSECURE RRset empty.
> --=C2=A0=C2=A0=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0signature is wrong, b=
ad packet.
> --=C2=A0=C2=A0=C2=A0STAT_NEED_KEY need DNSKEY to complete validation (name =
is
> returned in keyname)
> --
> --=C2=A0=C2=A0=C2=A0if key is non-NULL, use that key, which has the algo an=
d tag
> given in the params of those names,
> --=C2=A0=C2=A0=C2=A0otherwise find the key in the cache.
> -+static unsigned char **rrset =3D NULL, **sigs =3D NULL;
> -=C2=A0
> --=C2=A0=C2=A0=C2=A0name is unchanged on exit. keyname is used as workspace=
 and
> trashed.
> --*/
> --static int validate_rrset(time_t now, struct dns_header *header,
> size_t plen, int class, int type,=C2=A0
> --			=C2=A0=C2=A0char *name, char *keyname, char
> **wildcard_out, struct blockdata *key, int keylen, int algo_in, int
> keytag_in)
> -+/* Get pointers to RRset menbers and signature(s) for same.
> -+=C2=A0=C2=A0=C2=A0Check signatures, and return keyname associated in keyn=
ame. */
> -+static int explore_rrset(struct dns_header *header, size_t plen,
> int class, int type,=C2=A0
> -+			=C2=A0char *name, char *keyname, int *sigcnt,
> int *rrcnt)
> - {
> --=C2=A0=C2=A0static unsigned char **rrset =3D NULL, **sigs =3D NULL;
> --=C2=A0=C2=A0static int rrset_sz =3D 0, sig_sz =3D 0;
> --=C2=A0=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=A0int rrsetidx, sigidx, res, rdlen, j, name_labels;
> --=C2=A0=C2=A0struct crec *crecp =3D NULL;
> --=C2=A0=C2=A0int type_covered, algo, labels, orig_ttl, sig_expiration,
> sig_inception, key_tag;
> --=C2=A0=C2=A0u16 *rr_desc =3D get_desc(type);
> --=C2=A0
> --=C2=A0=C2=A0if (wildcard_out)
> --=C2=A0=C2=A0=C2=A0=C2=A0*wildcard_out =3D NULL;
> --=C2=A0=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=A0int gotkey =3D 0;
> -+
> -=C2=A0=C2=A0=C2=A0if (!(p =3D skip_questions(header, plen)))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0name_labels =3D count_labels(name); /* For 4035 5.3.2 check */
> -=C2=A0
> --=C2=A0=C2=A0/* look for RRSIGs for this RRset and get pointers to each RR=
 in
> the set. */
> -+=C2=A0=C2=A0=C2=A0/* look for RRSIGs for this RRset and get pointers to e=
ach RR in
> the set. */
> -=C2=A0=C2=A0=C2=A0for (rrsetidx =3D 0, sigidx =3D 0, j =3D ntohs(header->a=
ncount) +
> ntohs(header->nscount);=C2=A0
> -=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;
> -+=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=A0=C2=A0=C2=A0pstart =3D p;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -@@ -762,14 +745,14 @@ 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=A0GETSHORT(rdlen, 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 (!CHECK_LEN(header, p, plen, =
rdlen))
> --	return STAT_BOGUS;=C2=A0
> -+	return 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=A0=C2=A0if (res =3D=3D 1 && sclass =3D=
=3D class)
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0if (stype =3D=3D type)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!expand_workspace(&rrset, &=
rrset_sz, rrsetidx))
> --		return STAT_BOGUS;=C2=A0
> -+		return 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=A0=C2=A0rrset[rrsetidx++] =3D pstart;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -@@ -777,14 +760,54 @@ static int validate_rrset(time_t now, struct
> dns_header *header, size_t plen, in
> -=C2=A0	=C2=A0=C2=A0if (stype =3D=3D T_RRSIG)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rdlen < 18)
> --		return STAT_BOGUS; /* bad packet */=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=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=A0=C2=A0=C2=A0if (gotkey)
> -+		{
> -+		=C2=A0=C2=A0/* If there's more than one SIG, ensure they all
> have same keyname */
> -+		=C2=A0=C2=A0if (extract_name(header, plen, &p, keyname, 0, 0)
> !=3D 1)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+		}
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+		{
> -+		=C2=A0=C2=A0gotkey =3D 1;
> -+		=C2=A0=C2=A0
> -+		=C2=A0=C2=A0if (!extract_name(header, plen, &p, keyname, 1,
> 0))
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+		=C2=A0=C2=A0
> -+		=C2=A0=C2=A0/* RFC 4035 5.3.1 says that the Signer's Name
> field MUST equal
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the name of the zone containing the RRset=
. We
> can't tell that
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for certain, but we can check that=C2=A0=
=C2=A0the RRset
> name is equal to
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0or encloses the signers name, which shoul=
d be
> enough to stop=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0an attacker using signatures made with th=
e key
> of an unrelated=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0zone he controls. Note that the root key =
is
> always allowed. */
> -+		=C2=A0=C2=A0if (*keyname !=3D 0)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *name_start;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (name_start =3D name;
> !hostname_isequal(name_start, keyname); )
> -+			if ((name_start =3D strchr(name_start, '.')))
> -+			=C2=A0=C2=A0name_start++; /* chop a label off and try
> again */
> -+			else
> -+			=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/* 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=A0algo_digest_name(algo))
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0if (!expand_workspace(&sigs, &sig_sz, sigidx))
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0
> -=C2=A0		=C2=A0=C2=A0
> -=C2=A0		=C2=A0=C2=A0sigs[sigidx++] =3D pdata;
> -=C2=A0		}=C2=A0
> -@@ -794,17 +817,45 @@ 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=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, =
rdlen))
> --	return STAT_BOGUS;
> -+	return 0;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0/* RRset empty */
> --=C2=A0=C2=A0if (rrsetidx =3D=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE;=C2=A0
> -+=C2=A0=C2=A0*sigcnt =3D sigidx;
> -+=C2=A0=C2=A0*rrcnt =3D rrsetidx;
> -+
> -+=C2=A0=C2=A0return 1;
> -+}
> -+
> -+/* Validate a single RRset (class, type, name) in the supplied DNS
> reply=C2=A0
> -+=C2=A0=C2=A0=C2=A0Return code:
> -+=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0if it validates.
> -+=C2=A0=C2=A0=C2=A0STAT_SECURE_WILDCARD if it validates and is the result =
of
> wildcard expansion.
> -+=C2=A0=C2=A0=C2=A0(In this case *wildcard_out points to the "body" of the=
 wildcard
> within name.)=C2=A0
> -+=C2=A0=C2=A0=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0signature is wrong, b=
ad packet.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_KEY need DNSKEY to complete validation (name =
is
> returned in keyname)
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0need DS to complete validation =
(name is returned
> in keyname)
> -+
> -+=C2=A0=C2=A0=C2=A0if key is non-NULL, use that key, which has the algo an=
d tag
> given in the params of those names,
> -+=C2=A0=C2=A0=C2=A0otherwise find the key in the cache.
> -=C2=A0
> --=C2=A0=C2=A0/* no RRSIGs */
> --=C2=A0=C2=A0if (sigidx =3D=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_NO_SIG;=C2=A0
> -+=C2=A0=C2=A0=C2=A0name is unchanged on exit. keyname is used as workspace=
 and
> trashed.
> -+
> -+=C2=A0=C2=A0=C2=A0Call explore_rrset first to find and count RRs and sigs.
> -+*/
> -+static int validate_rrset(time_t now, struct dns_header *header,
> size_t plen, int class, int type, int sigidx, int rrsetidx,=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=A0unsigned char *p;
> -+=C2=A0=C2=A0int rdlen, j, name_labels;
> -+=C2=A0=C2=A0struct crec *crecp =3D NULL;
> -+=C2=A0=C2=A0int algo, labels, orig_ttl, key_tag;
> -+=C2=A0=C2=A0u16 *rr_desc =3D get_desc(type);
> -+=C2=A0
> -+=C2=A0=C2=A0if (wildcard_out)
> -+=C2=A0=C2=A0=C2=A0=C2=A0*wildcard_out =3D NULL;
> -=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0name_labels =3D count_labels(name); /* For 4035 5.3.2 check */
> -+
> -=C2=A0=C2=A0=C2=A0/* Sort RRset records into canonical order.=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Note that at this point keyname and da=
emon->workspacename
> buffs are
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unused, and used as workspace by the s=
ort. */
> -@@ -828,44 +879,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=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 8; /* sig_expiration, sig_ince=
ption already checked */
> -=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=A0/* RFC 4035 5.3.1 says that the Signe=
r's Name field MUST
> equal
> --	=C2=A0the name of the zone containing the RRset. We can't tell
> that
> --	=C2=A0for certain, but we can check that=C2=A0=C2=A0the RRset name is
> equal to
> --	=C2=A0or encloses the signers name, which should be enough to
> stop=C2=A0
> --	=C2=A0an attacker using signatures made with the key of an
> unrelated=C2=A0
> --	=C2=A0zone he controls. Note that the root key is always
> allowed. */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (*keyname !=3D 0)
> --	{
> --	=C2=A0=C2=A0int failed =3D 0;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0for (name_start =3D name; !hostname_isequal(name_start,
> keyname); )
> --	=C2=A0=C2=A0=C2=A0=C2=A0if ((name_start =3D strchr(name_start, '.')))
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0name_start++; /* chop a label off an=
d try again */
> --	=C2=A0=C2=A0=C2=A0=C2=A0else
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --		failed =3D 1;
> --		break;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --	=C2=A0=C2=A0/* Bad sig, try another */
> --	=C2=A0=C2=A0if (failed)
> --	=C2=A0=C2=A0=C2=A0=C2=A0continue;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Other 5.3.1 checks */
> --=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=C2=A0=C2=A0=C2=A0if (!(hash =3D hash_find(algo_digest_=
name(algo))) ||
> -=C2=A0	=C2=A0=C2=A0!hash_init(hash, &ctx, &digest))
> -=C2=A0	continue;
> --=09
> -+=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/* OK, we have the signature rec=
ord, see if the relevant
> DNSKEY is in the cache. */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!key && !(crecp =3D cache_fi=
nd_by_name(NULL, keyname, now,
> F_DNSKEY)))
> -=C2=A0	return STAT_NEED_KEY;
> -@@ -971,10 +994,11 @@ static int validate_rrset(time_t now, struct
> dns_header *header, size_t plen, in
> - /* The DNS packet is expected to contain the answer to a DNSKEY
> query.
> -=C2=A0=C2=A0=C2=A0=C2=A0Put all DNSKEYs in the answer which are valid into=
 the cache.
> -=C2=A0=C2=A0=C2=A0=C2=A0return codes:
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=
=C2=A0=C2=A0At least one valid DNSKEY found and in
> cache.
> --	=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0No DNSKEYs found, which=C2=A0=C2=
=A0can be validated
> with 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=C2=A0=C2=A0or self-sign for DNSKEY RRset is not valid,
> bad packet.
> --	=C2=A0STAT_NEED_DS=C2=A0=C2=A0DS records to validate a key not found, na=
me
> in keyname=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0STAT_OK=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Done, key(s) in cache.
> -+	=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0No DNSKE=
Ys found, which=C2=A0=C2=A0can be
> validated with 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=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0or self-sign for DNSKEY RRset is not
> valid, bad packet.
> -+	=C2=A0STAT_NEED_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0DS records to vali=
date a key not found,
> name in keyname=C2=A0
> -+	=C2=A0STAT_NEED_DNSKEY=C2=A0=C2=A0DNSKEY records to validate a key not
> found, name in keyname=C2=A0
> - */
> - int dnssec_validate_by_ds(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname, int class)
> - {
> -@@ -1001,23 +1025,6 @@ 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=A0return STAT_NEED_DS;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0/* If we've cached that DS provably doesn't exist, result mus=
t be
> INSECURE */
> --=C2=A0=C2=A0if (crecp->flags & F_NEG)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE_DS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0/* 4035 5.2=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0If the validator does not support any of th=
e algorithms listed
> in an
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0authenticated DS RRset, then the resolver h=
as no supported
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0authentication path leading from the parent=
 to the child.=C2=A0=C2=A0The
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0resolver should treat this case as it would=
 the case of an
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0authenticated NSEC RRset proving that no DS=
 RRset exists,=C2=A0=C2=A0*/
> --=C2=A0=C2=A0for (recp1 =3D crecp; recp1; recp1 =3D cache_find_by_name(rec=
p1,
> name, now, F_DS))
> --=C2=A0=C2=A0=C2=A0=C2=A0if (hash_find(ds_digest_name(recp1->addr.ds.diges=
t)))
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (!recp1)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE_DS;
> --
> -=C2=A0=C2=A0=C2=A0/* NOTE, we need to find ONE DNSKEY which matches the DS=
 */
> -=C2=A0=C2=A0=C2=A0for (valid =3D 0, j =3D ntohs(header->ancount); j !=3D 0=
 && !valid; j
> --)=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -@@ -1070,7 +1077,8 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0void *ctx;
> -=C2=A0	=C2=A0=C2=A0unsigned char *digest, *ds_digest;
> -=C2=A0	=C2=A0=C2=A0const struct nettle_hash *hash;
> --	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0int sigcnt, rrcnt;
> -+
> -=C2=A0	=C2=A0=C2=A0if (recp1->addr.ds.algo =3D=3D algo &&=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0recp1->addr.ds.keytag =3D=3D ke=
ytag &&
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0recp1->uid =3D=3D (unsigned int=
)class &&
> -@@ -1088,10 +1096,14 @@ 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=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0from_wire(name);
> -=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 (recp1->addr.ds.keylen =3D=3D (in=
t)hash->digest_size
> &&
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(recp1->flags & F_NEG) &&
> -+		=C2=A0=C2=A0recp1->addr.ds.keylen =3D=3D (int)hash->digest_size
> &&
> -=C2=A0		=C2=A0=C2=A0(ds_digest =3D blockdata_retrieve(recp1-
> >addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
> -=C2=A0		=C2=A0=C2=A0memcmp(ds_digest, digest, recp1->addr.ds.keylen)
> =3D=3D 0 &&
> --		=C2=A0=C2=A0validate_rrset(now, header, plen, class,
> T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) =3D=3D
> STAT_SECURE)
> -+		=C2=A0=C2=A0explore_rrset(header, plen, class, T_DNSKEY,
> name, keyname, &sigcnt, &rrcnt) &&
> -+		=C2=A0=C2=A0sigcnt !=3D 0 && rrcnt !=3D 0 &&
> -+		=C2=A0=C2=A0validate_rrset(now, header, plen, class,
> T_DNSKEY, sigcnt, rrcnt, name, keyname,=C2=A0
> -+				=C2=A0NULL, key, rdlen - 4, algo,
> keytag) =3D=3D STAT_SECURE)
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0valid =3D 1;
> -=C2=A0		=C2=A0=C2=A0break;
> -@@ -1112,7 +1124,7 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0/* Ensure we have type, class=C2=A0=C2=A0TTL and length=
 */
> -=C2=A0	=C2=A0=C2=A0if (!(rc =3D extract_name(header, plen, &p, name, 0, 10=
)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; /* bad packet */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0GETSHORT(qtype, p);=C2=A0
> -=C2=A0	=C2=A0=C2=A0GETSHORT(qclass, p);
> -@@ -1198,7 +1210,7 @@ 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=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* commit cache insert. */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_end_insert();
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_SECURE;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_OK;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNS=
KEY");
> -@@ -1207,12 +1219,14 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0
> - /* The DNS packet is expected to contain the answer to a DS query
> -=C2=A0=C2=A0=C2=A0=C2=A0Put all DSs in the answer which are valid into the=
 cache.
> -+=C2=A0=C2=A0=C2=A0Also handles replies which prove that there's no DS at =
this
> location,=C2=A0
> -+=C2=A0=C2=A0=C2=A0either because the zone is unsigned or this isn't a zon=
e cut.
> These are
> -+=C2=A0=C2=A0=C2=A0cached too.
> -=C2=A0=C2=A0=C2=A0=C2=A0return codes:
> --=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0At least=
 one valid DS found and in cache.
> --=C2=A0=C2=A0=C2=A0STAT_NO_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0It'=
s proved there's no DS here.
> --=C2=A0=C2=A0=C2=A0STAT_NO_NS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0It'=
s proved there's no DS _or_ NS here.
> -+=C2=A0=C2=A0=C2=A0STAT_OK=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0At least one valid DS found and in cache.
> -=C2=A0=C2=A0=C2=A0=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0no DS in reply or not signed, fails validation,
> bad packet.
> -=C2=A0=C2=A0=C2=A0=C2=A0STAT_NEED_KEY=C2=A0=C2=A0=C2=A0=C2=A0DNSKEY record=
s to validate a DS not found, name
> in keyname
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0DS record nee=
ded.
> - */
> -=C2=A0
> - int dnssec_validate_ds(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname, int class)
> -@@ -1230,7 +1244,7 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0=C2=A0=C2=A0if (qtype !=3D T_DS || qclass !=3D class)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0val =3D STAT_BOGUS;
> -=C2=A0=C2=A0=C2=A0else
> --=C2=A0=C2=A0=C2=A0=C2=A0val =3D dnssec_validate_reply(now, header, plen, =
name, keyname,
> NULL, &neganswer, &nons);
> -+=C2=A0=C2=A0=C2=A0=C2=A0val =3D dnssec_validate_reply(now, header, plen, =
name, keyname,
> NULL, 0, &neganswer, &nons);
> -=C2=A0=C2=A0=C2=A0/* Note dnssec_validate_reply() will have cached positiv=
e answers
> */
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (val =3D=3D STAT_INSECURE)
> -@@ -1242,22 +1256,21 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (!(p =3D skip_section(p, ntohs(header->ancount), head=
er, plen)))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0val =3D STAT_BOGUS;
> --=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0/* If we return STAT_NO_SIG, name contains the name of the DS
> query */
> --=C2=A0=C2=A0if (val =3D=3D STAT_NO_SIG)
> --=C2=A0=C2=A0=C2=A0=C2=A0return val;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* If the key needed to validate the DS is on the same d=
omain as
> the DS, we'll
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0loop getting nowhere. Stop that now. T=
his can happen of the DS
> answer comes
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0from the DS's zone, and not the parent=
 zone. */
> --=C2=A0=C2=A0if (val =3D=3D STAT_BOGUS ||=C2=A0=C2=A0(val =3D=3D STAT_NEED=
_KEY &&
> hostname_isequal(name, keyname)))
> -+=C2=A0=C2=A0if (val =3D=3D STAT_BOGUS || (val =3D=3D STAT_NEED_KEY &&
> hostname_isequal(name, keyname)))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_UPSTREAM=
, name, NULL, "BOGUS DS");
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (val !=3D STAT_SECURE)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return val;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0/* By here, the answer is proved secure, and a positive =
answer
> has been cached. */
> --=C2=A0=C2=A0if (val =3D=3D STAT_SECURE && neganswer)
> -+=C2=A0=C2=A0if (neganswer)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int rdlen, flags =3D F_FORWARD |=
 F_DS | F_NEG | F_DNSSECOK;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned long ttl, minttl =3D UL=
ONG_MAX;
> -@@ -1317,15 +1330,14 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0cache_end_insert();=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0
> --	=C2=A0=C2=A0log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no
> delegation" : "no DS");
> -+	=C2=A0=C2=A0log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
> -=C2=A0	}
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return nons ? STAT_NO_NS : STAT_NO_DS=
;=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> --=C2=A0=C2=A0return val;
> -+=C2=A0=C2=A0return STAT_OK;
> - }
> -=C2=A0
> -+
> - /* 4034 6.1 */
> - static int hostname_cmp(const char *a, const char *b)
> - {
> -@@ -1452,7 +1464,7 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> -=C2=A0=C2=A0=C2=A0int mask =3D 0x80 >> (type & 0x07);
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (nons)
> --=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 0;
> -+=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 1;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Find NSEC record that proves name doesn't exist */
> -=C2=A0=C2=A0=C2=A0for (i =3D 0; i < nsec_count; i++)
> -@@ -1480,9 +1492,22 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> -=C2=A0	=C2=A0=C2=A0/* rdlen is now length of type map, and p points to it =
*/
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0/* If we can prove that there's no NS record, return th=
at
> information. */
> --	=C2=A0=C2=A0if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >>
> T_NS)) =3D=3D 0)
> --	=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 1;
> -+	=C2=A0=C2=A0if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >>
> T_NS)) !=3D 0)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 0;
> -=C2=A0	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (rdlen >=3D 2 && p[0] =3D=3D 0)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* A CNAME answer would also be vali=
d, so if there's
> a CNAME is should=C2=A0
> -+		=C2=A0have been returned. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((p[2] & (0x80 >> T_CNAME)) !=3D =
0)
> -+		return STAT_BOGUS;
> -+	=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 SOA bit is set for a DS re=
cord, then we
> have the
> -+		=C2=A0DS from the wrong side of the delegation. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (type =3D=3D T_DS && (p[2] & (0x8=
0 >> T_SOA)) !=3D 0)
> -+		return STAT_BOGUS;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0}
> -+
> -=C2=A0	=C2=A0=C2=A0while (rdlen >=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=A0if (!CHECK_LEN(header, p, plen,=
 rdlen))
> -@@ -1586,7 +1611,7 @@ static int base32_decode(char *in, unsigned
> char *out)
> - static int check_nsec3_coverage(struct dns_header *header, size_t
> plen, int digest_len, unsigned char *digest, int type,
> -=C2=A0				char *workspace1, char *workspace2,
> unsigned char **nsecs, int nsec_count, int *nons)
> - {
> --=C2=A0=C2=A0int i, hash_len, salt_len, base32_len, rdlen;
> -+=C2=A0=C2=A0int i, hash_len, salt_len, base32_len, rdlen, flags;
> -=C2=A0=C2=A0=C2=A0unsigned char *p, *psave;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0for (i =3D 0; i < nsec_count; i++)
> -@@ -1599,7 +1624,9 @@ static int check_nsec3_coverage(struct
> dns_header *header, size_t plen, int dige
> -=C2=A0	p +=3D 8; /* class, type, TTL */
> -=C2=A0	GETSHORT(rdlen, p);
> -=C2=A0	psave =3D p;
> --	p +=3D 4; /* algo, flags, iterations */
> -+	p++; /* algo */
> -+	flags =3D *p++; /* flags */
> -+	p +=3D 2; /* iterations */
> -=C2=A0	salt_len =3D *p++; /* salt_len */
> -=C2=A0	p +=3D salt_len; /* salt */
> -=C2=A0	hash_len =3D *p++; /* p now points to next hashed name */
> -@@ -1626,16 +1653,29 @@ static int check_nsec3_coverage(struct
> dns_header *header, size_t plen, int dige
> -=C2=A0		=C2=A0=C2=A0return 0;
> -=C2=A0	=09
> -=C2=A0		/* If we can prove that there's no NS record,
> return that information. */
> --		if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] &
> (0x80 >> T_NS)) =3D=3D 0)
> --		=C2=A0=C2=A0*nons =3D 1;
> -+		if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] &
> (0x80 >> T_NS)) !=3D 0)
> -+		=C2=A0=C2=A0*nons =3D 0;
> -=C2=A0	=09
> -+		if (rdlen >=3D 2 && p[0] =3D=3D 0)
> -+		=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0/* A CNAME answer would also be valid, so if
> there's a CNAME is should=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0have been returned. */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if ((p[2] & (0x80 >> T_CNAME)) !=3D 0)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0/* If the SOA bit is set for a DS record, then
> we have the
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0DS from the wrong side of the=
 delegation. */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if (type =3D=3D T_DS && (p[2] & (0x80 >> T_SOA)=
) !=3D
> 0)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+		=C2=A0=C2=A0}
> -+
> -=C2=A0		while (rdlen >=3D 2)
> -=C2=A0		=C2=A0=C2=A0{
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0if (p[0] =3D=3D type >> 8)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0			/* Does the NSEC3 say our type exists? */
> -=C2=A0			if (offset < p[1] && (p[offset+2] & mask)
> !=3D 0)
> --			=C2=A0=C2=A0return STAT_BOGUS;
> -+			=C2=A0=C2=A0return 0;
> -=C2=A0		=09
> -=C2=A0			break; /* finshed checking */
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -@@ -1643,7 +1683,7 @@ static int check_nsec3_coverage(struct
> dns_header *header, size_t plen, int dige
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0rdlen -=3D p[1];
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0p +=3D=C2=A0=C2=A0p[1];
> -=C2=A0		=C2=A0=C2=A0}
> --
> -+	=09
> -=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=A0else if (rc < 0)
> -@@ -1651,16 +1691,27 @@ static int check_nsec3_coverage(struct
> dns_header *header, size_t plen, int dige
> -=C2=A0		/* Normal case, hash falls between NSEC3 name-hash
> and next domain name-hash,
> -=C2=A0		=C2=A0=C2=A0=C2=A0wrap around case, name-hash falls between NSEC3
> name-hash and end */
> -=C2=A0		if (memcmp(p, digest, digest_len) >=3D 0 ||
> memcmp(workspace2, p, digest_len) >=3D 0)
> --		=C2=A0=C2=A0return 1;
> -+		=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if ((flags & 0x01) && nons) /* opt out */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 0;
> -+
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return 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=A0=C2=A0else=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		/* wrap around case, name falls between start and
> next domain name */
> -=C2=A0		if (memcmp(workspace2, p, digest_len) >=3D 0 &&
> memcmp(p, digest, digest_len) >=3D 0)
> --		=C2=A0=C2=A0return 1;
> -+		=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if ((flags & 0x01) && nons) /* opt out */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 0;
> -+
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return 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=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+
> -=C2=A0=C2=A0=C2=A0return 0;
> - }
> -=C2=A0
> -@@ -1673,7 +1724,7 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0=C2=A0=C2=A0char *closest_encloser, *next_closest, *wildcard;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (nons)
> --=C2=A0=C2=A0=C2=A0=C2=A0*nons =3D 0;
> -+=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=A0=C2=A0an algorithm we support (currently onl=
y algo =3D=3D 1).
> -@@ -1813,16 +1864,81 @@ 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=A0return STAT_SECURE;
> - }
> --=C2=A0=C2=A0=C2=A0=C2=A0
> --/* Validate all the RRsets in the answer and authority sections of
> the reply (4035:3.2.3) */
> --/* Returns are the same as validate_rrset, plus the class if the
> missing key is in *class */
> -+
> -+/* Check signing status of name.
> -+=C2=A0=C2=A0=C2=A0returns:
> -+=C2=A0=C2=A0=C2=A0STAT_SECURE zone is signed.
> -+=C2=A0=C2=A0=C2=A0STAT_INSECURE zone proved unsigned.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DS require DS record of name returned in keyn=
ame.
> -+=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0name returned unaltered.
> -+*/
> -+static int zone_status(char *name, int class, char *keyname, time_t
> now)
> -+{
> -+=C2=A0=C2=A0int name_start =3D strlen(name);
> -+=C2=A0=C2=A0struct crec *crecp;
> -+=C2=A0=C2=A0char *p;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0while (1)
> -+=C2=A0=C2=A0=C2=A0=C2=A0{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0strcpy(keyname, &name[name_start]);
> -+=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_name(NU=
LL, keyname, now, F_DS)))
> -+	return STAT_NEED_DS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	do=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=A0=C2=A0=C2=A0=C2=A0{
> -+		/* F_DNSSECOK misused in DS cache records to non-
> existance of NS record.
> -+		=C2=A0=C2=A0=C2=A0F_NEG && !F_DNSSECOK implies that we've proved
> there's no DS record here,
> -+		=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=A0of a zone. We only prove that the DNS tree below
> a node is unsigned when
> -+		=C2=A0=C2=A0=C2=A0we prove that we're at a zone cut AND there's no
> DS record.
> -+		*/	=C2=A0=C2=A0
> -+		if (crecp->flags & F_NEG)
> -+		=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_DNSSECOK)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; /* proved no =
DS here */
> -+		=C2=A0=C2=A0}
> -+		else if (!ds_digest_name(crecp->addr.ds.digest) ||
> !algo_digest_name(crecp->addr.ds.algo))
> -+		=C2=A0=C2=A0return STAT_INSECURE; /* algo we can't use -
> insecure */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0}
> -+	while ((crecp =3D cache_find_by_name(crecp, keyname, now,
> F_DS)));
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (name_start =3D=3D 0)
> -+	break;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (p =3D &name[name_start-2]; (*p !=
=3D '.') && (p !=3D name); p
> --);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (p !=3D name)
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p++;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0name_start =3D p - name;
> -+=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> -+
> -+=C2=A0=C2=A0return STAT_SECURE;
> -+}
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+/* Validate all the RRsets in the answer and authority sections of
> the reply (4035:3.2.3)=C2=A0
> -+=C2=A0=C2=A0=C2=A0Return code:
> -+=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0if it validates.
> -+=C2=A0=C2=A0=C2=A0STAT_INSECURE at least one RRset not validated, because=
 in
> unsigned zone.
> -+=C2=A0=C2=A0=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0signature is wrong, b=
ad packet, no validation
> where there should be.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_KEY need DNSKEY to complete validation (name =
is
> returned in keyname, class in *class)
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0need DS to complete validation =
(name is returned
> in keyname)=C2=A0
> -+*/
> - int dnssec_validate_reply(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname,=C2=A0
> --			=C2=A0=C2=A0int *class, int *neganswer, int *nons)
> -+			=C2=A0=C2=A0int *class, int check_unsigned, int
> *neganswer, int *nons)
> - {
> --=C2=A0=C2=A0unsigned char *ans_start, *qname, *p1, *p2, **nsecs;
> --=C2=A0=C2=A0int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qty=
pe;
> --=C2=A0=C2=A0int i, j, rc, nsec_count, cname_count =3D CNAME_CHAIN;
> --=C2=A0=C2=A0int nsec_type =3D 0, have_answer =3D 0;
> -+=C2=A0=C2=A0static unsigned char **targets =3D NULL;
> -+=C2=A0=C2=A0static int target_sz =3D 0;
> -+
> -+=C2=A0=C2=A0unsigned char *ans_start, *p1, *p2, **nsecs;
> -+=C2=A0=C2=A0int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qty=
pe,
> targetidx;
> -+=C2=A0=C2=A0int i, j, rc, nsec_count;
> -+=C2=A0=C2=A0int nsec_type;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (neganswer)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*neganswer =3D 0;
> -@@ -1833,70 +1949,51 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0=C2=A0=C2=A0if (RCODE(header) !=3D NXDOMAIN && RCODE(header) !=3D NO=
ERROR)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE;
> -=C2=A0
> --=C2=A0=C2=A0qname =3D p1 =3D (unsigned char *)(header+1);
> -+=C2=A0=C2=A0p1 =3D (unsigned char *)(header+1);
> -=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0/* Find all the targets we're looking for answers to.
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0The zeroth array element is for the query, =
subsequent ones
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for CNAME targets, unless the query is for =
a CNAME. */
> -+
> -+=C2=A0=C2=A0if (!expand_workspace(&targets, &target_sz, 0))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0targets[0] =3D p1;
> -+=C2=A0=C2=A0targetidx =3D 1;
> -+=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (!extract_name(header, plen, &p1, name, 1, 4))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --
> -+=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0GETSHORT(qtype, p1);
> -=C2=A0=C2=A0=C2=A0GETSHORT(qclass, p1);
> -=C2=A0=C2=A0=C2=A0ans_start =3D p1;
> --
> --=C2=A0=C2=A0if (qtype =3D=3D T_ANY)
> --=C2=A0=C2=A0=C2=A0=C2=A0have_answer =3D 1;
> -=C2=A0=C2=A0
> --=C2=A0=C2=A0/* Can't validate an RRISG query */
> -+=C2=A0=C2=A0/* Can't validate an RRSIG query */
> -=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_RRSIG)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE;
> --=C2=A0
> -- cname_loop:
> --=C2=A0=C2=A0for (j =3D ntohs(header->ancount); j !=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/* leave pointer to missing name in q=
name */
> --=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=A0if (!(rc =3D extract_name(header, ple=
n, &p1, name, 0, 10)))
> --	return STAT_BOGUS; /* 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=A0GETSHORT(type2, p1);=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class2, p1);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p1 +=3D 4; /* TTL */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen2, p1);
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D 1 && qclass =3D=3D clas=
s2)
> --	{
> --	=C2=A0=C2=A0/* Do we have an answer for the question? */
> --	=C2=A0=C2=A0if (type2 =3D=3D qtype)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0have_answer =3D 1;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0else if (type2 =3D=3D T_CNAME)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0qname =3D p1;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* looped CNAMES */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!cname_count-- || !extract_name(=
header, plen,
> &p1, name, 1, 0))
> --		return STAT_BOGUS;
> --	=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=A0p1 =3D ans_start;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0goto cname_loop;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	}=C2=A0
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p1, plen, rdle=
n2))
> --	return STAT_BOGUS;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0if (neganswer && !have_answer)
> --=C2=A0=C2=A0=C2=A0=C2=A0*neganswer =3D 1;
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0/* No data, therefore no sigs */
> --=C2=A0=C2=A0if (ntohs(header->ancount) + ntohs(header->nscount) =3D=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*keyname =3D 0;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_NO_SIG;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> -+=C2=A0=C2=A0if (qtype !=3D T_CNAME)
> -+=C2=A0=C2=A0=C2=A0=C2=A0for (j =3D ntohs(header->ancount); j !=3D 0; j--)=
=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	if (!(p1 =3D skip_name(p1, header, plen, 10)))
> -+	=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+=09
> -+	GETSHORT(type2, p1);=C2=A0
> -+	p1 +=3D 6; /* class, TTL */
> -+	GETSHORT(rdlen2, p1);=C2=A0=C2=A0
> -+=09
> -+	if (type2 =3D=3D T_CNAME)
> -+	=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0if (!expand_workspace(&targets, &target_sz, targ=
etidx))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0targets[targetidx++] =3D p1; /* pointer to targe=
t name */
> -+	=C2=A0=C2=A0}
> -+=09
> -+	if (!ADD_RDLEN(header, p1, plen, rdlen2))
> -+	=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0for (p1 =3D ans_start, i =3D 0; i < ntohs(header->ancoun=
t) +
> ntohs(header->nscount); i++)
> -=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, =
&p1, name, 1, 10))
> -@@ -1931,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0/* Not done, validate now */
> -=C2=A0	=C2=A0=C2=A0if (j =3D=3D i)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ttl, keytag, algo, digest, type_=
covered;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ttl, keytag, algo, digest, type_=
covered, sigcnt,
> rrcnt;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *psave;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr a;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct blockdata *key;
> -@@ -1939,143 +2036,186 @@ int dnssec_validate_reply(time_t now,
> struct dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *wildname;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int have_wildcard =3D 0;
> -=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rc =3D validate_rrset(now, header, p=
len, class1, type1,
> name, keyname, &wildname, NULL, 0, 0, 0);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD)
> --		{
> --		=C2=A0=C2=A0have_wildcard =3D 1;
> --
> --		=C2=A0=C2=A0/* An attacker replay a wildcard answer with a
> different
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0answer and overlay a genuine RR. To prove=
 this
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0hasn't happened, the answer must prove th=
at
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the gennuine record doesn't exist. Check =
that
> here. */
> --		=C2=A0=C2=A0if (!nsec_type && !(nsec_type =3D
> find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* No NSECs or bad packet */
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> --		=C2=A0=C2=A0=C2=A0=C2=A0rc =3D prove_non_existence_nsec(header, plen,
> nsecs, nsec_count, daemon->workspacename, keyname, name, type1,
> NULL);
> --		=C2=A0=C2=A0else
> --		=C2=A0=C2=A0=C2=A0=C2=A0rc =3D prove_non_existence_nsec3(header, plen,
> nsecs, nsec_count, daemon->workspacename,=C2=A0
> --						=C2=A0=C2=A0=C2=A0keyname, name,
> type1, wildname, NULL);
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> --		=C2=A0=C2=A0=C2=A0=C2=A0return rc;
> --		}=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (rc !=3D STAT_SECURE)
> --		{
> --		=C2=A0=C2=A0if (class)
> --		=C2=A0=C2=A0=C2=A0=C2=A0*class =3D class1; /* Class for DS or DNSKEY */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!explore_rrset(header, plen, cla=
ss1, type1, name,
> keyname, &sigcnt, &rrcnt))
> -+		return STAT_BOGUS;
> -=C2=A0
> --		=C2=A0=C2=A0if (rc =3D=3D STAT_NO_SIG)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* No signatures for RRset. We can b=
e configured to
> assume this is OK and return a INSECURE result. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (sigcnt =3D=3D 0)
> -+		{
> -+		=C2=A0=C2=A0if (check_unsigned)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* If we dropped off the end of a C=
NAME
> chain, return
> --			=C2=A0STAT_NO_SIG and the last name is keyname.
> This is used for proving non-existence
> --			=C2=A0if DS records in CNAME chains. */
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (cname_count =3D=3D CNAME_CHAIN =
|| i <
> ntohs(header->ancount))=C2=A0
> --			/* No CNAME chain, or no sig in answer
> section, return empty name. */
> --			*keyname =3D 0;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (!extract_name(header, plen=
, &qname,
> keyname, 1, 0))
> --			return STAT_BOGUS;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rc =3D zone_status(name, class1, ke=
yname, now);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE)
> -+			rc =3D STAT_BOGUS;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (class)
> -+			=C2=A0*class =3D class1; /* Class for NEED_DS or
> NEED_DNSKEY */
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0
> -+		=C2=A0=C2=A0else=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0rc =3D STAT_INSECURE;=C2=A0
> -+		=C2=A0=C2=A0
> -=C2=A0		=C2=A0=C2=A0return rc;
> -=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/* Cache RRsigs in answer section, a=
nd if we just
> validated a DS RRset, cache it */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_start_insert();
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* explore_rrset() gives us key name=
 from sigs in
> keyname.
> -+		=C2=A0Can't overwrite name here. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0strcpy(daemon->workspacename, keynam=
e);
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rc =3D zone_status(daemon->workspace=
name, class1,
> keyname, now);
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> -+		{
> -+		=C2=A0=C2=A0/* Zone is insecure, don't need to validate RRset
> */
> -+		=C2=A0=C2=A0if (class)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0*class =3D class1; /* Class for NEED_DS or
> NEED_DNSKEY */
> -+		=C2=A0=C2=A0return rc;
> -+		}=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=A0rc =3D validate_rrset(now, header, p=
len, class1, type1,
> sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 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=A0for (p2 =3D ans_start, j =3D 0; j < =
ntohs(header-
> >ancount); j++)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_BOGUS || rc =3D=
=3D STAT_NEED_KEY || rc =3D=3D
> STAT_NEED_DS)
> -=C2=A0		{
> --		=C2=A0=C2=A0if (!(rc =3D extract_name(header, plen, &p2, name,
> 0, 10)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+		=C2=A0=C2=A0if (class)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0*class =3D class1; /* Class for DS or DNSKEY */
> -+		=C2=A0=C2=A0return rc;
> -+		}=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> -+		{
> -+		=C2=A0=C2=A0/* rc is now STAT_SECURE or STAT_SECURE_WILDCARD
> */
> -+		=C2=A0
> -+		=C2=A0=C2=A0/* Note if we've validated either the answer to
> the question
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0or the target of a CNAME. Any not noted w=
ill
> need NSEC or
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0to be in unsigned space. */
> -+
> -+		=C2=A0=C2=A0for (j =3D 0; j <targetidx; j++)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if ((p2 =3D targets[j]))
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+			if (!(rc =3D extract_name(header, plen, &p2,
> name, 0, 10)))
> -+			=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+		=09
> -+			if (class1 =3D=3D qclass && rc =3D=3D 1 && (type1
> =3D=3D T_CNAME || type1 =3D=3D qtype || qtype =3D=3D T_ANY ))
> -+			=C2=A0=C2=A0targets[j] =3D NULL;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+			=C2=A0=C2=A0=C2=A0=C2=A0
> -+		=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0have_wildcard =3D 1;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --		=C2=A0=C2=A0GETSHORT(type2, p2);
> --		=C2=A0=C2=A0GETSHORT(class2, p2);
> --		=C2=A0=C2=A0GETLONG(ttl, p2);
> --		=C2=A0=C2=A0GETSHORT(rdlen2, p2);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (!CHECK_LEN(header, p2, plen, rdlen2))
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (class2 =3D=3D class1 && rc =3D=3D 1)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{=C2=A0
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0psave =3D p2;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* An attacker replay a wildcard an=
swer with
> a different
> -+			=C2=A0answer and overlay a genuine RR. To prove
> this
> -+			=C2=A0hasn't happened, the answer must prove
> that
> -+			=C2=A0the gennuine record doesn't exist. Check
> that here. */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(nsec_type =3D find_nsec_recor=
ds(header,
> plen, &nsecs, &nsec_count, class1)))
> -+			return STAT_BOGUS; /* No NSECs or 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/* Note that we may not yet have va=
lidated
> the NSEC/NSEC3 RRsets. Since the check
> -+			=C2=A0below returns either SECURE or BOGUS,
> that's not a problem. If the RRsets later fail
> -+			=C2=A0we'll return BOGUS then. */
> -=C2=A0
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (type1 =3D=3D T_DS && type2 =3D=
=3D T_DS)
> --			{
> --			=C2=A0=C2=A0if (rdlen2 < 4)
> --			=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0GETSHORT(keytag, p2);
> --			=C2=A0=C2=A0algo =3D *p2++;
> --			=C2=A0=C2=A0digest =3D *p2++;
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0/* Cache needs to known class for DNSSEC
> stuff */
> --			=C2=A0=C2=A0a.addr.dnssec.class =3D class2;
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0if ((key =3D blockdata_alloc((char*)p2,
> rdlen2 - 4)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(crecp =3D cache_insert(name,=
 &a,
> now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
> --				blockdata_free(key);
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --				{
> --				=C2=A0=C2=A0a.addr.keytag =3D keytag;
> --				=C2=A0=C2=A0log_query(F_NOEXTRA | F_KEYTAG |
> F_UPSTREAM, name, &a, "DS keytag %u");
> --				=C2=A0=C2=A0crecp->addr.ds.digest =3D digest;
> --				=C2=A0=C2=A0crecp->addr.ds.keydata =3D key;
> --				=C2=A0=C2=A0crecp->addr.ds.algo =3D algo;
> --				=C2=A0=C2=A0crecp->addr.ds.keytag =3D keytag;
> --				=C2=A0=C2=A0crecp->addr.ds.keylen =3D rdlen2 -
> 4;=C2=A0
> --				}=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0}
> --			}
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (type2 =3D=3D T_RRSIG)
> --			{
> --			=C2=A0=C2=A0if (rdlen2 < 18)
> --			=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> -+			rc =3D prove_non_existence_nsec(header, plen,
> nsecs, nsec_count, daemon->workspacename, keyname, name, type1,
> NULL);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+			rc =3D prove_non_existence_nsec3(header,
> plen, nsecs, nsec_count, daemon->workspacename,=C2=A0
> -+						=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0keyname,
> name, type1, wildname, NULL);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_BOGUS)
> -+			return rc;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> -+		=C2=A0=C2=A0
> -+		=C2=A0=C2=A0/* Cache RRsigs in answer section, and if we just
> validated a DS RRset, cache it */
> -+		=C2=A0=C2=A0/* Also note if the RRset is the answer to the
> question, or the target of a CNAME */
> -+		=C2=A0=C2=A0cache_start_insert();
> -+		=C2=A0=C2=A0
> -+		=C2=A0=C2=A0for (p2 =3D ans_start, j =3D 0; j < ntohs(header-
> >ancount); j++)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(rc =3D extract_name(header, p=
len, &p2,
> name, 0, 10)))
> -+			return STAT_BOGUS; /* 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=A0GETSHORT(type2, p2);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class2, p2);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(ttl, p2);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen2, p2);
> -+		=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_LEN(header, p2, plen, rd=
len2))
> -+			return STAT_BOGUS; /* 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=A0if (class2 =3D=3D class1 && rc =3D=
=3D 1)
> -+			{=C2=A0
> -+			=C2=A0=C2=A0psave =3D p2;
> -=C2=A0			=C2=A0=C2=A0
> --			=C2=A0=C2=A0GETSHORT(type_covered, p2);
> --
> --			=C2=A0=C2=A0if (type_covered =3D=3D type1 &&=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(type_covered =3D=3D T_A || type_c=
overed
> =3D=3D T_AAAA ||
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0type_covered =3D=3D T_CNAME =
||
> type_covered =3D=3D T_DS ||=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0type_covered =3D=3D T_DNSKEY=
 ||
> type_covered =3D=3D T_PTR))=C2=A0
> -+			=C2=A0=C2=A0if (type1 =3D=3D T_DS && type2 =3D=3D T_DS)
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.type =3D type_covere=
d;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.class =3D class1;
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rdlen2 < 4)
> -+				return STAT_BOGUS; /* 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=A0algo =3D *p2++;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p2 +=3D 13; /* labels, orig_ttl,
> expiration, inception */
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(keytag, p2);
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0algo =3D *p2++;
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0digest =3D *p2++;
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Cache needs to known class for
> DNSSEC stuff */
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.class =3D class2;
> -=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/* We don't cache sigs for wildcard
> answers, because to reproduce the
> --				=C2=A0answer from the cache will require
> one or more NSEC/NSEC3 records=C2=A0
> --				=C2=A0which we don't cache. The lack of
> the RRSIG ensures that a query for
> --				=C2=A0this RRset asking for a secure
> answer will always be forwarded. */
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!have_wildcard && (key =3D
> blockdata_alloc((char*)psave, rdlen2)))
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((key =3D blockdata_alloc((char=
*)p2,
> rdlen2 - 4)))
> -=C2=A0				{
> --				=C2=A0=C2=A0if (!(crecp =3D cache_insert(name,
> &a, now, ttl,=C2=A0=C2=A0F_FORWARD | F_DNSKEY | F_DS)))
> -+				=C2=A0=C2=A0if (!(crecp =3D cache_insert(name,
> &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
> -=C2=A0				=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(key);
> -=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=A0crecp->addr.sig.keydata =3D
> key;
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.keylen =3D
> rdlen2;
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.keytag =3D
> keytag;
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.type_covered
> =3D type_covered;
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.algo =3D algo;
> -+				=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=A0crecp->addr.ds.digest =3D
> digest;
> -+				=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=A0crecp->addr.ds.algo =3D algo;
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keytag =3D
> keytag;
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keylen =3D
> rdlen2 - 4;=C2=A0
> -+				=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> -+				}
> -+			=C2=A0=C2=A0=C2=A0=C2=A0}
> -+			=C2=A0=C2=A0else if (type2 =3D=3D T_RRSIG)
> -+			=C2=A0=C2=A0=C2=A0=C2=A0{
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rdlen2 < 18)
> -+				return STAT_BOGUS; /* 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=A0GETSHORT(type_covered, p2);
> -+			=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 type1 &&=
=C2=A0
> -+				=C2=A0=C2=A0(type_covered =3D=3D T_A ||
> type_covered =3D=3D T_AAAA ||
> -+				=C2=A0=C2=A0=C2=A0type_covered =3D=3D T_CNAME ||
> type_covered =3D=3D T_DS ||=C2=A0
> -+				=C2=A0=C2=A0=C2=A0type_covered =3D=3D T_DNSKEY ||
> type_covered =3D=3D T_PTR))=C2=A0
> -+				{
> -+				=C2=A0=C2=A0a.addr.dnssec.type =3D
> type_covered;
> -+				=C2=A0=C2=A0a.addr.dnssec.class =3D class1;
> -+				=C2=A0=C2=A0
> -+				=C2=A0=C2=A0algo =3D *p2++;
> -+				=C2=A0=C2=A0p2 +=3D 13; /* labels, orig_ttl,
> expiration, inception */
> -+				=C2=A0=C2=A0GETSHORT(keytag, p2);
> -+				=C2=A0=C2=A0
> -+				=C2=A0=C2=A0/* We don't cache sigs for
> wildcard answers, because to reproduce the
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0answer from the cache will
> require one or more NSEC/NSEC3 records=C2=A0
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0which we don't cache. The lack
> of the RRSIG ensures that a query for
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0this RRset asking for a secure
> answer will always be forwarded. */
> -+				=C2=A0=C2=A0if (!have_wildcard && (key =3D
> blockdata_alloc((char*)psave, rdlen2)))
> -+				=C2=A0=C2=A0=C2=A0=C2=A0{
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(crecp =3D
> cache_insert(name, &a, now, ttl,=C2=A0=C2=A0F_FORWARD | F_DNSKEY | F_DS)))
> -+					blockdata_free(key);
> -+				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+					{
> -+					=C2=A0=C2=A0crecp->addr.sig.keydata =3D
> key;
> -+					=C2=A0=C2=A0crecp->addr.sig.keylen =3D
> rdlen2;
> -+					=C2=A0=C2=A0crecp->addr.sig.keytag =3D
> keytag;
> -+					=C2=A0=C2=A0crecp-
> >addr.sig.type_covered =3D type_covered;
> -+					=C2=A0=C2=A0crecp->addr.sig.algo =3D
> algo;
> -+					}
> -=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=A0p2 =3D 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=C2=A0p2 =3D psave;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p2, plen, rd=
len2))
> -+			return STAT_BOGUS; /* bad packet */
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (!ADD_RDLEN(header, p2, plen, rdlen2))
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+		=C2=A0=C2=A0cache_end_insert();
> -=C2=A0		}
> --		=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_end_insert();
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	}
> -=C2=A0
> -@@ -2083,143 +2223,49 @@ int dnssec_validate_reply(time_t now,
> struct dns_header *header, size_t plen, ch
> -=C2=A0	return STAT_BOGUS;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> --=C2=A0=C2=A0/* OK, all the RRsets validate, now see if we have a NODATA or
> NXDOMAIN reply */
> --=C2=A0=C2=A0if (have_answer)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_SECURE;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0/* NXDOMAIN or NODATA reply, prove that (name, class1, type1)
> can't exist */
> --=C2=A0=C2=A0/* First marshall the NSEC records, if we've not done it
> previously */
> --=C2=A0=C2=A0if (!nsec_type && !(nsec_type =3D find_nsec_records(header, p=
len,
> &nsecs, &nsec_count, qclass)))
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* No NSEC records. If we dropped off=
 the end of a CNAME
> chain, return
> --	=C2=A0STAT_NO_SIG and the last name is keyname. This is used for
> proving non-existence
> --	=C2=A0if DS records in CNAME chains. */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (cname_count =3D=3D CNAME_CHAIN) /=
* No CNAME chain, return
> empty name. */
> --	*keyname =3D 0;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (!extract_name(header, plen, =
&qname, keyname, 1, 0))
> --	return STAT_BOGUS;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_NO_SIG; /* No NSECs, this=
 is probably a dangling
> CNAME pointing into
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0an unsigned zone. Return STAT_NO_SIG
> to cause this to be proved. */
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0/* Get name of missing answer */
> --=C2=A0=C2=A0if (!extract_name(header, plen, &qname, name, 1, 0))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> --=C2=A0=C2=A0=C2=A0=C2=A0return prove_non_existence_nsec(header, plen, nse=
cs,
> nsec_count, daemon->workspacename, keyname, name, qtype, nons);
> --=C2=A0=C2=A0else
> --=C2=A0=C2=A0=C2=A0=C2=A0return prove_non_existence_nsec3(header, plen, ns=
ecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
> --}
> --
> --/* Chase the CNAME chain in the packet until the first record which
> _doesn't validate.
> --=C2=A0=C2=A0=C2=A0Needed for proving answer in unsigned space.
> --=C2=A0=C2=A0=C2=A0Return STAT_NEED_*=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0STAT_BOGUS - =
error
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0STAT_INSECURE=
 - name of first non-secure record in name=C2=A0
> --*/
> --int dnssec_chase_cname(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname)
> --{
> --=C2=A0=C2=A0unsigned char *p =3D (unsigned char *)(header+1);
> --=C2=A0=C2=A0int type, class, qclass, rdlen, j, rc;
> --=C2=A0=C2=A0int cname_count =3D CNAME_CHAIN;
> --=C2=A0=C2=A0char *wildname;
> --
> --=C2=A0=C2=A0/* Get question */
> --=C2=A0=C2=A0if (!extract_name(header, plen, &p, name, 1, 4))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0p +=3D2; /* type */
> --=C2=A0=C2=A0GETSHORT(qclass, p);
> --
> --=C2=A0=C2=A0while (1)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (j =3D ntohs(header->ancount); j =
!=3D 0; j--)=C2=A0
> --	{
> --	=C2=A0=C2=A0if (!(rc =3D extract_name(header, plen, &p, name, 0, 10)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0GETSHORT(type, p);=C2=A0
> --	=C2=A0=C2=A0GETSHORT(class, p);
> --	=C2=A0=C2=A0p +=3D 4; /* TTL */
> --	=C2=A0=C2=A0GETSHORT(rdlen, p);
> --
> --	=C2=A0=C2=A0/* Not target, loop */
> --	=C2=A0=C2=A0if (rc =3D=3D 2 || qclass !=3D class)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdle=
n))
> --		return STAT_BOGUS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0continue;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0/* Got to end of CNAME chain. */
> --	=C2=A0=C2=A0if (type !=3D T_CNAME)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0/* validate CNAME chain, return if insecure or need more
> data */
> --	=C2=A0=C2=A0rc =3D validate_rrset(now, header, plen, class, type, name,
> keyname, &wildname, NULL, 0, 0, 0);
> --	=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int nsec_type, nsec_count, i;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char **nsecs;
> --
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* An attacker can replay a wildcard=
 answer with a
> different
> --		=C2=A0answer and overlay a genuine RR. To prove this
> --		=C2=A0hasn't happened, the answer must prove that
> --		=C2=A0the genuine record doesn't exist. Check that here.
> */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(nsec_type =3D find_nsec_record=
s(header, plen,
> &nsecs, &nsec_count, class)))
> --		return STAT_BOGUS; /* No NSECs or 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/* Note that we're called here becau=
se something
> didn't validate in validate_reply,
> --		=C2=A0so we can't assume that any NSEC records have been
> validated. We do them by steam here */
> --
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (i =3D 0; i < nsec_count; i++)
> --		{
> --		=C2=A0=C2=A0unsigned char *p1 =3D nsecs[i];
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (!extract_name(header, plen, &p1, daemon-
> >workspacename, 1, 0))
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --
> --		=C2=A0=C2=A0rc =3D validate_rrset(now, header, plen, class,
> nsec_type, daemon->workspacename, keyname, NULL, NULL, 0, 0, 0);
> -+=C2=A0=C2=A0/* OK, all the RRsets validate, now see if we have a missing
> answer or CNAME target. */
> -+=C2=A0=C2=A0for (j =3D 0; j <targetidx; j++)
> -+=C2=A0=C2=A0=C2=A0=C2=A0if ((p2 =3D targets[j]))
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	if (neganswer)
> -+	=C2=A0=C2=A0*neganswer =3D 1;
> -=C2=A0
> --		=C2=A0=C2=A0/* NSECs can't be wildcards. */
> --		=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD)
> --		=C2=A0=C2=A0=C2=A0=C2=A0rc =3D STAT_BOGUS;
> -+	if (!extract_name(header, plen, &p2, name, 1, 10))
> -+	=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0
> -+	/* NXDOMAIN or NODATA reply, unanswered question is (name,
> qclass, qtype) */
> -=C2=A0
> --		=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> -+	/* For anything other than a DS record, this situation is
> OK if either
> -+	=C2=A0=C2=A0=C2=A0the answer is in an unsigned zone, or there's a NSEC
> records. */
> -+	if (!(nsec_type =3D find_nsec_records(header, plen, &nsecs,
> &nsec_count, qclass)))
> -+	=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0/* Empty DS without NSECS */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_DS)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+		rc =3D zone_status(name, qclass, keyname, now);
> -+		if (rc !=3D STAT_SECURE)
> -+		=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0if (class)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*class =3D qclass; /* Class for NEE=
D_DS or
> NEED_DNSKEY */
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0return rc;
> --		}
> --
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> --		rc =3D prove_non_existence_nsec(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, type, NULL);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --		rc =3D prove_non_existence_nsec3(header, plen, nsecs,
> nsec_count, daemon->workspacename,=C2=A0
> --					=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0keyname, name, type,
> wildname, NULL);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> --		return rc;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_NO_SIG)
> --		rc =3D STAT_INSECURE;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return rc;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> -+		=C2=A0=C2=A0}=C2=A0
> -+	=09
> -+		return STAT_BOGUS; /* signed zone, no NSECs */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0}
> -=C2=A0
> --	=C2=A0=C2=A0/* Loop down CNAME chain/ */
> --	=C2=A0=C2=A0if (!cname_count-- ||=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!extract_name(header, plen, &p, name=
, 1, 0) ||
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!(p =3D skip_questions(header, plen)=
))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0break;
> --	}
> -+	=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> -+	=C2=A0=C2=A0rc =3D prove_non_existence_nsec(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, nons);
> -+	else
> -+	=C2=A0=C2=A0rc =3D prove_non_existence_nsec3(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
> -=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* End of CNAME chain */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE;=09
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	if (rc !=3D STAT_SECURE)
> -+	=C2=A0=C2=A0return rc;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0return STAT_SECURE;
> - }
> -=C2=A0
> -=C2=A0
> -diff --git a/src/forward.c b/src/forward.c
> -index b76a974..dd22a62 100644
> ---- a/src/forward.c
> -+++ b/src/forward.c
> -@@ -23,15 +23,6 @@ static struct frec
> *lookup_frec_by_sender(unsigned short id,
> - static unsigned short get_id(void);
> - static void free_frec(struct frec *f);
> -=C2=A0
> --#ifdef HAVE_DNSSEC
> --static int tcp_key_recurse(time_t now, int status, struct
> dns_header *header, size_t n,=C2=A0
> --			=C2=A0=C2=A0=C2=A0int class, char *name, char *keyname,
> struct server *server, int *keycount);
> --static int do_check_sign(struct frec *forward, int status, time_t
> now, char *name, char *keyname);
> --static int send_check_sign(struct frec *forward, time_t now, struct
> dns_header *header, size_t plen,=C2=A0
> --			=C2=A0=C2=A0=C2=A0char *name, char *keyname);
> --#endif
> --
> --
> - /* Send a UDP packet with its source address set as "source"=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0unless nowild is true, when we just send it with t=
he kernel
> default */
> - int send_from(int fd, int nowild, char *packet, size_t len,=C2=A0
> -@@ -825,236 +816,142 @@ void reply_query(int fd, int family, time_t
> now)
> - #ifdef HAVE_DNSSEC
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (server && option_bool(OPT_DN=
SSEC_VALID) && !(forward-
> >flags & FREC_CHECKING_DISABLED))
> -=C2=A0	{
> --	=C2=A0=C2=A0int status;
> -+	=C2=A0=C2=A0int status =3D 0;
> -=C2=A0
> -=C2=A0	=C2=A0=C2=A0/* We've had a reply already, which we're validating.
> Ignore this duplicate */
> -=C2=A0	=C2=A0=C2=A0if (forward->blocking_query)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0return;
> --
> --	=C2=A0=C2=A0if (header->hb3 & HB3_TC)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Truncated answer can't be validat=
ed.
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0/* Truncated answer can't be validated.
> -=C2=A0		=C2=A0If this is an answer to a DNSSEC-generated query,
> we still
> -=C2=A0		=C2=A0need to get the client to retry over TCP, so
> return
> -=C2=A0		=C2=A0an answer with the TC bit set, even if the actual
> answer fits.
> -=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=A0status =3D STAT_TRUNCATED;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0else if (forward->flags & FREC_DNSKEY_QUERY)
> --	=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_by_ds(now, header, n,=
 daemon-
> >namebuff, daemon->keyname, forward->class);
> --	=C2=A0=C2=A0else if (forward->flags & FREC_DS_QUERY)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_ds(now, h=
eader, n, daemon-
> >namebuff, daemon->keyname, forward->class);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Provably no DS, everything below =
is insecure, even
> if signatures are offered */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NO_DS)
> --		/* We only cache sigs when we've validated a reply.
> --		=C2=A0=C2=A0=C2=A0Avoid caching a reply with sigs if there's a
> vaildated break in the=C2=A0
> --		=C2=A0=C2=A0=C2=A0DS chain, so we don't return replies from cache
> missing sigs. */
> --=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	status =3D STAT_INSECURE_DS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_NO_SIG)
> --=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=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --=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=A0status =3D send_check_sign(forward,=
 now,
> header, n, daemon->namebuff, daemon->keyname);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_INSECURE)
> --			status =3D STAT_INSECURE_DS;
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		=C2=A0=C2=A0else
> --		=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_INSECURE_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=C2=A0else if (status =3D=3D STAT_NO_NS)
> --		status =3D STAT_BOGUS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0else if (forward->flags & FREC_CHECK_NOSIGN)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_ds(now, h=
eader, n, daemon-
> >namebuff, daemon->keyname, forward->class);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status !=3D STAT_NEED_KEY)
> --		status =3D do_check_sign(forward, status, now,
> daemon->namebuff, daemon->keyname);
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0else
> -+	=C2=A0=C2=A0if (header->hb3 & HB3_TC)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_TRUNCATED;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0while (1)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_reply(now=
, header, n,
> daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NO_SIG)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* As soon as anything returns BOGUS=
, we stop and
> unwind, to do otherwise
> -+		=C2=A0would invite infinite loops, since the answers to
> DNSKEY and DS queries
> -+		=C2=A0will not be cached, so they'll be repeated. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status !=3D STAT_BOGUS && status=
 !=3D STAT_TRUNCATED
> && status !=3D STAT_ABANDONED)
> -=C2=A0		{
> --		=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --		=C2=A0=C2=A0=C2=A0=C2=A0status =3D send_check_sign(forward, now, header,
> n, daemon->namebuff, daemon->keyname);
> -+		=C2=A0=C2=A0if (forward->flags & FREC_DNSKEY_QUERY)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_by_ds(now, header, n,
> daemon->namebuff, daemon->keyname, forward->class);
> -+		=C2=A0=C2=A0else if (forward->flags & FREC_DS_QUERY)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_ds(now, header, n,
> daemon->namebuff, daemon->keyname, forward->class);
> -=C2=A0		=C2=A0=C2=A0else
> --		=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_INSECURE;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_reply(now, header, n,
> daemon->namebuff, daemon->keyname, &forward->class,=C2=A0
> -+						=C2=A0=C2=A0=C2=A0option_bool(OPT_
> DNSSEC_NO_SIGN), NULL, NULL);
> -=C2=A0		}
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0/* Can't validate, as we're missing key data. Put this
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0answer aside, whilst we get that. */=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEED_DS=
_NEG
> || status =3D=3D STAT_NEED_KEY)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct frec *new, *orig;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Free any saved query */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (forward->stash)
> --		blockdata_free(forward->stash);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Now save reply pending receipt of=
 key data */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(forward->stash =3D blockdata_a=
lloc((char
> *)header, n)))
> --		return;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->stash_len =3D n;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0anotherkey:	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Find the original query that star=
ted it all.... */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (orig =3D forward; orig->depende=
nt; orig =3D orig-
> >dependent);
> --
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (--orig->work_counter =3D=3D 0 ||=
 !(new =3D
> get_new_frec(now, NULL, 1)))
> --		status =3D STAT_INSECURE;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Can't validate, as we're missing =
key data. Put
> this
> -+		=C2=A0answer aside, whilst we get that. */=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NEED_DS || st=
atus =3D=3D
> STAT_NEED_KEY)
> -=C2=A0		{
> --		=C2=A0=C2=A0int fd;
> --		=C2=A0=C2=A0struct frec *next =3D new->next;
> --		=C2=A0=C2=A0*new =3D *forward; /* copy everything, then
> overwrite */
> --		=C2=A0=C2=A0new->next =3D next;
> --		=C2=A0=C2=A0new->blocking_query =3D NULL;
> --		=C2=A0=C2=A0new->sentto =3D server;
> --		=C2=A0=C2=A0new->rfd4 =3D NULL;
> --		=C2=A0=C2=A0new->orig_domain =3D NULL;
> --#ifdef HAVE_IPV6
> --		=C2=A0=C2=A0new->rfd6 =3D NULL;
> --#endif
> --		=C2=A0=C2=A0new->flags &=3D ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY
> | FREC_CHECK_NOSIGN);
> -+		=C2=A0=C2=A0struct frec *new, *orig;
> -=C2=A0		=C2=A0=C2=A0
> --		=C2=A0=C2=A0new->dependent =3D forward; /* to find query
> awaiting new one. */
> --		=C2=A0=C2=A0forward->blocking_query =3D new; /* for garbage
> cleaning */
> --		=C2=A0=C2=A0/* validate routines leave name of required
> record in daemon->keyname */
> --		=C2=A0=C2=A0if (status =3D=3D STAT_NEED_KEY)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->flags |=3D FREC_DNSKEY_QUERY;=
=C2=A0
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0nn =3D dnssec_generate_query(header=
, ((char *)
> header) + daemon->packet_buff_sz,
> --						=C2=A0daemon->keyname,
> forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
> --		=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=C2=A0if (status =3D=3D STAT_NEED_DS_NEG)
> --			new->flags |=3D FREC_CHECK_NOSIGN;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --			new->flags |=3D FREC_DS_QUERY;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0nn =3D dnssec_generate_query(header=
,((char *)
> header) + daemon->packet_buff_sz,
> --						=C2=A0daemon->keyname,
> forward->class, T_DS, &server->addr, server->edns_pktsz);
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		=C2=A0=C2=A0if ((hash =3D hash_questions(header, nn, daemon-
> >namebuff)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0memcpy(new->hash, hash, HASH_SIZE);
> --		=C2=A0=C2=A0new->new_id =3D get_id();
> --		=C2=A0=C2=A0header->id =3D htons(new->new_id);
> --		=C2=A0=C2=A0/* Save query for retransmission */
> --		=C2=A0=C2=A0if (!(new->stash =3D blockdata_alloc((char
> *)header, nn)))
> -+		=C2=A0=C2=A0/* Free any saved query */
> -+		=C2=A0=C2=A0if (forward->stash)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(forward->stash);
> -+		=C2=A0=C2=A0
> -+		=C2=A0=C2=A0/* Now save reply pending receipt of key data */
> -+		=C2=A0=C2=A0if (!(forward->stash =3D blockdata_alloc((char
> *)header, n)))
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0return;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --		=C2=A0=C2=A0new->stash_len =3D nn;
> -+		=C2=A0=C2=A0forward->stash_len =3D n;
> -=C2=A0		=C2=A0=C2=A0
> --		=C2=A0=C2=A0/* Don't resend this. */
> --		=C2=A0=C2=A0daemon->srv_save =3D NULL;
> -+		=C2=A0=C2=A0/* Find the original query that started it
> all.... */
> -+		=C2=A0=C2=A0for (orig =3D forward; orig->dependent; orig =3D
> orig->dependent);
> -=C2=A0		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (server->sfd)
> --		=C2=A0=C2=A0=C2=A0=C2=A0fd =3D server->sfd->fd;
> -+		=C2=A0=C2=A0if (--orig->work_counter =3D=3D 0 || !(new =3D
> get_new_frec(now, NULL, 1)))
> -+		=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_ABANDONED;
> -=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=A0fd =3D -1;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int fd;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct frec *next =3D new->next;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*new =3D *forward; /* copy everythi=
ng, then
> overwrite */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->next =3D next;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->blocking_query =3D NULL;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->sentto =3D server;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->rfd4 =3D NULL;
> - #ifdef HAVE_IPV6
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (server->addr.sa.sa_family =3D=
=3D AF_INET6)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->rfd6 =3D NULL;
> -+#endif
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->flags &=3D ~(FREC_DNSKEY_QUERY=
 |
> FREC_DS_QUERY);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->dependent =3D forward; /* to f=
ind query
> awaiting new one. */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->blocking_query =3D new; /*=
 for garbage
> cleaning */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* validate routines leave name of =
required
> record in daemon->keyname */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NEED_KEY)
> -+			{
> -+			=C2=A0=C2=A0new->flags |=3D FREC_DNSKEY_QUERY;=C2=A0
> -+			=C2=A0=C2=A0nn =3D dnssec_generate_query(header, ((char
> *) header) + daemon->packet_buff_sz,
> -+						=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0daemon-
> >keyname, forward->class, T_DNSKEY, &server->addr, server-
> >edns_pktsz);
> -+			}
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> -=C2=A0			{
> --			=C2=A0=C2=A0if (new->rfd6 || (new->rfd6 =3D
> allocate_rfd(AF_INET6)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0fd =3D new->rfd6->fd;
> -+			=C2=A0=C2=A0new->flags |=3D FREC_DS_QUERY;
> -+			=C2=A0=C2=A0nn =3D dnssec_generate_query(header,((char
> *) header) + daemon->packet_buff_sz,
> -+						=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0daemon-
> >keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
> -=C2=A0			}
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((hash =3D hash_questions(header=
, nn,
> daemon->namebuff)))
> -+			memcpy(new->hash, hash, HASH_SIZE);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->new_id =3D get_id();
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0header->id =3D htons(new->new_id);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Save query for retransmission */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->stash =3D blockdata_alloc((cha=
r *)header,
> nn);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new->stash_len =3D nn;
> -+		=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 resend this. */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0daemon->srv_save =3D NULL;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (server->sfd)
> -+			fd =3D server->sfd->fd;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+			{
> -+			=C2=A0=C2=A0fd =3D -1;
> -+#ifdef HAVE_IPV6
> -+			=C2=A0=C2=A0if (server->addr.sa.sa_family =3D=3D
> AF_INET6)
> -+			=C2=A0=C2=A0=C2=A0=C2=A0{
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (new->rfd6 || (new->rfd6 =3D
> allocate_rfd(AF_INET6)))
> -+				fd =3D new->rfd6->fd;
> -+			=C2=A0=C2=A0=C2=A0=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=A0if (new->rfd4 || (new->rfd4 =3D
> allocate_rfd(AF_INET)))
> -+				fd =3D new->rfd4->fd;
> -+			=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=A0if (fd !=3D -1)
> -=C2=A0			{
> --			=C2=A0=C2=A0if (new->rfd4 || (new->rfd4 =3D
> allocate_rfd(AF_INET)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0fd =3D new->rfd4->fd;
> -+			=C2=A0=C2=A0while (retry_send(sendto(fd, (char
> *)header, nn, 0,=C2=A0
> -+						=C2=A0=C2=A0=C2=A0&server-
> >addr.sa,=C2=A0
> -+						=C2=A0=C2=A0=C2=A0sa_len(&server-
> >addr))));=C2=A0
> -+			=C2=A0=C2=A0server->queries++;
> -=C2=A0			}
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (fd !=3D -1)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0while (retry_send(sendto(fd, (char =
*)header,
> nn, 0,=C2=A0
> --					=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0&server->addr.sa,=C2=A0
> --					=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0sa_len(&server-
> >addr))));=C2=A0
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0server->queries++;
> --		=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=A0return;
> -=C2=A0		}
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	=C2=A0=C2=A0
> --	=C2=A0=C2=A0/* Ok, we reached far enough up the chain-of-trust that
> we can validate something.
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Now wind back down, pulling back answers w=
hich
> wouldn't previously validate
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0and validate them with the new data. Note =
that if an
> answer needs multiple
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0keys to validate, we may find another key =
is needed,
> in which case we set off
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0down another branch of the tree. Once we g=
et to the
> original answer=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(FREC_DNSSEC_QUERY not set) and it validat=
es, return
> it to the original requestor. */
> --	=C2=A0=C2=A0while (forward->dependent)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Validated original answer, all do=
ne. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!forward->dependent)
> -+		break;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* validated subsdiary query, (and c=
ached result)
> -+		=C2=A0pop that and return to the previous query we were
> working on. */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct frec *prev =3D forward->=
dependent;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free_frec(forward);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward =3D prev;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->blocking_query =3D NUL=
L; /* already gone */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_retrieve(forward->sta=
sh, forward-
> >stash_len, (void *)header);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0n =3D forward->stash_len;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_SECURE)
> --		{
> --		=C2=A0=C2=A0if (forward->flags & FREC_DNSKEY_QUERY)
> --		=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_by_ds(now, header, n,
> daemon->namebuff, daemon->keyname, forward->class);
> --		=C2=A0=C2=A0else if (forward->flags & FREC_DS_QUERY)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_ds(now, =
header, n,
> daemon->namebuff, daemon->keyname, forward->class);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Provably no DS, everything=
 below is
> insecure, even if signatures are offered */
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NO_DS)
> --			/* We only cache sigs when we've validated
> a reply.
> --			=C2=A0=C2=A0=C2=A0Avoid caching a reply with sigs if
> there's a vaildated break in the=C2=A0
> --			=C2=A0=C2=A0=C2=A0DS chain, so we don't return replies
> from cache missing sigs. */
> --			status =3D STAT_INSECURE_DS;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_N=
O_SIG)
> --			=C2=A0{
> --			=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D send_check_sign(f=
orward,
> now, header, n, daemon->namebuff, daemon->keyname);=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_INSEC=
URE)
> --				=C2=A0status =3D STAT_INSECURE_DS;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> --			=C2=A0=C2=A0=C2=A0else
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_INSECURE_DS;
> --			=C2=A0}
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_N=
O_NS)
> --			=C2=A0status =3D STAT_BOGUS;
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		=C2=A0=C2=A0else if (forward->flags & FREC_CHECK_NOSIGN)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D dnssec_validate_ds(now, =
header, n,
> daemon->namebuff, daemon->keyname, forward->class);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status !=3D STAT_NEED_KEY)
> --			status =3D do_check_sign(forward, status,
> now, daemon->namebuff, daemon->keyname);
> --		=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=A0status =3D dnssec_validate_reply(no=
w, header,
> n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);=09
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NO_SIG)
> --			{
> --			=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --			=C2=A0=C2=A0=C2=A0=C2=A0status =3D send_check_sign(forward, now,
> header, n, daemon->namebuff, daemon->keyname);
> --			=C2=A0=C2=A0else
> --			=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_INSECURE;
> --			}
> --		=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 (status =3D=3D STAT_NEED_DS || status =3D=3D
> STAT_NEED_DS_NEG || status =3D=3D STAT_NEED_KEY)
> --		=C2=A0=C2=A0=C2=A0=C2=A0goto anotherkey;
> --		}
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=09
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0no_cache_dnssec =3D 0;
> --
> --	=C2=A0=C2=A0if (status =3D=3D STAT_INSECURE_DS)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* We only cache sigs when we've val=
idated a reply.
> --		=C2=A0Avoid caching a reply with sigs if there's a
> vaildated break in the=C2=A0
> --		=C2=A0DS chain, so we don't return replies from cache
> missing sigs. */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_INSECURE;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0no_cache_dnssec =3D 1;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0if (status =3D=3D STAT_TRUNCATED)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0header->hb3 |=3D HB3_TC;
> -@@ -1062,7 +959,7 @@ void reply_query(int fd, int family, 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=A0char *result, *domain =3D "resu=
lt";
> -=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 (forward->work_counter =3D=3D 0)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_ABANDONED)
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0result =3D "ABANDONED";
> -=C2=A0		=C2=A0=C2=A0status =3D STAT_BOGUS;
> -@@ -1072,7 +969,7 @@ void reply_query(int fd, int family, 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 (status =3D=3D STAT_BOGUS &&=
 extract_request(header,
> n, daemon->namebuff, NULL))
> -=C2=A0		domain =3D daemon->namebuff;
> --
> -+	=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=A0log_query(F_KEYTAG | F_SECSTAT,=
 domain, NULL,
> result);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	=C2=A0=C2=A0
> -@@ -1415,315 +1312,49 @@ void receive_query(struct listener *listen,
> time_t now)
> - }
> -=C2=A0
> - #ifdef HAVE_DNSSEC
> --
> --/* UDP: we've got an unsigned answer, return STAT_INSECURE if we
> can prove there's no DS
> --=C2=A0=C2=A0=C2=A0and therefore the answer shouldn't be signed, or STAT_B=
OGUS if
> it should be, or=C2=A0
> --=C2=A0=C2=A0=C2=A0STAT_NEED_DS_NEG and keyname if we need to do the query=
. */
> --static int send_check_sign(struct frec *forward, time_t now, struct
> dns_header *header, size_t plen,=C2=A0
> --			=C2=A0=C2=A0=C2=A0char *name, char *keyname)
> --{
> --=C2=A0=C2=A0int status =3D dnssec_chase_cname(now, header, plen, name,
> keyname);
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (status !=3D STAT_INSECURE)
> --=C2=A0=C2=A0=C2=A0=C2=A0return status;
> --
> --=C2=A0=C2=A0/* Store the domain we're trying to check. */
> --=C2=A0=C2=A0forward->name_start =3D strlen(name);
> --=C2=A0=C2=A0forward->name_len =3D forward->name_start + 1;
> --=C2=A0=C2=A0if (!(forward->orig_domain =3D blockdata_alloc(name, forward-
> >name_len)))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0return do_check_sign(forward, 0, now, name, keyname);
> --}
> --=C2=A0
> --/* We either have a a reply (header non-NULL, or we need to start
> by looking in the cache */=C2=A0
> --static int do_check_sign(struct frec *forward, int status, time_t
> now, char *name, char *keyname)
> --{
> --=C2=A0=C2=A0/* get domain we're checking back from blockdata store, it's
> stored on the original query. */
> --=C2=A0=C2=A0while (forward->dependent && !forward->orig_domain)
> --=C2=A0=C2=A0=C2=A0=C2=A0forward =3D forward->dependent;
> --
> --=C2=A0=C2=A0blockdata_retrieve(forward->orig_domain, forward->name_len,
> name);
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0while (1)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *p;=C2=A0
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D 0)
> --	{
> --	=C2=A0=C2=A0struct crec *crecp;
> --
> --	=C2=A0=C2=A0/* Haven't received answer, see if in cache */
> --	=C2=A0=C2=A0if (!(crecp =3D cache_find_by_name(NULL, &name[forward-
> >name_start], now, F_DS)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* put name of DS record we're missi=
ng into keyname
> */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0strcpy(keyname, &name[forward->name_=
start]);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* and wait for reply to arrive */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_NEED_DS_NEG;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --	=C2=A0=C2=A0/* F_DNSSECOK misused in DS cache records to non-
> existance of NS record */=C2=A0
> --	=C2=A0=C2=A0if (!(crecp->flags & F_NEG))
> --	=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_SECURE;
> --	=C2=A0=C2=A0else if (crecp->flags & F_DNSSECOK)
> --	=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_NO_DS;
> --	=C2=A0=C2=A0else
> --	=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_NO_NS;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Have entered non-signed part of DN=
S tree. */=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NO_DS)
> --	return forward->dependent ? STAT_INSECURE_DS :
> STAT_INSECURE;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_BOGUS)
> --	return STAT_BOGUS;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NO_SIG && *key=
name !=3D 0)
> --	{
> --	=C2=A0=C2=A0/* There is a validated CNAME chain that doesn't end in a
> DS record. Start=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the search again in that domain. */
> --	=C2=A0=C2=A0blockdata_free(forward->orig_domain);
> --	=C2=A0=C2=A0forward->name_start =3D strlen(keyname);
> --	=C2=A0=C2=A0forward->name_len =3D forward->name_start + 1;
> --	=C2=A0=C2=A0if (!(forward->orig_domain =3D blockdata_alloc(keyname,
> forward->name_len)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0strcpy(name, keyname);
> --	=C2=A0=C2=A0status =3D 0; /* force to cache when we iterate. */
> --	=C2=A0=C2=A0continue;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* There's a proven DS record, or we'=
re within a zone, where
> there doesn't need
> --	=C2=A0to be a DS record. Add a name and try again.=C2=A0
> --	=C2=A0If we've already tried the whole name, then fail */
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (forward->name_start =3D=3D 0)
> --	return STAT_BOGUS;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (p =3D &name[forward->name_start-=
2]; (*p !=3D '.') && (p !=3D
> name); p--);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (p !=3D name)
> --	p++;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward->name_start =3D p - name;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D 0; /* force to cache when =
we iterate. */
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --}
> --
> --/* Move down from the root, until we find a signed non-existance of
> a DS, in which case
> --=C2=A0=C2=A0=C2=A0an unsigned answer is OK, or we find a signed DS, in wh=
ich case
> there should be=C2=A0
> --=C2=A0=C2=A0=C2=A0a signature, and the answer is BOGUS */
> --static int=C2=A0=C2=A0tcp_check_for_unsigned_zone(time_t now, struct
> dns_header *header, size_t plen, int class, char *name,=C2=A0
> --					char *keyname, struct
> server *server, int *keycount)
> --{
> --=C2=A0=C2=A0size_t m;
> --=C2=A0=C2=A0unsigned char *packet, *payload;
> --=C2=A0=C2=A0u16 *length;
> --=C2=A0=C2=A0int status, name_len;
> --=C2=A0=C2=A0struct blockdata *block;
> --
> --=C2=A0=C2=A0char *name_start;
> --
> --=C2=A0=C2=A0/* Get first insecure entry in CNAME chain */
> --=C2=A0=C2=A0status =3D tcp_key_recurse(now, STAT_CHASE_CNAME, header, ple=
n,
> class, name, keyname, server, keycount);
> --=C2=A0=C2=A0if (status =3D=3D STAT_BOGUS)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (!(packet =3D whine_malloc(65536 + MAXDNAME + RRFIXEDSZ +
> sizeof(u16))))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0payload =3D &packet[2];
> --=C2=A0=C2=A0header =3D (struct dns_header *)payload;
> --=C2=A0=C2=A0length =3D (u16 *)packet;
> --
> --=C2=A0=C2=A0/* Stash the name away, since the buffer will be trashed when=
 we
> recurse */
> --=C2=A0=C2=A0name_len =3D strlen(name) + 1;
> --=C2=A0=C2=A0name_start =3D name + name_len - 1;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (!(block =3D blockdata_alloc(name, name_len)))
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --=C2=A0=C2=A0while (1)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char c1, c2;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct crec *crecp;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (--(*keycount) =3D=3D 0)
> --	{
> --	=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0return STAT_BOGUS;=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=A0while ((crecp =3D cache_find_by_name(=
NULL, name_start, now,
> F_DS)))
> --	{=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0if ((crecp->flags & F_NEG) && (crecp->flags &
> F_DNSSECOK))
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Found a secure denial of DS - del=
egation is indeed
> insecure */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0=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=A0=C2=A0
> --	=C2=A0=C2=A0/* Here, either there's a secure DS, or no NS and no DS,
> and therefore no delegation.
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Add another label and continue. */
> --=C2=A0
> --	=C2=A0=C2=A0if (name_start =3D=3D name)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* run out of lab=
els */
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0name_start -=3D 2;
> --	=C2=A0=C2=A0while (*name_start !=3D '.' && name_start !=3D name)=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0name_start--;
> --	=C2=A0=C2=A0if (name_start !=3D name)
> --	=C2=A0=C2=A0=C2=A0=C2=A0name_start++;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Can't find it in the cache, have t=
o send a query */
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D dnssec_generate_query(header, (=
(char *) header) + 65536,
> name_start, class, T_DS, &server->addr, server->edns_pktsz);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*length =3D htons(m);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (read_write(server->tcpfd, packet,=
 m + sizeof(u16), 0) &&
> --	=C2=A0=C2=A0read_write(server->tcpfd, &c1, 1, 1) &&
> --	=C2=A0=C2=A0read_write(server->tcpfd, &c2, 1, 1) &&
> --	=C2=A0=C2=A0read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
> --	{
> --	=C2=A0=C2=A0m =3D (c1 << 8) | c2;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0/* Note this trashes all three name workspaces */
> --	=C2=A0=C2=A0status =3D tcp_key_recurse(now, STAT_NEED_DS_NEG, header,
> m, class, name, keyname, server, keycount);
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (status =3D=3D STAT_NO_DS)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Found a secure denial of DS - del=
egation is indeed
> insecure */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0=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=A0if (status =3D=3D STAT_NO_SIG && *keyname !=3D 0)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* There is a validated CNAME chain =
that doesn't end
> in a DS record. Start=C2=A0
> --		=C2=A0the search again in that domain. */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0name_len =3D strlen(keyname) + 1;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0name_start =3D name + name_len - 1;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(block =3D blockdata_alloc(keyn=
ame, name_len)))
> --		return STAT_BOGUS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0strcpy(name, keyname);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0continue;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (status =3D=3D STAT_BOGUS)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0/* Here, either there's a secure DS, or no NS and no DS,
> and therefore no delegation.
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Add another label and continue. */
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0/* Get name we're checking back. */
> --	=C2=A0=C2=A0blockdata_retrieve(block, name_len, name);
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (name_start =3D=3D name)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* run out of lab=
els */
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0name_start -=3D 2;
> --	=C2=A0=C2=A0while (*name_start !=3D '.' && name_start !=3D name)=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0name_start--;
> --	=C2=A0=C2=A0if (name_start !=3D name)
> --	=C2=A0=C2=A0=C2=A0=C2=A0name_start++;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --	{
> --	=C2=A0=C2=A0/* IO failure */
> --	=C2=A0=C2=A0free(packet);
> --	=C2=A0=C2=A0blockdata_free(block);
> --	=C2=A0=C2=A0return STAT_BOGUS; /* run out of labels */
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --}
> --
> - static int tcp_key_recurse(time_t now, int status, struct
> dns_header *header, size_t n,=C2=A0
> -=C2=A0			=C2=A0=C2=A0=C2=A0int class, char *name, char *keyname,
> struct server *server, int *keycount)
> - {
> -=C2=A0=C2=A0=C2=A0/* Recurse up the key heirarchy */
> -=C2=A0=C2=A0=C2=A0int new_status;
> -+=C2=A0=C2=A0unsigned char *packet =3D NULL;
> -+=C2=A0=C2=A0size_t m;=C2=A0
> -+=C2=A0=C2=A0unsigned char *payload =3D NULL;
> -+=C2=A0=C2=A0struct dns_header *new_header =3D NULL;
> -+=C2=A0=C2=A0u16 *length =3D NULL;
> -+=C2=A0=C2=A0unsigned char c1, c2;
> -=C2=A0
> --=C2=A0=C2=A0/* limit the amount of work we do, to avoid cycling forever on
> loops in the DNS */
> --=C2=A0=C2=A0if (--(*keycount) =3D=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (status =3D=3D STAT_NEED_KEY)
> --=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D dnssec_validate_by_ds(now, header,=
 n, name,
> keyname, class);
> --=C2=A0=C2=A0else if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEE=
D_DS_NEG)
> -+=C2=A0=C2=A0while (1)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D dnssec_validate_ds(now=
, header, n, name,
> keyname, class);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NEED_DS)
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* limit the amount of work we do, to=
 avoid cycling forever
> on loops in the DNS */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (--(*keycount) =3D=3D 0)
> -+	new_status =3D STAT_ABANDONED;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_NEED_KEY)
> -+	new_status =3D dnssec_validate_by_ds(now, header, n, name,
> keyname, class);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_NEED_DS)
> -+	new_status =3D dnssec_validate_ds(now, header, n, name,
> keyname, class);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> -+	new_status =3D dnssec_validate_reply(now, header, n, name,
> keyname, &class, option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (new_status !=3D STAT_NEED_DS && n=
ew_status !=3D
> STAT_NEED_KEY)
> -+	break;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Can't validate because we need a k=
ey/DS whose name now in
> keyname.
> -+	=C2=A0Make query for same, and recurse to validate */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!packet)
> -=C2=A0	{
> --	=C2=A0=C2=A0if (new_status =3D=3D STAT_NO_DS)
> --	=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D STAT_INSECURE_DS;
> --	=C2=A0=C2=A0if (new_status =3D=3D STAT_NO_SIG)
> --	=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0new_status =3D tcp_check_for_unsigned_zone(now,
> header, n, class, name, keyname, server, keycount);
> --		=C2=A0if (new_status =3D=3D STAT_INSECURE)
> --		=C2=A0=C2=A0=C2=A0new_status =3D STAT_INSECURE_DS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=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=A0new_status =3D STAT_INSECURE_D=
S;
> --	=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0else if (new_status =3D=3D STAT_NO_NS)
> --	=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D STAT_BOGUS;
> -+	=C2=A0=C2=A0packet =3D whine_malloc(65536 + MAXDNAME + RRFIXEDSZ +
> sizeof(u16));
> -+	=C2=A0=C2=A0payload =3D &packet[2];
> -+	=C2=A0=C2=A0new_header =3D (struct dns_header *)payload;
> -+	=C2=A0=C2=A0length =3D (u16 *)packet;
> -=C2=A0	}
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0else if (status =3D=3D STAT_CHASE_CNAME)
> --=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D dnssec_chase_cname(now, header, n,=
 name, keyname);
> --=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=A0new_status =3D dnssec_validate_reply(=
now, header, n, name,
> keyname, &class, NULL, 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=A0if (new_status =3D=3D STAT_NO_SIG)
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!packet)
> -=C2=A0	{
> --	=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --	=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D tcp_check_for_unsigned_zone(now, =
header,
> n, class, name, keyname, server, keycount);
> --	=C2=A0=C2=A0else
> --	=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D STAT_INSECURE;
> -+	=C2=A0=C2=A0new_status =3D STAT_ABANDONED;
> -+	=C2=A0=C2=A0break;
> -=C2=A0	}
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --=C2=A0=C2=A0/* Can't validate because we need a key/DS whose name now in
> keyname.
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Make query for same, and recurse to validat=
e */
> --=C2=A0=C2=A0if (new_status =3D=3D STAT_NEED_DS || new_status =3D=3D STAT_=
NEED_KEY)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0size_t m;=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *packet =3D whine_mallo=
c(65536 + MAXDNAME +
> RRFIXEDSZ + sizeof(u16));
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *payload =3D &packet[2];
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct dns_header *new_header =3D (st=
ruct dns_header *)payload;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0u16 *length =3D (u16 *)packet;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char c1, c2;
> --=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 (!packet)
> --	return STAT_INSECURE;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0another_tcp_key:
> -+	=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D dnssec_generate_query(new_=
header, ((char *) new_header) +
> 65536, keyname, class,=C2=A0
> -=C2=A0				new_status =3D=3D STAT_NEED_KEY ?
> T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -@@ -1733,65 +1364,22 @@ static int tcp_key_recurse(time_t now, int
> status, struct dns_header *header, si
> -=C2=A0	=C2=A0=C2=A0!read_write(server->tcpfd, &c1, 1, 1) ||
> -=C2=A0	=C2=A0=C2=A0!read_write(server->tcpfd, &c2, 1, 1) ||
> -=C2=A0	=C2=A0=C2=A0!read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
> --	new_status =3D STAT_INSECURE;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -=C2=A0	{
> --	=C2=A0=C2=A0m =3D (c1 << 8) | c2;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0new_status =3D tcp_key_recurse(now, new_status, new_header,
> m, class, name, keyname, server, keycount);
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (new_status =3D=3D STAT_SECURE)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Reached a validated record, now t=
ry again at this
> level.
> --		=C2=A0Note that we may get ANOTHER NEED_* if an answer
> needs more than one key.
> --		=C2=A0If so, go round again. */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (status =3D=3D STAT_NEED_KEY)
> --		new_status =3D dnssec_validate_by_ds(now, header, n,
> name, keyname, class);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_NEED_DS =
|| status =3D=3D
> STAT_NEED_DS_NEG)
> --		{
> --		=C2=A0=C2=A0new_status =3D dnssec_validate_ds(now, header, n,
> name, keyname, class);
> --		=C2=A0=C2=A0if (status =3D=3D STAT_NEED_DS)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (new_status =3D=3D STAT_NO_DS)
> --			new_status =3D STAT_INSECURE_DS;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (new_status =3D=3D STAT_NO_=
SIG)
> --			{
> --			=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D
> tcp_check_for_unsigned_zone(now, header, n, class, name, keyname,
> server, keycount);=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (new_status =3D=3D STAT_INSECUR=
E)
> --				new_status =3D STAT_INSECURE_DS;
> --			=C2=A0=C2=A0=C2=A0=C2=A0}
> --			=C2=A0=C2=A0else
> --			=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D STAT_INSECURE_DS;
> --			}
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (new_status =3D=3D STAT_NO_=
NS)
> --			new_status =3D STAT_BOGUS;
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		}
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (status =3D=3D STAT_CHASE_CN=
AME)
> --		new_status =3D dnssec_chase_cname(now, header, n,
> name, keyname);
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> --		{
> --		=C2=A0=C2=A0new_status =3D dnssec_validate_reply(now, header,
> n, name, keyname, &class, NULL, NULL);
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (new_status =3D=3D STAT_NO_SIG)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_NO_SIGN))
> --			new_status =3D
> tcp_check_for_unsigned_zone(now, header, n, class, name, keyname,
> server, keycount);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --			new_status =3D STAT_INSECURE;
> --		=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=A0if (new_status =3D=3D STAT_NEED_DS |=
| new_status =3D=3D
> STAT_NEED_KEY)
> --		goto another_tcp_key;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0new_status =3D STAT_ABANDONED;
> -+	=C2=A0=C2=A0break;
> -=C2=A0	}
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0m =3D (c1 << 8) | c2;
> -=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=A0free(packet);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0new_status =3D tcp_key_recurse(now, n=
ew_status, new_header, m,
> class, name, keyname, server, keycount);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (new_status !=3D STAT_OK)
> -+	break;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+
> -+=C2=A0=C2=A0if (packet)
> -+=C2=A0=C2=A0=C2=A0=C2=A0free(packet);
> -+=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0return new_status;
> - }
> - #endif
> -@@ -2075,19 +1663,10 @@ unsigned char *tcp_request(int confd, time_t
> now,
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_VAL=
ID) &&
> !checking_disabled)
> -=C2=A0			{
> -=C2=A0			=C2=A0=C2=A0int keycount =3D DNSSEC_WORK; /* Limit to
> number of DNSSEC questions, to catch loops and avoid filling cache.
> */
> --			=C2=A0=C2=A0int status =3D tcp_key_recurse(now,
> STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname,
> last_server, &keycount);
> -+			=C2=A0=C2=A0int status =3D tcp_key_recurse(now,
> STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
> last_server, &keycount);
> -=C2=A0			=C2=A0=C2=A0char *result, *domain =3D "result";
> --
> --			=C2=A0=C2=A0if (status =3D=3D STAT_INSECURE_DS)
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* We only cache sigs when we've
> validated a reply.
> --				=C2=A0Avoid caching a reply with sigs if
> there's a vaildated break in the=C2=A0
> --				=C2=A0DS chain, so we don't return
> replies from cache missing sigs. */
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_INSECURE;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0no_cache_dnssec =3D 1;
> --			=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0			=C2=A0=C2=A0
> --			=C2=A0=C2=A0if (keycount =3D=3D 0)
> -+			=C2=A0=C2=A0if (status =3D=3D STAT_ABANDONED)
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0result =3D "ABANDONED";
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0status =3D STAT_BOGUS;
> -@@ -2179,7 +1758,6 @@ static struct frec *allocate_frec(time_t now)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0f->dependent =3D NULL;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0f->blocking_query =3D NULL;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0f->stash =3D NULL;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0f->orig_domain =3D NULL;
> - #endif
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0daemon->frec_list =3D f;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -@@ -2248,12 +1826,6 @@ static void free_frec(struct frec *f)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0f->stash =3D NULL;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> --=C2=A0=C2=A0if (f->orig_domain)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(f->orig_domain);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0f->orig_domain =3D NULL;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> -=C2=A0=C2=A0=C2=A0/* Anything we're waiting on is pointless now, too */
> -=C2=A0=C2=A0=C2=A0if (f->blocking_query)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free_frec(f->blocking_query);
> -@@ -2281,14 +1853,23 @@ struct frec *get_new_frec(time_t now, int
> *wait, int force)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0target =3D f;
> -=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{
> --	if (difftime(now, f->time) >=3D 4*TIMEOUT)
> --	=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0free_frec(f);
> --	=C2=A0=C2=A0=C2=A0=C2=A0target =3D f;
> --	=C2=A0=C2=A0}
> --=09
> --	if (!oldest || difftime(f->time, oldest->time) <=3D 0)
> --	=C2=A0=C2=A0oldest =3D f;
> -+#ifdef HAVE_DNSSEC
> -+	=C2=A0=C2=A0=C2=A0=C2=A0/* Don't free DNSSEC sub-queries here, as we may=
 end up
> with
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dangling references to them. T=
hey'll go when their
> "real" query=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0is freed. */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0if (!f->dependent)
> -+#endif
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -+		if (difftime(now, f->time) >=3D 4*TIMEOUT)
> -+		=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0free_frec(f);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0target =3D f;
> -+		=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0
> -+		if (!oldest || difftime(f->time, oldest->time) <=3D
> 0)
> -+		=C2=A0=C2=A0oldest =3D f;
> -+	=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=A0if (target)
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/017-
> Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
> b/src/patches/dnsmasq/017-
> Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
> deleted file mode 100644
> index 5ffaf97..0000000
> --- a/src/patches/dnsmasq/017-
> Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
> +++ /dev/null
> @@ -1,612 +0,0 @@
> -From 93be5b1e023b0c661e1ec2cd6d811a8ec9055c49 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 15 Dec 2015 12:04:40 +0000
> -Subject: [PATCH] Abandon caching RRSIGs and returning them from
> cache.
> -
> -The list of exceptions to being able to locally answer
> -cached data for validated records when DNSSEC data is requested
> -was getting too long, so don't ever do that. This means
> -that the cache no longer has to hold RRSIGS and allows
> -us to lose lots of code. Note that cached validated
> -answers are still returned as long as do=3D0
> ----
> - src/cache.c=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A038 ++---------
> - src/dnsmasq.h |=C2=A0=C2=A0=C2=A010 +--
> - src/dnssec.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A094 ++++-----------------------
> - src/rfc1035.c |=C2=A0=C2=A0197 ++++++------------------------------------=
--
> -------------
> - 4 files changed, 42 insertions(+), 297 deletions(-)
> -
> -diff --git a/src/cache.c b/src/cache.c
> -index 1b76b67..51ba7cc 100644
> ---- a/src/cache.c
> -+++ b/src/cache.c
> -@@ -189,12 +189,7 @@ static void cache_hash(struct crec *crecp)
> - static void cache_blockdata_free(struct crec *crecp)
> - {
> -=C2=A0=C2=A0=C2=A0if (crecp->flags & F_DNSKEY)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_DS)
> --	blockdata_free(crecp->addr.sig.keydata);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --	blockdata_free(crecp->addr.key.keydata);
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(crecp->addr.key.keydata);
> -=C2=A0=C2=A0=C2=A0else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG=
))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(crecp->addr.ds.keydata);
> - }
> -@@ -369,13 +364,8 @@ static struct crec *cache_scan_free(char *name,
> struct all_addr *addr, time_t no
> -=C2=A0		}
> -=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/* Deletion has to be class-sensitiv=
e for DS, DNSKEY,
> RRSIG, also=C2=A0
> --		=C2=A0type-covered sensitive for=C2=A0=C2=A0RRSIG */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((flags & (F_DNSKEY | F_DS)) &&
> --		=C2=A0=C2=A0(flags & (F_DNSKEY | F_DS)) =3D=3D (crecp->flags &
> (F_DNSKEY | F_DS)) &&
> --		=C2=A0=C2=A0crecp->uid =3D=3D addr->addr.dnssec.class &&
> --		=C2=A0=C2=A0(!((flags & (F_DS | F_DNSKEY)) =3D=3D (F_DS |
> F_DNSKEY)) ||=C2=A0
> --		=C2=A0=C2=A0=C2=A0crecp->addr.sig.type_covered =3D=3D addr-
> >addr.dnssec.type))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Deletion has to be class-sensitiv=
e for DS and
> DNSKEY */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((flags & crecp->flags & (F_DNSKE=
Y | F_DS)) &&
> crecp->uid =3D=3D addr->addr.dnssec.class)
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0if (crecp->flags & F_CONFIG)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0return crecp;
> -@@ -532,13 +522,9 @@ struct crec *cache_insert(char *name, struct
> all_addr *addr,
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr free_addr =3D new->addr.add=
r;;
> -=C2=A0
> - #ifdef HAVE_DNSSEC
> --	=C2=A0=C2=A0=C2=A0=C2=A0/* For DNSSEC records, addr holds class and
> type_covered for RRSIG */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0/* For DNSSEC records, addr holds class. */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (new->flags & (F_DS | F_DNSKEY))
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --		free_addr.addr.dnssec.class =3D new->uid;
> --		if ((new->flags & (F_DS | F_DNSKEY)) =3D=3D (F_DS |
> F_DNSKEY))
> --		=C2=A0=C2=A0free_addr.addr.dnssec.type =3D new-
> >addr.sig.type_covered;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free_addr.addr.dnssec.class =3D new-=
>uid;
> - #endif
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0free_avail =3D 1; /* Must be free space now=
. */
> -@@ -653,9 +639,6 @@ struct crec *cache_find_by_name(struct crec
> *crecp, char *name, time_t now, unsi
> -=C2=A0	=C2=A0=C2=A0if (!is_expired(now, crecp) &&
> !is_outdated_cname_pointer(crecp))
> -=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->flags & F_FORWARD) =
&&=C2=A0
> --#ifdef HAVE_DNSSEC
> --		=C2=A0=C2=A0(((crecp->flags & (F_DNSKEY | F_DS)) =3D=3D (prot &
> (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
> --#endif
> -=C2=A0		=C2=A0=C2=A0(crecp->flags & prot) &&
> -=C2=A0		=C2=A0=C2=A0hostname_isequal(cache_get_name(crecp), name))
> -=C2=A0		{
> -@@ -713,9 +696,6 @@ struct crec *cache_find_by_name(struct crec
> *crecp, char *name, time_t now, unsi
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (ans &&=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(ans->flags & F_FORWARD) &&
> --#ifdef HAVE_DNSSEC
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(((ans->flags & (F_DNSKEY | F_DS)) =
=3D=3D (prot & (F_DNSKEY |
> F_DS))) || (prot & F_NSIGMATCH)) &&
> --#endif
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(ans->flags & prot) &&=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0hostname_isequal(cache_get_name(=
ans), name))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return ans;
> -@@ -1472,11 +1452,7 @@ void dump_cache(time_t now)
> - #ifdef HAVE_DNSSEC
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0else if (cache->flags & F_DS)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --		if (cache->flags & F_DNSKEY)
> --		=C2=A0=C2=A0/* RRSIG */
> --		=C2=A0=C2=A0sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
> --			=C2=A0=C2=A0cache->addr.sig.algo, querystr("", cache-
> >addr.sig.type_covered));
> --		else if (!(cache->flags & F_NEG))
> -+		if (!(cache->flags & F_NEG))
> -=C2=A0		=C2=A0=C2=A0sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
> -=C2=A0			=C2=A0=C2=A0cache->addr.ds.algo, cache-
> >addr.ds.digest);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -@@ -1502,8 +1478,6 @@ void dump_cache(time_t now)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0else if (cache->flags & F_CNAME)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0t =3D "C";
> - #ifdef HAVE_DNSSEC
> --	=C2=A0=C2=A0=C2=A0=C2=A0else if ((cache->flags & (F_DS | F_DNSKEY)) =3D=
=3D (F_DS |
> F_DNSKEY))
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0t =3D "G"; /* DNSKEY and DS set -> R=
RISG */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0else if (cache->flags & F_DS)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0t =3D "S";
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0else if (cache->flags & F_DNSKEY)
> -diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> -index 023a1cf..4344cae 100644
> ---- a/src/dnsmasq.h
> -+++ b/src/dnsmasq.h
> -@@ -398,14 +398,9 @@ struct crec {
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char algo;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char digest;=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} ds;=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0struct {
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct blockdata *keydata;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned short keylen, type_covered, =
keytag;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char algo;
> --=C2=A0=C2=A0=C2=A0=C2=A0} sig;
> -=C2=A0=C2=A0=C2=A0} addr;
> -=C2=A0=C2=A0=C2=A0time_t ttd; /* time to die */
> --=C2=A0=C2=A0/* used as class if DNSKEY/DS/RRSIG, index to source for F_HO=
STS
> */
> -+=C2=A0=C2=A0/* used as class if DNSKEY/DS, index to source for F_HOSTS */
> -=C2=A0=C2=A0=C2=A0unsigned int uid;=C2=A0
> -=C2=A0=C2=A0=C2=A0unsigned short flags;
> -=C2=A0=C2=A0=C2=A0union {
> -@@ -445,8 +440,7 @@ struct crec {
> - #define F_SECSTAT=C2=A0=C2=A0=C2=A0(1u<<24)
> - #define F_NO_RR=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(1u<<25)
> - #define F_IPSET=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(1u<<26)
> --#define F_NSIGMATCH (1u<<27)
> --#define F_NOEXTRA=C2=A0=C2=A0=C2=A0(1u<<28)
> -+#define F_NOEXTRA=C2=A0=C2=A0=C2=A0(1u<<27)
> -=C2=A0
> - /* Values of uid in crecs with F_CONFIG bit set. */
> - #define SRC_INTERFACE 0
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index de7b335..1ae03a6 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -1004,7 +1004,7 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> - {
> -=C2=A0=C2=A0=C2=A0unsigned char *psave, *p =3D (unsigned char *)(header+1);
> -=C2=A0=C2=A0=C2=A0struct crec *crecp, *recp1;
> --=C2=A0=C2=A0int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, key=
tag,
> type_covered;
> -+=C2=A0=C2=A0int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, key=
tag;
> -=C2=A0=C2=A0=C2=A0struct blockdata *key;
> -=C2=A0=C2=A0=C2=A0struct all_addr a;
> -=C2=A0
> -@@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (valid)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* DNSKEY RRset determined to be OK, =
now cache it and the
> RRsigs that sign it. */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* DNSKEY RRset determined to be OK, =
now cache it. */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_start_insert();
> -=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=A0p =3D skip_questions(header, ple=
n);
> -@@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0		=C2=A0=C2=A0if ((key =3D blockdata_alloc((char*)p, rdlen - 4)))
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(recp1 =3D cache_insert(n=
ame, &a, now,
> ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
> --			blockdata_free(key);
> -+			{
> -+			=C2=A0=C2=A0blockdata_free(key);
> -+			=C2=A0=C2=A0return STAT_BOGUS;
> -+			}
> -=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;
> -@@ -1169,38 +1172,7 @@ 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=A0		}
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (qtype =3D=3D T_RRSIG)
> --		{
> --		=C2=A0=C2=A0/* RRSIG, cache if covers DNSKEY RRset */
> --		=C2=A0=C2=A0if (rdlen < 18)
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0GETSHORT(type_covered, p);
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0if (type_covered =3D=3D T_DNSKEY)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.class =3D class;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.type =3D type_covered;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=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=A0p +=3D 13; /* labels, orig_ttl, exp=
iration,
> inception */
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(keytag, p);=09
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((key =3D blockdata_alloc((char*=
)psave,
> rdlen)))
> --			{
> --			=C2=A0=C2=A0if (!(crecp =3D cache_insert(name, &a, now,
> ttl,=C2=A0=C2=A0F_FORWARD | F_DNSKEY | F_DS)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(key);
> --			=C2=A0=C2=A0else
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.keydata =3D key;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.keylen =3D rdlen;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.keytag =3D keytag;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.type_covered =3D
> type_covered;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.sig.algo =3D algo;
> --			=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=A0p =3D psave;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> -@@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0	=C2=A0=C2=A0cache_start_insert();
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0a.addr.dnssec.class =3D class;
> --	=C2=A0=C2=A0cache_insert(name, &a, now, ttl, flags);
> -+	=C2=A0=C2=A0if (!cache_insert(name, &a, now, ttl, flags))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0cache_end_insert();=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0
> -@@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0/* Not done, validate now */
> -=C2=A0	=C2=A0=C2=A0if (j =3D=3D i)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ttl, keytag, algo, digest, type_=
covered, sigcnt,
> rrcnt;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ttl, keytag, algo, digest, sigcn=
t, rrcnt;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *psave;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr a;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct blockdata *key;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct crec *crecp;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *wildname;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int have_wildcard =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=A0if (!explore_rrset(header, plen=
, class1, type1, name,
> keyname, &sigcnt, &rrcnt))
> -=C2=A0		return STAT_BOGUS;
> -=C2=A0
> -@@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0		=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0have_wildcard =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=A0=C2=A0/* An attacker replay a wildca=
rd answer with
> a different
> -=C2=A0			=C2=A0answer and overlay a genuine RR. To prove
> this
> -=C2=A0			=C2=A0hasn't happened, the answer must prove
> that
> -@@ -2119,7 +2089,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0			return rc;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> -=C2=A0		=C2=A0=C2=A0
> --		=C2=A0=C2=A0/* Cache RRsigs in answer section, and if we just
> validated a DS RRset, cache it */
> -+		=C2=A0=C2=A0/* If we just validated a DS RRset, cache it */
> -=C2=A0		=C2=A0=C2=A0/* Also note if the RRset is the answer to the
> question, or the target of a CNAME */
> -=C2=A0		=C2=A0=C2=A0cache_start_insert();
> -=C2=A0		=C2=A0=C2=A0
> -@@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=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=A0else if (type2 =3D=3D T_RRSIG)
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rdlen2 < 18)
> --				return STAT_BOGUS; /* 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=A0GETSHORT(type_covered, p2);
> --			=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 type1 &&=
=C2=A0
> --				=C2=A0=C2=A0(type_covered =3D=3D T_A ||
> type_covered =3D=3D T_AAAA ||
> --				=C2=A0=C2=A0=C2=A0type_covered =3D=3D T_CNAME ||
> type_covered =3D=3D T_DS ||=C2=A0
> --				=C2=A0=C2=A0=C2=A0type_covered =3D=3D T_DNSKEY ||
> type_covered =3D=3D T_PTR))=C2=A0
> --				{
> --				=C2=A0=C2=A0a.addr.dnssec.type =3D
> type_covered;
> --				=C2=A0=C2=A0a.addr.dnssec.class =3D class1;
> --				=C2=A0=C2=A0
> --				=C2=A0=C2=A0algo =3D *p2++;
> --				=C2=A0=C2=A0p2 +=3D 13; /* labels, orig_ttl,
> expiration, inception */
> --				=C2=A0=C2=A0GETSHORT(keytag, p2);
> --				=C2=A0=C2=A0
> --				=C2=A0=C2=A0/* We don't cache sigs for
> wildcard answers, because to reproduce the
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0answer from the cache will
> require one or more NSEC/NSEC3 records=C2=A0
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0which we don't cache. The lack
> of the RRSIG ensures that a query for
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0this RRset asking for a secure
> answer will always be forwarded. */
> --				=C2=A0=C2=A0if (!have_wildcard && (key =3D
> blockdata_alloc((char*)psave, rdlen2)))
> --				=C2=A0=C2=A0=C2=A0=C2=A0{
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(crecp =3D
> cache_insert(name, &a, now, ttl,=C2=A0=C2=A0F_FORWARD | F_DNSKEY | F_DS)))
> --					blockdata_free(key);
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --					{
> --					=C2=A0=C2=A0crecp->addr.sig.keydata =3D
> key;
> --					=C2=A0=C2=A0crecp->addr.sig.keylen =3D
> rdlen2;
> --					=C2=A0=C2=A0crecp->addr.sig.keytag =3D
> keytag;
> --					=C2=A0=C2=A0crecp-
> >addr.sig.type_covered =3D type_covered;
> --					=C2=A0=C2=A0crecp->addr.sig.algo =3D
> algo;
> --					}
> --				=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=A0p2 =3D psave;
> -=C2=A0			}
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -diff --git a/src/rfc1035.c b/src/rfc1035.c
> -index 4eb1772..def8fa0 100644
> ---- a/src/rfc1035.c
> -+++ b/src/rfc1035.c
> -@@ -1275,11 +1275,9 @@ int check_for_local_domain(char *name, time_t
> now)
> -=C2=A0=C2=A0=C2=A0struct naptr *naptr;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Note: the call to cache_find_by_name is intended to f=
ind any
> record which matches
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ie A, AAAA, CNAME, DS. Because RRSIG record=
s are marked by
> setting both F_DS and F_DNSKEY,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_find_by name ordinarily only returns =
records with an
> exact match on those bits (ie
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for the call below, only DS records). The F=
_NSIGMATCH bit
> changes this behaviour */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ie A, AAAA, CNAME. */
> -=C2=A0
> --=C2=A0=C2=A0if ((crecp =3D cache_find_by_name(NULL, name, now, F_IPV4 | F=
_IPV6
> | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
> -+=C2=A0=C2=A0if ((crecp =3D cache_find_by_name(NULL, name, now, F_IPV4 | F=
_IPV6
> | F_CNAME |F_NO_RR)) &&
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0(crecp->flags & (F_HOSTS | F_DHC=
P | F_CONFIG)))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -=C2=A0=C2=A0=C2=A0
> -@@ -1566,9 +1564,11 @@ 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(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=A0=C2=A0=C2=A0if ((sec_reqd =3D flags & 0x8000=
))
> --	*do_bit =3D 1;/* do bit */=C2=A0
> -+	{
> -+	=C2=A0=C2=A0*do_bit =3D 1;/* do bit */=C2=A0
> -+	=C2=A0=C2=A0*ad_reqd =3D 1;
> -+	}
> -=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=A0dryrun =3D 1;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> -@@ -1636,98 +1636,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=A0
> --#ifdef HAVE_DNSSEC
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (option_bool(OPT_DNSSEC_VALID) && =
(qtype =3D=3D T_DNSKEY ||
> qtype =3D=3D T_DS))
> --	{
> --	=C2=A0=C2=A0int gotone =3D 0;
> --	=C2=A0=C2=A0struct blockdata *keydata;
> --
> --	=C2=A0=C2=A0/* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
> --	=C2=A0=C2=A0if (sec_reqd)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp =3D NULL;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0while ((crecp =3D cache_find_by_name=
(crecp, name, now,
> F_DNSKEY | F_DS)))
> --		if (crecp->uid =3D=3D qclass && crecp-
> >addr.sig.type_covered =3D=3D qtype)
> --		=C2=A0=C2=A0break;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (!sec_reqd || crecp)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_DS)
> --		{
> --		=C2=A0=C2=A0crecp =3D NULL;
> --		=C2=A0=C2=A0while ((crecp =3D cache_find_by_name(crecp, name,
> now, F_DS)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D qclass)
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --			gotone =3D 1;=C2=A0
> --			if (!dryrun)
> --			=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{
> --				if (crecp->flags & F_NXDOMAIN)
> --				=C2=A0=C2=A0nxdomain =3D 1;
> --				log_query(F_UPSTREAM, name, NULL,
> "no DS");=09
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> --			=C2=A0=C2=A0=C2=A0=C2=A0else if ((keydata =3D
> blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen,
> NULL)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=09
> 		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --				struct all_addr a;
> --				a.addr.keytag =3D=C2=A0=C2=A0crecp-
> >addr.ds.keytag;
> --				log_query(F_KEYTAG | (crecp->flags
> & F_CONFIG), name, &a, "DS keytag %u");
> --				if (add_resource_record(header,
> limit, &trunc, nameoffset, &ansp,=C2=A0
> --							crec_ttl(cr
> ecp, now), &nameoffset,
> --							T_DS,
> qclass, "sbbt",=C2=A0
> --							crecp-
> >addr.ds.keytag, crecp->addr.ds.algo,=C2=A0
> --							crecp-
> >addr.ds.digest, crecp->addr.ds.keylen, keydata))
> --				=C2=A0=C2=A0anscount++;
> --			=09
> --			=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=A0else /* DNSKEY */
> --		{
> --		=C2=A0=C2=A0crecp =3D NULL;
> --		=C2=A0=C2=A0while ((crecp =3D cache_find_by_name(crecp, name,
> now, F_DNSKEY)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D qclass)
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --			gotone =3D 1;
> --			if (!dryrun && (keydata =3D
> blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen,
> NULL)))
> --			=C2=A0=C2=A0{			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0	=09
> 	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr a;
> --			=C2=A0=C2=A0=C2=A0=C2=A0a.addr.keytag =3D=C2=A0=C2=A0crecp-
> >addr.key.keytag;
> --			=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_KEYTAG | (crecp->flags &
> F_CONFIG), name, &a, "DNSKEY keytag %u");
> --			=C2=A0=C2=A0=C2=A0=C2=A0if (add_resource_record(header, limit,
> &trunc, nameoffset, &ansp,=C2=A0
> --						=C2=A0=C2=A0=C2=A0=C2=A0crec_ttl(crecp,
> now), &nameoffset,
> --						=C2=A0=C2=A0=C2=A0=C2=A0T_DNSKEY,
> qclass, "sbbt",=C2=A0
> --						=C2=A0=C2=A0=C2=A0=C2=A0crecp-
> >addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen,
> keydata))
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0anscount++;
> --			=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/* Now do RRSIGs */
> --	=C2=A0=C2=A0if (gotone)
> --	=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=A0=C2=A0=C2=A0auth =3D 0;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!dryrun && sec_reqd)
> --		{
> --		=C2=A0=C2=A0crecp =3D NULL;
> --		=C2=A0=C2=A0while ((crecp =3D cache_find_by_name(crecp, name,
> now, F_DNSKEY | F_DS)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->uid =3D=3D qclass && crecp-
> >addr.sig.type_covered =3D=3D qtype &&
> --			(keydata =3D blockdata_retrieve(crecp-
> >addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --			add_resource_record(header, limit, &trunc,
> nameoffset, &ansp,=C2=A0
> --					=C2=A0=C2=A0=C2=A0=C2=A0crec_ttl(crecp, now),
> &nameoffset,
> --					=C2=A0=C2=A0=C2=A0=C2=A0T_RRSIG, qclass, "t",
> crecp->addr.sig.keylen, keydata);
> --			anscount++;
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> --		}
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	}
> --#endif	=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=A0if (qclass =3D=3D C_IN)
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0struct txt_record *t;
> -@@ -1736,6 +1644,7 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if ((t->class =3D=3D qtype || qtype =3D=3D =
T_ANY) &&
> hostname_isequal(name, t->name))
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		ans =3D 1;
> -+		sec_data =3D 0;
> -=C2=A0		if (!dryrun)
> -=C2=A0		=C2=A0=C2=A0{
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_CONFIG | F_RRNAME, name, NULL,
> "<RR>");
> -@@ -1792,6 +1701,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=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (intr)
> -=C2=A0		{
> -+		=C2=A0=C2=A0sec_data =3D 0;
> -=C2=A0		=C2=A0=C2=A0ans =3D 1;
> -=C2=A0		=C2=A0=C2=A0if (!dryrun)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0{
> -@@ -1805,6 +1715,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=A0else if (ptr)
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0ans =3D 1;
> -+		=C2=A0=C2=A0sec_data =3D 0;
> -=C2=A0		=C2=A0=C2=A0if (!dryrun)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_CONFIG | F_RRNAME,=
 name, NULL,
> "<PTR>");
> -@@ -1819,38 +1730,8 @@ 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=A0else if ((crecp =3D cache_find_=
by_addr(NULL, &addr,
> now, is_arpa)))
> -=C2=A0		{
> --		=C2=A0=C2=A0if (!(crecp->flags & (F_HOSTS | F_DHCP |
> F_CONFIG)) && sec_reqd)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!option_bool(OPT_DNSSEC_VALID) =
||
> ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
> --			crecp =3D NULL;
> --#ifdef HAVE_DNSSEC
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (crecp->flags & F_DNSSECOK)
> --			{
> --			=C2=A0=C2=A0int gotsig =3D 0;
> --			=C2=A0=C2=A0struct crec *rr_crec =3D NULL;
> --
> --			=C2=A0=C2=A0while ((rr_crec =3D
> cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rr_crec->addr.sig.type_covered=
 =3D=3D
> T_PTR && rr_crec->uid =3D=3D C_IN)
> --				{
> --				=C2=A0=C2=A0char *sigdata =3D
> blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec-
> >addr.sig.keylen, NULL);
> --				=C2=A0=C2=A0gotsig =3D 1;
> --				=C2=A0=C2=A0
> --				=C2=A0=C2=A0if (!dryrun &&=C2=A0
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0add_resource_record(header,
> limit, &trunc, nameoffset, &ansp,=C2=A0
> --							=C2=A0=C2=A0rr_crec-
> >ttd - now, &nameoffset,
> --							=C2=A0=C2=A0T_RRSIG,
> C_IN, "t", crecp->addr.sig.keylen, sigdata))
> --				=C2=A0=C2=A0=C2=A0=C2=A0anscount++;
> --				}
> --			=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0if (!gotsig)
> --			=C2=A0=C2=A0=C2=A0=C2=A0crecp =3D NULL;
> --			}
> --#endif
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --		=C2=A0=C2=A0if (crecp)
> -+		=C2=A0=C2=A0/* Don't use cache when DNSSEC data required. */
> -+		=C2=A0=C2=A0if ((crecp->flags & (F_HOSTS | F_DHCP |
> F_CONFIG)) || !sec_reqd || !(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
> -=C2=A0			{=C2=A0
> -@@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0			=C2=A0=C2=A0
> -=C2=A0			=C2=A0=C2=A0if (!(crecp->flags & F_DNSSECOK))
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0sec_data =3D 0;
> --			=C2=A0=C2=A0
> -+			=C2=A0=C2=A0=C2=A0
> -+			=C2=A0=C2=A0ans =3D 1;
> -+			=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=A0=C2=A0ans =3D 1;
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0auth =3D 0;
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_NXDOMAIN)
> -=C2=A0				nxdomain =3D 1;
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!dryrun)
> -=C2=A0				log_query(crecp->flags &
> ~F_FORWARD, name, &addr, NULL);
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0}
> --			=C2=A0=C2=A0else if ((crecp->flags & (F_HOSTS |
> F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
> -+			=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=A0ans =3D 1;
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(crecp->flags & (F_HOSTS=
 |
> F_DHCP)))
> -=C2=A0				auth =3D 0;
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!dryrun)
> -@@ -1892,6 +1773,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=A0else if (is_rev_synth(is_arpa, =
&addr, name))
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0ans =3D 1;
> -+		=C2=A0=C2=A0sec_data =3D 0;
> -=C2=A0		=C2=A0=C2=A0if (!dryrun)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_CONFIG | F_REVERSE=
 | is_arpa,
> name, &addr, NULL);=C2=A0
> -@@ -1908,6 +1790,7 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0/* if not in cache, enabled and private IPV4
> address, return NXDOMAIN */
> -=C2=A0		=C2=A0=C2=A0ans =3D 1;
> -+		=C2=A0=C2=A0sec_data =3D 0;
> -=C2=A0		=C2=A0=C2=A0nxdomain =3D 1;
> -=C2=A0		=C2=A0=C2=A0if (!dryrun)
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_CONFIG | F_REVERSE | F_IPV4 | =
F_NEG
> | F_NXDOMAIN,=C2=A0
> -@@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0		=C2=A0=C2=A0if (i =3D=3D 4)
> -=C2=A0		=C2=A0=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=A0=C2=A0=C2=A0sec_data =3D 0;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!dryrun)
> -=C2=A0			{
> -=C2=A0			=C2=A0=C2=A0addr.addr.addr4.s_addr =3D htonl(a);
> -@@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0				continue;
> - #endif=09
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ans =3D 1;=09
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0sec_data =3D 0;
> -=C2=A0			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!dryrun)
> -=C2=A0				{
> -=C2=A0				=C2=A0=C2=A0gotit =3D 1;
> -@@ -2032,48 +1917,8 @@ 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=A0crecp =3D save;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> --		=C2=A0=C2=A0/* If the client asked for DNSSEC and we can't
> provide RRSIGs, either
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0because we've not doing DNSSEC or the cac=
hed
> answer is signed by negative,
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0don't answer from the cache, forward inst=
ead.
> */
> --		=C2=A0=C2=A0if (!(crecp->flags & (F_HOSTS | F_DHCP |
> F_CONFIG)) && sec_reqd)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!option_bool(OPT_DNSSEC_VALID) =
||
> ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
> --			crecp =3D NULL;
> --#ifdef HAVE_DNSSEC
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (crecp->flags & F_DNSSECOK)
> --			{
> --			=C2=A0=C2=A0/* We're returning validated data, need
> to return the RRSIG too. */
> --			=C2=A0=C2=A0struct crec *rr_crec =3D NULL;
> --			=C2=A0=C2=A0int sigtype =3D type;
> --			=C2=A0=C2=A0/* The signature may have expired even
> though the data is still in cache,=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward instead of answering from
> cache if so. */
> --			=C2=A0=C2=A0int gotsig =3D 0;
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0if (crecp->flags & F_CNAME)
> --			=C2=A0=C2=A0=C2=A0=C2=A0sigtype =3D T_CNAME;
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0while ((rr_crec =3D
> cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rr_crec->addr.sig.type_covered=
 =3D=3D
> sigtype && rr_crec->uid =3D=3D C_IN)
> --				{
> --				=C2=A0=C2=A0char *sigdata =3D
> blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec-
> >addr.sig.keylen, NULL);
> --				=C2=A0=C2=A0gotsig =3D 1;
> --				=C2=A0=C2=A0
> --				=C2=A0=C2=A0if (!dryrun &&=C2=A0
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0add_resource_record(header,
> limit, &trunc, nameoffset, &ansp,=C2=A0
> --							=C2=A0=C2=A0rr_crec-
> >ttd - now, &nameoffset,
> --							=C2=A0=C2=A0T_RRSIG,
> C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
> --				=C2=A0=C2=A0=C2=A0=C2=A0anscount++;
> --				}
> --			=C2=A0=C2=A0=C2=A0=C2=A0}
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0if (!gotsig)
> --			=C2=A0=C2=A0=C2=A0=C2=A0crecp =3D NULL;
> --			}
> --#endif
> --		=C2=A0=C2=A0=C2=A0=C2=A0}		=C2=A0
> --
> --		=C2=A0=C2=A0if (crecp)
> -+		=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=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
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/018-
> Move_code_which_caches_DS_records_to_a_more_logical_place.patch
> b/src/patches/dnsmasq/018-
> Move_code_which_caches_DS_records_to_a_more_logical_place.patch
> deleted file mode 100644
> index ff055f7..0000000
> --- a/src/patches/dnsmasq/018-
> Move_code_which_caches_DS_records_to_a_more_logical_place.patch
> +++ /dev/null
> @@ -1,269 +0,0 @@
> -From d64c81fff7faf4392b688223ef3a617c5c07e7dc Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 15 Dec 2015 16:11:06 +0000
> -Subject: [PATCH] Move code which caches DS records to a more logical
> place.
> -
> ----
> - src/dnssec.c |=C2=A0=C2=A0179 +++++++++++++++++++++++++++++--------------=
--
> -------------
> - 1 file changed, 90 insertions(+), 89 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index 1ae03a6..359231f 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -1204,7 +1204,10 @@ int dnssec_validate_by_ds(time_t now, struct
> dns_header *header, size_t plen, ch
> - int dnssec_validate_ds(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname, int class)
> - {
> -=C2=A0=C2=A0=C2=A0unsigned char *p =3D (unsigned char *)(header+1);
> --=C2=A0=C2=A0int qtype, qclass, val, i, neganswer, nons;
> -+=C2=A0=C2=A0int qtype, qclass, rc, i, neganswer, nons;
> -+=C2=A0=C2=A0int aclass, atype, rdlen;
> -+=C2=A0=C2=A0unsigned long ttl;
> -+=C2=A0=C2=A0struct all_addr a;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (ntohs(header->qdcount) !=3D 1 ||
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!(p =3D skip_name(p, header, ple=
n, 4)))
> -@@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0=C2=A0=C2=A0GETSHORT(qclass, p);
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (qtype !=3D T_DS || qclass !=3D class)
> --=C2=A0=C2=A0=C2=A0=C2=A0val =3D STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0rc =3D STAT_BOGUS;
> -=C2=A0=C2=A0=C2=A0else
> --=C2=A0=C2=A0=C2=A0=C2=A0val =3D dnssec_validate_reply(now, header, plen, =
name, keyname,
> NULL, 0, &neganswer, &nons);
> -+=C2=A0=C2=A0=C2=A0=C2=A0rc =3D dnssec_validate_reply(now, header, plen, n=
ame, keyname,
> NULL, 0, &neganswer, &nons);
> -=C2=A0=C2=A0=C2=A0/* Note dnssec_validate_reply() will have cached positiv=
e answers
> */
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0if (val =3D=3D STAT_INSECURE)
> --=C2=A0=C2=A0=C2=A0=C2=A0val =3D STAT_BOGUS;
> --
> -+=C2=A0=C2=A0if (rc =3D=3D STAT_INSECURE)
> -+=C2=A0=C2=A0=C2=A0=C2=A0rc =3D STAT_BOGUS;
> -+=C2=A0
> -=C2=A0=C2=A0=C2=A0p =3D (unsigned char *)(header+1);
> -=C2=A0=C2=A0=C2=A0extract_name(header, plen, &p, name, 1, 4);
> -=C2=A0=C2=A0=C2=A0p +=3D 4; /* qtype, qclass */
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0if (!(p =3D skip_section(p, ntohs(header->ancount), header, p=
len)))
> --=C2=A0=C2=A0=C2=A0=C2=A0val =3D STAT_BOGUS;
> --=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* If the key needed to validate the DS is on the same d=
omain as
> the DS, we'll
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0loop getting nowhere. Stop that now. T=
his can happen of the DS
> answer comes
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0from the DS's zone, and not the parent=
 zone. */
> --=C2=A0=C2=A0if (val =3D=3D STAT_BOGUS || (val =3D=3D STAT_NEED_KEY &&
> hostname_isequal(name, keyname)))
> -+=C2=A0=C2=A0if (rc =3D=3D STAT_BOGUS || (rc =3D=3D STAT_NEED_KEY &&
> hostname_isequal(name, keyname)))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0log_query(F_NOEXTRA | F_UPSTREAM=
, name, NULL, "BOGUS DS");
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0if (val !=3D STAT_SECURE)
> --=C2=A0=C2=A0=C2=A0=C2=A0return val;
> --
> --=C2=A0=C2=A0/* By here, the answer is proved secure, and a positive answer
> has been cached. */
> --=C2=A0=C2=A0if (neganswer)
> -+=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return rc;
> -+=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (!neganswer)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int rdlen, flags =3D F_FORWARD | F_DS=
 | F_NEG | F_DNSSECOK;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned long ttl, minttl =3D ULONG_M=
AX;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr a;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_start_insert();
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (i =3D 0; i < ntohs(header->ancou=
nt); i++)
> -+	{
> -+	=C2=A0=C2=A0if (!(rc =3D extract_name(header, plen, &p, name, 0, 10)))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0GETSHORT(atype, p);
> -+	=C2=A0=C2=A0GETSHORT(aclass, p);
> -+	=C2=A0=C2=A0GETLONG(ttl, p);
> -+	=C2=A0=C2=A0GETSHORT(rdlen, p);
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (!CHECK_LEN(header, p, plen, rdlen))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (aclass =3D=3D class && atype =3D=3D T_DS && rc =3D=3D 1)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0{=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int algo, digest, keytag;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *psave =3D p;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct blockdata *key;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct crec *crecp;
> -=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rdlen < 4)
> -+		return STAT_BOGUS; /* 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=A0GETSHORT(keytag, 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=A0digest =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/* Cache needs to known class for DN=
SSEC stuff */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.class =3D class;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((key =3D blockdata_alloc((char*)=
p, rdlen - 4)))
> -+		{
> -+		=C2=A0=C2=A0if (!(crecp =3D cache_insert(name, &a, now, ttl,
> F_FORWARD | F_DS | F_DNSSECOK)))
> -+		=C2=A0=C2=A0=C2=A0=C2=A0{
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(key);
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+		=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=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=A0crecp->addr.ds.digest =3D digest;
> -+		=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=A0crecp->addr.ds.algo =3D algo;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keytag =3D keytag;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keylen =3D rdlen - 4=
;=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=A0p =3D psave;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdle=
n))
> -+		return STAT_BOGUS; /* bad packet */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0cache_end_insert();
> -+	}
> -+=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=A0int flags =3D F_FORWARD | F_DS | F_NE=
G | F_DNSSECOK;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned long minttl =3D ULONG_MAX;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(p =3D skip_section(p, ntohs(hea=
der->ancount), header,
> plen)))
> -+	return STAT_BOGUS;
> -+=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 (RCODE(header) =3D=3D NXDOMAI=
N)
> -=C2=A0	flags |=3D F_NXDOMAIN;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -@@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0	=C2=A0=C2=A0if (!(p =3D skip_name(p, header, plen, 0)))
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -=C2=A0	=C2=A0=C2=A0
> --	=C2=A0=C2=A0GETSHORT(qtype, p);=C2=A0
> --	=C2=A0=C2=A0GETSHORT(qclass, p);
> -+	=C2=A0=C2=A0GETSHORT(atype, p);=C2=A0
> -+	=C2=A0=C2=A0GETSHORT(aclass, p);
> -=C2=A0	=C2=A0=C2=A0GETLONG(ttl, p);
> -=C2=A0	=C2=A0=C2=A0GETSHORT(rdlen, p);
> --
> -+	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0if (!CHECK_LEN(header, p, plen, rdlen))
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> --	=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (qclass !=3D class || qtype !=3D T_SOA)
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (aclass !=3D class || atype !=3D T_SOA)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D rdlen;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0continue;
> -=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=A0if (ttl < minttl)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0minttl =3D ttl;
> -=C2=A0	=C2=A0=C2=A0
> -@@ -1306,7 +1369,7 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=C2=A0	=C2=A0=C2=A0log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no 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=C2=A0=C2=A0return STAT_OK;
> - }
> -=C2=A0
> -@@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0/* Not done, validate now */
> -=C2=A0	=C2=A0=C2=A0if (j =3D=3D i)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int ttl, keytag, algo, digest, sigcn=
t, rrcnt;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *psave;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct all_addr a;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct blockdata *key;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0struct crec *crecp;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int sigcnt, rrcnt;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0char *wildname;
> -=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 (!explore_rrset(header, plen=
, class1, type1, name,
> keyname, &sigcnt, &rrcnt))
> -@@ -2032,6 +2091,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0		=C2=A0Can't overwrite name here. */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0strcpy(daemon->workspacename, k=
eyname);
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rc =3D zone_status(daemon->work=
spacename, class1,
> keyname, now);
> -+
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0/* Zone is insecure, don't need to validate RRset
> */
> -@@ -2088,65 +2148,6 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_BOGUS)
> -=C2=A0			return rc;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0/* If we just validated a DS RRset, cache it */
> --		=C2=A0=C2=A0/* Also note if the RRset is the answer to the
> question, or the target of a CNAME */
> --		=C2=A0=C2=A0cache_start_insert();
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0for (p2 =3D ans_start, j =3D 0; j < ntohs(header-
> >ancount); j++)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(rc =3D extract_name(header, p=
len, &p2,
> name, 0, 10)))
> --			return STAT_BOGUS; /* 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=A0GETSHORT(type2, p2);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class2, p2);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETLONG(ttl, p2);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen2, p2);
> --		=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_LEN(header, p2, plen, rd=
len2))
> --			return STAT_BOGUS; /* 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=A0if (class2 =3D=3D class1 && rc =3D=
=3D 1)
> --			{=C2=A0
> --			=C2=A0=C2=A0psave =3D p2;
> --			=C2=A0=C2=A0
> --			=C2=A0=C2=A0if (type1 =3D=3D T_DS && type2 =3D=3D T_DS)
> --			=C2=A0=C2=A0=C2=A0=C2=A0{
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rdlen2 < 4)
> --				return STAT_BOGUS; /* 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=A0GETSHORT(keytag, p2);
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0algo =3D *p2++;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0digest =3D *p2++;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Cache needs to known class for
> DNSSEC stuff */
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0a.addr.dnssec.class =3D class2;
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((key =3D blockdata_alloc((char=
*)p2,
> rdlen2 - 4)))
> --				{
> --				=C2=A0=C2=A0if (!(crecp =3D cache_insert(name,
> &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
> --				=C2=A0=C2=A0=C2=A0=C2=A0blockdata_free(key);
> --				=C2=A0=C2=A0else
> --				=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=A0crecp->addr.ds.digest =3D
> digest;
> --				=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=A0crecp->addr.ds.algo =3D algo;
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keytag =3D
> keytag;
> --				=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0crecp->addr.ds.keylen =3D
> rdlen2 - 4;=C2=A0
> --				=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> --				}
> --			=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --			=C2=A0=C2=A0p2 =3D psave;
> --			}
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p2, plen, rd=
len2))
> --			return STAT_BOGUS; /* bad packet */
> --		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		=C2=A0=C2=A0
> --		=C2=A0=C2=A0cache_end_insert();
> -=C2=A0		}
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	}
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/019-Generalise_RR-
> filtering_code_for_use_with_EDNS0.patch b/src/patches/dnsmasq/019-
> Generalise_RR-filtering_code_for_use_with_EDNS0.patch
> deleted file mode 100644
> index 0a4942a..0000000
> --- a/src/patches/dnsmasq/019-Generalise_RR-
> filtering_code_for_use_with_EDNS0.patch
> +++ /dev/null
> @@ -1,755 +0,0 @@
> -From c2bcd1e183bcc5fdd63811c045355fc57e36ecfd Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Tue, 15 Dec 2015 17:25:21 +0000
> -Subject: [PATCH] Generalise RR-filtering code, for use with EDNS0.
> -
> ----
> - Makefile=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=
=A03 +-
> - bld/Android.mk |=C2=A0=C2=A0=C2=A0=C2=A02 +-
> - src/dnsmasq.h=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A05 +
> - src/dnssec.c=C2=A0=C2=A0=C2=A0|=C2=A0=C2=A0307 +-------------------------=
-----------------
> -------
> - src/forward.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A0=C2=A02 +-
> - src/rrfilter.c |=C2=A0=C2=A0339
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> - 6 files changed, 349 insertions(+), 309 deletions(-)
> - create mode 100644 src/rrfilter.c
> -
> -diff --git a/Makefile b/Makefile
> -index 4c87ea9..b664160 100644
> ---- a/Makefile
> -+++ b/Makefile
> -@@ -73,7 +73,8 @@ objs =3D cache.o rfc1035.o util.o option.o forward.o
> network.o \
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dnsmasq.o dhcp.o lease.o r=
fc2131.o netlink.o dbus.o bpf.o \
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0helper.o tftp.o log.o conn=
track.o dhcp6.o rfc3315.o \
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dhcp-common.o outpacket.o =
radv.o slaac.o auth.o ipset.o \
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0domain.o dnssec.o blockdata.o t=
ables.o loop.o inotify.o
> poll.o
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0domain.o dnssec.o blockdata.o t=
ables.o loop.o inotify.o \
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0poll.o rrfilter.o
> -=C2=A0
> - hdrs =3D dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0dns-protocol.h radv-protoc=
ol.h ip6addr.h
> -diff --git a/bld/Android.mk b/bld/Android.mk
> -index 5364ee7..67b9c4b 100644
> ---- a/bld/Android.mk
> -+++ b/bld/Android.mk
> -@@ -10,7 +10,7 @@ LOCAL_SRC_FILES :=3D=C2=A0=C2=A0bpf.c cache.c dbus.c dhc=
p.c
> dnsmasq.c \
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0dhcp6.c rfc3315.c dhcp-common.c outpacket.=
c \
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0radv.c slaac.c auth.c ipset.c domain.c \
> -=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=A0dnssec.c dnssec-openssl.c blockdata.c tables.c
> \
> --		=C2=A0=C2=A0=C2=A0=C2=A0loop.c inotify.c poll.c
> -+		=C2=A0=C2=A0=C2=A0=C2=A0loop.c inotify.c poll.c rrfilter.c
> -=C2=A0
> - LOCAL_MODULE :=3D dnsmasq
> -=C2=A0
> -diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> -index 4344cae..39a930c 100644
> ---- a/src/dnsmasq.h
> -+++ b/src/dnsmasq.h
> -@@ -1513,3 +1513,8 @@ int poll_check(int fd, short event);
> - void poll_listen(int fd, short event);
> - int do_poll(int timeout);
> -=C2=A0
> -+/* rrfilter.c */
> -+size_t rrfilter(struct dns_header *header, size_t plen, int mode);
> -+u16 *rrfilter_desc(int type);
> -+int expand_workspace(unsigned char ***wkspc, int *szp, int new);
> -+
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index 359231f..fa3eb81 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -507,50 +507,6 @@ static int check_date_range(unsigned long
> date_start, unsigned long date_end)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0&& serial_compare_32(curtime, date_end) =3D=
=3D SERIAL_LT;
> - }
> -=C2=A0
> --static u16 *get_desc(int type)
> --{
> --=C2=A0=C2=A0/* List of RRtypes which include domains in the data.
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00 -> domain
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0integer -> no of plain bytes
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0-1 -> end
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0zero is not a valid RRtype, so the final en=
try is returned for
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0anything which needs no mangling.
> --=C2=A0=C2=A0*/
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0static u16 rr_desc[] =3D=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0{=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_NS, 0, -1,=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MD, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MF, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_CNAME, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_SOA, 0, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MB, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MG, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MR, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_PTR, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MINFO, 0, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MX, 2, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_RP, 0, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_AFSDB, 2, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_RT, 2, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_SIG, 18, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_PX, 2, 0, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_NXT, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_KX, 2, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_SRV, 6, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_DNAME, 0, -1,
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00, -1 /* wildcard/catchall */
> --=C2=A0=C2=A0=C2=A0=C2=A0};=C2=A0
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0u16 *p =3D rr_desc;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0while (*p !=3D type && *p !=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0while (*p++ !=3D (u16)-1);
> --
> --=C2=A0=C2=A0return p+1;
> --}
> --
> - /* Return bytes of canonicalised rdata, when the return value is
> zero, the remaining=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0data, pointed to by *p, should be used raw. */
> - static int get_rdata(struct dns_header *header, size_t plen,
> unsigned char *end, char *buff, int bufflen,
> -@@ -594,34 +550,6 @@ static int get_rdata(struct dns_header *header,
> size_t plen, unsigned char *end,
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> - }
> -=C2=A0
> --static int expand_workspace(unsigned char ***wkspc, int *szp, int
> new)
> --{
> --=C2=A0=C2=A0unsigned char **p;
> --=C2=A0=C2=A0int old =3D *szp;
> --
> --=C2=A0=C2=A0if (old >=3D new+1)
> --=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> --
> --=C2=A0=C2=A0if (new >=3D 100)
> --=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --
> --=C2=A0=C2=A0new +=3D 5;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (!(p =3D whine_malloc(new * sizeof(unsigned char **))))
> --=C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0=C2=A0
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0if (old !=3D 0 && *wkspc)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0memcpy(p, *wkspc, old * sizeof(unsign=
ed char **));
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(*wkspc);
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0*wkspc =3D p;
> --=C2=A0=C2=A0*szp =3D new;
> --
> --=C2=A0=C2=A0return 1;
> --}
> --
> - /* Bubble sort the RRset into the canonical order.=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0Note that the byte-streams from two RRs may get un=
synced:
> consider=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0RRs which have two domain-names at the start and t=
hen other
> data.
> -@@ -849,7 +777,7 @@ static int validate_rrset(time_t now, struct
> dns_header *header, size_t plen, in
> -=C2=A0=C2=A0=C2=A0int rdlen, j, name_labels;
> -=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=A0u16 *rr_desc =3D get_desc(type);
> -+=C2=A0=C2=A0u16 *rr_desc =3D rrfilter_desc(type);
> -=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (wildcard_out)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*wildcard_out =3D NULL;
> -@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct
> dns_header *header, char *end, char *name, i
> -=C2=A0=C2=A0=C2=A0return ret;
> - }
> -=C2=A0
> --/* Go through a domain name, find "pointers" and fix them up based
> on how many bytes
> --=C2=A0=C2=A0=C2=A0we've chopped out of the packet, or check they don't po=
int into
> an elided part.=C2=A0=C2=A0*/
> --static int check_name(unsigned char **namep, struct dns_header
> *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
> --{
> --=C2=A0=C2=A0unsigned char *ansp =3D *namep;
> --
> --=C2=A0=C2=A0while(1)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned int label_type;
> --=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_LEN(header, ansp, plen, 1))
> --	return 0;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0label_type =3D (*ansp) & 0xc0;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (label_type =3D=3D 0xc0)
> --	{
> --	=C2=A0=C2=A0/* pointer for compression. */
> --	=C2=A0=C2=A0unsigned int offset;
> --	=C2=A0=C2=A0int i;
> --	=C2=A0=C2=A0unsigned char *p;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (!CHECK_LEN(header, ansp, plen, 2))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --
> --	=C2=A0=C2=A0offset =3D ((*ansp++) & 0x3f) << 8;
> --	=C2=A0=C2=A0offset |=3D *ansp++;
> --
> --	=C2=A0=C2=A0p =3D offset + (unsigned char *)header;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0for (i =3D 0; i < rr_count; i++)
> --	=C2=A0=C2=A0=C2=A0=C2=A0if (p < rrs[i])
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> --	=C2=A0=C2=A0=C2=A0=C2=A0else
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (i & 1)
> --		offset -=3D rrs[i] - rrs[i-1];
> --
> --	=C2=A0=C2=A0/* does the pointer end up in an elided RR? */
> --	=C2=A0=C2=A0if (i & 1)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --
> --	=C2=A0=C2=A0/* No, scale the pointer */
> --	=C2=A0=C2=A0if (fixup)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ansp -=3D 2;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*ansp++ =3D (offset >> 8) | 0xc0;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*ansp++ =3D offset & 0xff;
> --	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0break;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (label_type =3D=3D 0x80)
> --	return 0; /* reserved */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (label_type =3D=3D 0x40)
> --	{
> --	=C2=A0=C2=A0/* Extended label type */
> --	=C2=A0=C2=A0unsigned int count;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (!CHECK_LEN(header, ansp, plen, 2))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (((*ansp++) & 0x3f) !=3D 1)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0; /* we only understand bitstrings */
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0count =3D *(ansp++); /* Bits in bitstring */
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (count =3D=3D 0) /* count =3D=3D 0 means 256 bits */
> --	=C2=A0=C2=A0=C2=A0=C2=A0ansp +=3D 32;
> --	=C2=A0=C2=A0else
> --	=C2=A0=C2=A0=C2=A0=C2=A0ansp +=3D ((count-1)>>3)+1;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --	{ /* label type =3D=3D 0 Bottom six bits is length */
> --	=C2=A0=C2=A0unsigned int len =3D (*ansp++) & 0x3f;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (!ADD_RDLEN(header, ansp, plen, len))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --
> --	=C2=A0=C2=A0if (len =3D=3D 0)
> --	=C2=A0=C2=A0=C2=A0=C2=A0break; /* zero length label marks the end. */
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --
> --=C2=A0=C2=A0*namep =3D ansp;
> --
> --=C2=A0=C2=A0return 1;
> --}
> --
> --/* Go through RRs and check or fixup the domain names contained
> within */
> --static int check_rrs(unsigned char *p, struct dns_header *header,
> size_t plen, int fixup, unsigned char **rrs, int rr_count)
> --{
> --=C2=A0=C2=A0int i, type, class, rdlen;
> --=C2=A0=C2=A0unsigned char *pp;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0for (i =3D 0; i < ntohs(header->ancount) + ntohs(header->nsco=
unt) +
> ntohs(header->arcount); i++)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0pp =3D p;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(p =3D skip_name(p, header, plen=
, 10)))
> --	return 0;
> --=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, p);=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class, p);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* TTL */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, p);
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (type !=3D T_NSEC && type !=3D T_N=
SEC3 && type !=3D T_RRSIG)
> --	{
> --	=C2=A0=C2=A0/* fixup name of RR */
> --	=C2=A0=C2=A0if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (class =3D=3D C_IN)
> --	=C2=A0=C2=A0=C2=A0=C2=A0{
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0u16 *d;
> --=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (pp =3D p, d =3D get_desc(type);=
 *d !=3D (u16)-1; d++)
> --		{
> --		=C2=A0=C2=A0if (*d !=3D 0)
> --		=C2=A0=C2=A0=C2=A0=C2=A0pp +=3D *d;
> --		=C2=A0=C2=A0else if (!check_name(&pp, header, plen, fixup,
> rrs, rr_count))
> --		=C2=A0=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=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdlen=
))
> --	return 0;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0return 1;
> --}
> --=09
> --
> --size_t filter_rrsigs(struct dns_header *header, size_t plen)
> --{
> --=C2=A0=C2=A0static unsigned char **rrs;
> --=C2=A0=C2=A0static int rr_sz =3D 0;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0unsigned char *p =3D (unsigned char *)(header+1);
> --=C2=A0=C2=A0int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop=
_ar;
> --
> --=C2=A0=C2=A0if (ntohs(header->qdcount) !=3D 1 ||
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!(p =3D skip_name(p, header, plen, 4)=
))
> --=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0GETSHORT(qtype, p);
> --=C2=A0=C2=A0GETSHORT(qclass, p);
> --
> --=C2=A0=C2=A0/* First pass, find pointers to start and end of all the reco=
rds
> we wish to elide:
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0records added for DNSSEC, unless explicity =
queried for */
> --=C2=A0=C2=A0for (rr_found =3D 0, chop_ns =3D 0, chop_an =3D 0, chop_ar =
=3D 0, i =3D 0;=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0i < ntohs(header->ancount) + nt=
ohs(header->nscount) +
> ntohs(header->arcount);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0i++)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *pstart =3D p;
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int type, class;
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(p =3D skip_name(p, header, plen=
, 10)))
> --	return plen;
> --=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, p);=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class, p);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* TTL */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, p);
> --=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 =3D=3D T_NSEC || type =3D=
=3D T_NSEC3 || type =3D=3D T_RRSIG)
> &&=C2=A0
> --	=C2=A0=C2=A0(type !=3D qtype || class !=3D qclass))
> --	{
> --	=C2=A0=C2=A0if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return plen;=C2=A0
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0rrs[rr_found++] =3D pstart;
> --
> --	=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdlen))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0rrs[rr_found++] =3D p;
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0if (i < ntohs(header->ancount))
> --	=C2=A0=C2=A0=C2=A0=C2=A0chop_an++;
> --	=C2=A0=C2=A0else if (i < (ntohs(header->nscount) + ntohs(header-
> >ancount)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0chop_ns++;
> --	=C2=A0=C2=A0else
> --	=C2=A0=C2=A0=C2=A0=C2=A0chop_ar++;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (!ADD_RDLEN(header, p, plen, =
rdlen))
> --	return plen;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0/* Nothing to do. */
> --=C2=A0=C2=A0if (rr_found =3D=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> --
> --=C2=A0=C2=A0/* Second pass, look for pointers in names in the records we'=
re
> keeping and make sure they don't
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0point to records we're going to elide. This=
 is theoretically
> possible, but unlikely. If
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0it happens, we give up and leave the answer=
 unchanged. */
> --=C2=A0=C2=A0p =3D (unsigned char *)(header+1);
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0/* question first */
> --=C2=A0=C2=A0if (!check_name(&p, header, plen, 0, rrs, rr_found))
> --=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> --=C2=A0=C2=A0p +=3D 4; /* qclass, qtype */
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0/* Now answers and NS */
> --=C2=A0=C2=A0if (!check_rrs(p, header, plen, 0, rrs, rr_found))
> --=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0/* Third pass, elide records */
> --=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=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=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=A0p +=3D end-start;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0plen =3D p - (unsigned char *)header;
> --=C2=A0=C2=A0header->ancount =3D htons(ntohs(header->ancount) - chop_an);
> --=C2=A0=C2=A0header->nscount =3D htons(ntohs(header->nscount) - chop_ns);
> --=C2=A0=C2=A0header->arcount =3D htons(ntohs(header->arcount) - chop_ar);
> --
> --=C2=A0=C2=A0/* Fourth pass, fix up pointers in the remaining records */
> --=C2=A0=C2=A0p =3D (unsigned char *)(header+1);
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0check_name(&p, header, plen, 1, rrs, rr_found);
> --=C2=A0=C2=A0p +=3D 4; /* qclass, qtype */
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0check_rrs(p, header, plen, 1, rrs, rr_found);
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0return plen;
> --}
> --
> - unsigned char* hash_questions(struct dns_header *header, size_t
> plen, char *name)
> - {
> -=C2=A0=C2=A0=C2=A0int q;
> -diff --git a/src/forward.c b/src/forward.c
> -index dd22a62..3e801c8 100644
> ---- a/src/forward.c
> -+++ b/src/forward.c
> -@@ -662,7 +662,7 @@ static size_t process_reply(struct dns_header
> *header, time_t now, struct server
> -=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=A0if (!do_bit)
> --=C2=A0=C2=A0=C2=A0=C2=A0n =3D filter_rrsigs(header, n);
> -+=C2=A0=C2=A0=C2=A0=C2=A0n =3D rrfilter(header, n, 1);
> - #endif
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0/* do this after extract_addresses. Ensure NODATA reply =
and
> remove
> -diff --git a/src/rrfilter.c b/src/rrfilter.c
> -new file mode 100644
> -index 0000000..ae12261
> ---- /dev/null
> -+++ b/src/rrfilter.c
> -@@ -0,0 +1,339 @@
> -+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
> -+
> -+=C2=A0=C2=A0=C2=A0This program is free software; you can redistribute it =
and/or
> modify
> -+=C2=A0=C2=A0=C2=A0it under the terms of the GNU General Public License as
> published by
> -+=C2=A0=C2=A0=C2=A0the Free Software Foundation; version 2 dated June, 199=
1, or
> -+=C2=A0=C2=A0=C2=A0(at your option) version 3 dated 29 June, 2007.
> -+=C2=A0
> -+=C2=A0=C2=A0=C2=A0This program is distributed in the hope that it will be=
 useful,
> -+=C2=A0=C2=A0=C2=A0but WITHOUT ANY WARRANTY; without even the implied warr=
anty of
> -+=C2=A0=C2=A0=C2=A0MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=
=A0=C2=A0See the
> -+=C2=A0=C2=A0=C2=A0GNU General Public License for more details.
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0You should have received a copy of the GNU General Publ=
ic
> License
> -+=C2=A0=C2=A0=C2=A0along with this program.=C2=A0=C2=A0If not, see <http:/=
/www.gnu.org/licens
> es/>.
> -+*/
> -+
> -+/* Code to safely remove RRs from an DNS answer */=C2=A0
> -+
> -+#include "dnsmasq.h"
> -+
> -+/* Go through a domain name, find "pointers" and fix them up based
> on how many bytes
> -+=C2=A0=C2=A0=C2=A0we've chopped out of the packet, or check they don't po=
int into
> an elided part.=C2=A0=C2=A0*/
> -+static int check_name(unsigned char **namep, struct dns_header
> *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
> -+{
> -+=C2=A0=C2=A0unsigned char *ansp =3D *namep;
> -+
> -+=C2=A0=C2=A0while(1)
> -+=C2=A0=C2=A0=C2=A0=C2=A0{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned int label_type;
> -+=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_LEN(header, ansp, plen, 1))
> -+	return 0;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0label_type =3D (*ansp) & 0xc0;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (label_type =3D=3D 0xc0)
> -+	{
> -+	=C2=A0=C2=A0/* pointer for compression. */
> -+	=C2=A0=C2=A0unsigned int offset;
> -+	=C2=A0=C2=A0int i;
> -+	=C2=A0=C2=A0unsigned char *p;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (!CHECK_LEN(header, ansp, plen, 2))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+
> -+	=C2=A0=C2=A0offset =3D ((*ansp++) & 0x3f) << 8;
> -+	=C2=A0=C2=A0offset |=3D *ansp++;
> -+
> -+	=C2=A0=C2=A0p =3D offset + (unsigned char *)header;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0for (i =3D 0; i < rr_count; i++)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0if (p < rrs[i])
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0break;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (i & 1)
> -+		offset -=3D rrs[i] - rrs[i-1];
> -+
> -+	=C2=A0=C2=A0/* does the pointer end up in an elided RR? */
> -+	=C2=A0=C2=A0if (i & 1)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+
> -+	=C2=A0=C2=A0/* No, scale the pointer */
> -+	=C2=A0=C2=A0if (fixup)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ansp -=3D 2;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*ansp++ =3D (offset >> 8) | 0xc0;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*ansp++ =3D offset & 0xff;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0}
> -+	=C2=A0=C2=A0break;
> -+	}
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (label_type =3D=3D 0x80)
> -+	return 0; /* reserved */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (label_type =3D=3D 0x40)
> -+	{
> -+	=C2=A0=C2=A0/* Extended label type */
> -+	=C2=A0=C2=A0unsigned int count;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (!CHECK_LEN(header, ansp, plen, 2))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (((*ansp++) & 0x3f) !=3D 1)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0; /* we only understand bitstrings */
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0count =3D *(ansp++); /* Bits in bitstring */
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (count =3D=3D 0) /* count =3D=3D 0 means 256 bits */
> -+	=C2=A0=C2=A0=C2=A0=C2=A0ansp +=3D 32;
> -+	=C2=A0=C2=A0else
> -+	=C2=A0=C2=A0=C2=A0=C2=A0ansp +=3D ((count-1)>>3)+1;
> -+	}
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	{ /* label type =3D=3D 0 Bottom six bits is length */
> -+	=C2=A0=C2=A0unsigned int len =3D (*ansp++) & 0x3f;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (!ADD_RDLEN(header, ansp, plen, len))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+
> -+	=C2=A0=C2=A0if (len =3D=3D 0)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0break; /* zero length label marks the end. */
> -+	}
> -+=C2=A0=C2=A0=C2=A0=C2=A0}
> -+
> -+=C2=A0=C2=A0*namep =3D ansp;
> -+
> -+=C2=A0=C2=A0return 1;
> -+}
> -+
> -+/* Go through RRs and check or fixup the domain names contained
> within */
> -+static int check_rrs(unsigned char *p, struct dns_header *header,
> size_t plen, int fixup, unsigned char **rrs, int rr_count)
> -+{
> -+=C2=A0=C2=A0int i, j, type, class, rdlen;
> -+=C2=A0=C2=A0unsigned char *pp;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0for (i =3D 0; i < ntohs(header->ancount) + ntohs(header->nsco=
unt) +
> ntohs(header->arcount); i++)
> -+=C2=A0=C2=A0=C2=A0=C2=A0{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0pp =3D p;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(p =3D skip_name(p, header, plen=
, 10)))
> -+	return 0;
> -+=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, p);=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class, p);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* TTL */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, p);
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* If this RR is to be elided, don't =
fix up its contents */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (j =3D 0; j < rr_count; j +=3D 2)
> -+	if (rrs[j] =3D=3D pp)
> -+	=C2=A0=C2=A0break;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (j >=3D rr_count)
> -+	{
> -+	=C2=A0=C2=A0/* fixup name of RR */
> -+	=C2=A0=C2=A0if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0if (class =3D=3D C_IN)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0{
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0u16 *d;
> -+=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0for (pp =3D p, d =3D rrfilter_desc(t=
ype); *d !=3D (u16)-1;
> d++)
> -+		{
> -+		=C2=A0=C2=A0if (*d !=3D 0)
> -+		=C2=A0=C2=A0=C2=A0=C2=A0pp +=3D *d;
> -+		=C2=A0=C2=A0else if (!check_name(&pp, header, plen, fixup,
> rrs, rr_count))
> -+		=C2=A0=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=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdlen=
))
> -+	return 0;
> -+=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0return 1;
> -+}
> -+=09
> -+
> -+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
> -+size_t rrfilter(struct dns_header *header, size_t plen, int mode)
> -+{
> -+=C2=A0=C2=A0static unsigned char **rrs;
> -+=C2=A0=C2=A0static int rr_sz =3D 0;
> -+
> -+=C2=A0=C2=A0unsigned char *p =3D (unsigned char *)(header+1);
> -+=C2=A0=C2=A0int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop=
_ar;
> -+
> -+=C2=A0=C2=A0if (ntohs(header->qdcount) !=3D 1 ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0!(p =3D skip_name(p, header, plen, 4)=
))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0GETSHORT(qtype, p);
> -+=C2=A0=C2=A0GETSHORT(qclass, p);
> -+
> -+=C2=A0=C2=A0/* First pass, find pointers to start and end of all the reco=
rds
> we wish to elide:
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0records added for DNSSEC, unless explicity =
queried for */
> -+=C2=A0=C2=A0for (rr_found =3D 0, chop_ns =3D 0, chop_an =3D 0, chop_ar =
=3D 0, i =3D 0;=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0i < ntohs(header->ancount) + nt=
ohs(header->nscount) +
> ntohs(header->arcount);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0i++)
> -+=C2=A0=C2=A0=C2=A0=C2=A0{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *pstart =3D p;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0int type, class;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(p =3D skip_name(p, header, plen=
, 10)))
> -+	return plen;
> -+=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, p);=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class, p);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* TTL */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, 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 (!ADD_RDLEN(header, p, plen, rdlen=
))
> -+	return plen;
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* Don't remove the answer. */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (i < ntohs(header->ancount) && typ=
e =3D=3D qtype && class =3D=3D
> qclass)
> -+	continue;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (mode =3D=3D 0) /* EDNS */
> -+	{
> -+	=C2=A0=C2=A0/* EDNS mode, remove T_OPT from additional section only
> */
> -+	=C2=A0=C2=A0if (i < (ntohs(header->nscount) + ntohs(header->ancount))=20
> || type !=3D T_OPT)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0continue;
> -+	}
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (type !=3D T_NSEC && type !=
=3D T_NSEC3 && type !=3D
> T_RRSIG)
> -+	/* DNSSEC mode, remove SIGs and NSECs from all three
> sections. */
> -+	continue;
> -+=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=A0if (!expand_workspace(&rrs, &rr_sz, r=
r_found + 1))
> -+	return 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=A0rrs[rr_found++] =3D pstart;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0rrs[rr_found++] =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=A0if (i < ntohs(header->ancount))
> -+	chop_an++;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (i < (ntohs(header->nscount) =
+ ntohs(header-
> >ancount)))
> -+	chop_ns++;
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	chop_ar++;
> -+=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* Nothing to do. */
> -+=C2=A0=C2=A0if (rr_found =3D=3D 0)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> -+
> -+=C2=A0=C2=A0/* Second pass, look for pointers in names in the records we'=
re
> keeping and make sure they don't
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0point to records we're going to elide. This=
 is theoretically
> possible, but unlikely. If
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0it happens, we give up and leave the answer=
 unchanged. */
> -+=C2=A0=C2=A0p =3D (unsigned char *)(header+1);
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* question first */
> -+=C2=A0=C2=A0if (!check_name(&p, header, plen, 0, rrs, rr_found))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> -+=C2=A0=C2=A0p +=3D 4; /* qclass, qtype */
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* Now answers and NS */
> -+=C2=A0=C2=A0if (!check_rrs(p, header, plen, 0, rrs, rr_found))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return plen;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* Third pass, elide records */
> -+=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=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=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=A0p +=3D end-start;
> -+=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0plen =3D p - (unsigned char *)header;
> -+=C2=A0=C2=A0header->ancount =3D htons(ntohs(header->ancount) - chop_an);
> -+=C2=A0=C2=A0header->nscount =3D htons(ntohs(header->nscount) - chop_ns);
> -+=C2=A0=C2=A0header->arcount =3D htons(ntohs(header->arcount) - chop_ar);
> -+
> -+=C2=A0=C2=A0/* Fourth pass, fix up pointers in the remaining records */
> -+=C2=A0=C2=A0p =3D (unsigned char *)(header+1);
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0check_name(&p, header, plen, 1, rrs, rr_found);
> -+=C2=A0=C2=A0p +=3D 4; /* qclass, qtype */
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0check_rrs(p, header, plen, 1, rrs, rr_found);
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0return plen;
> -+}
> -+
> -+/* This is used in the DNSSEC code too, hence it's exported */
> -+u16 *rrfilter_desc(int type)
> -+{
> -+=C2=A0=C2=A0/* List of RRtypes which include domains in the data.
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00 -> domain
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0integer -> no of plain bytes
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0-1 -> end
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0zero is not a valid RRtype, so the final en=
try is returned for
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0anything which needs no mangling.
> -+=C2=A0=C2=A0*/
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0static u16 rr_desc[] =3D=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0{=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_NS, 0, -1,=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MD, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MF, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_CNAME, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_SOA, 0, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MB, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MG, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MR, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_PTR, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MINFO, 0, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_MX, 2, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_RP, 0, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_AFSDB, 2, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_RT, 2, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_SIG, 18, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_PX, 2, 0, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_NXT, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_KX, 2, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_SRV, 6, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0T_DNAME, 0, -1,
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A00, -1 /* wildcard/catchall */
> -+=C2=A0=C2=A0=C2=A0=C2=A0};=C2=A0
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0u16 *p =3D rr_desc;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0while (*p !=3D type && *p !=3D 0)
> -+=C2=A0=C2=A0=C2=A0=C2=A0while (*p++ !=3D (u16)-1);
> -+
> -+=C2=A0=C2=A0return p+1;
> -+}
> -+
> -+int expand_workspace(unsigned char ***wkspc, int *szp, int new)
> -+{
> -+=C2=A0=C2=A0unsigned char **p;
> -+=C2=A0=C2=A0int old =3D *szp;
> -+
> -+=C2=A0=C2=A0if (old >=3D new+1)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -+
> -+=C2=A0=C2=A0if (new >=3D 100)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+
> -+=C2=A0=C2=A0new +=3D 5;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (!(p =3D whine_malloc(new * sizeof(unsigned char **))))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0=C2=A0
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (old !=3D 0 && *wkspc)
> -+=C2=A0=C2=A0=C2=A0=C2=A0{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0memcpy(p, *wkspc, old * sizeof(unsign=
ed char **));
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0free(*wkspc);
> -+=C2=A0=C2=A0=C2=A0=C2=A0}
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0*wkspc =3D p;
> -+=C2=A0=C2=A0*szp =3D new;
> -+
> -+=C2=A0=C2=A0return 1;
> -+}
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
> b/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
> deleted file mode 100644
> index ffb412b..0000000
> --- a/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
> +++ /dev/null
> @@ -1,134 +0,0 @@
> -From 2dbba34b2c1289a108f876c78b84889f2a93115d Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Wed, 16 Dec 2015 13:41:58 +0000
> -Subject: [PATCH] DNSSEC validation tweak.
> -
> -A zone which has at least one key with an algorithm we don't
> -support should be considered as insecure.
> ----
> - src/dnssec.c |=C2=A0=C2=A0=C2=A082 ++++++++++++++++++++++++++++++++++++++=
---------
> -----------
> - 1 file changed, 54 insertions(+), 28 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index fa3eb81..dc563e0 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -763,10 +763,10 @@ static int explore_rrset(struct dns_header
> *header, size_t plen, int class, int
> -=C2=A0=C2=A0=C2=A0=C2=A0STAT_NEED_KEY need DNSKEY to complete validation (=
name is
> returned in keyname)
> -=C2=A0=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0need DS to complete valida=
tion (name is returned
> in keyname)
> -=C2=A0
> --=C2=A0=C2=A0=C2=A0if key is non-NULL, use that key, which has the algo an=
d tag
> given in the params of those names,
> -+=C2=A0=C2=A0=C2=A0If key is non-NULL, use that key, which has the algo an=
d tag
> given in the params of those names,
> -=C2=A0=C2=A0=C2=A0=C2=A0otherwise find the key in the cache.
> -=C2=A0
> --=C2=A0=C2=A0=C2=A0name is unchanged on exit. keyname is used as workspace=
 and
> trashed.
> -+=C2=A0=C2=A0=C2=A0Name is unchanged on exit. keyname is used as workspace=
 and
> trashed.
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0Call explore_rrset first to find and count RRs and=
 sigs.
> - */
> -@@ -919,6 +919,7 @@ static int validate_rrset(time_t now, struct
> dns_header *header, size_t plen, in
> -=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> - }
> -=C2=A0=C2=A0
> -+
> - /* The DNS packet is expected to contain the answer to a DNSKEY
> query.
> -=C2=A0=C2=A0=C2=A0=C2=A0Put all DNSKEYs in the answer which are valid into=
 the cache.
> -=C2=A0=C2=A0=C2=A0=C2=A0return codes:
> -@@ -1831,15 +1832,15 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0
> - /* Check signing status of name.
> -=C2=A0=C2=A0=C2=A0=C2=A0returns:
> --=C2=A0=C2=A0=C2=A0STAT_SECURE zone is signed.
> --=C2=A0=C2=A0=C2=A0STAT_INSECURE zone proved unsigned.
> --=C2=A0=C2=A0=C2=A0STAT_NEED_DS require DS record of name returned in keyn=
ame.
> --=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0zone is =
signed.
> -+=C2=A0=C2=A0=C2=A0STAT_INSECURE=C2=A0=C2=A0=C2=A0=C2=A0zone proved unsign=
ed.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0require DS re=
cord of name returned in keyname.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DNSKEY require DNSKEY record of name returned=
 in
> keyname.
> -=C2=A0=C2=A0=C2=A0=C2=A0name returned unaltered.
> - */
> - static int zone_status(char *name, int class, char *keyname, time_t
> now)
> - {
> --=C2=A0=C2=A0int name_start =3D strlen(name);
> -+=C2=A0=C2=A0int secure_ds, 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
> -@@ -1850,27 +1851,52 @@ 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 =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=A0else
> --	do=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=A0=C2=A0=C2=A0=C2=A0{
> --		/* F_DNSSECOK misused in DS cache records to non-
> existance of NS record.
> --		=C2=A0=C2=A0=C2=A0F_NEG && !F_DNSSECOK implies that we've proved
> there's no DS record here,
> --		=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=A0of a zone. We only prove that the DNS tree below
> a node is unsigned when
> --		=C2=A0=C2=A0=C2=A0we prove that we're at a zone cut AND there's no
> DS record.
> --		*/	=C2=A0=C2=A0
> --		if (crecp->flags & F_NEG)
> --		=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0if (crecp->flags & F_DNSSECOK)
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_INSECURE; /* proved no =
DS here */
> --		=C2=A0=C2=A0}
> --		else if (!ds_digest_name(crecp->addr.ds.digest) ||
> !algo_digest_name(crecp->addr.ds.algo))
> --		=C2=A0=C2=A0return STAT_INSECURE; /* algo we can't use -
> insecure */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0}
> --	while ((crecp =3D cache_find_by_name(crecp, keyname, now,
> F_DS)));
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+	{
> -+	=C2=A0=C2=A0secure_ds =3D 0;
> -+	=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=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 (!ds_digest_name(crecp->addr.ds.digest)
> || !algo_digest_name(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=A0while ((crecp =3D cache_find_by_name(crecp, keyname, now,
> 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=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 &&
> !algo_digest_name(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=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (name_start =3D=3D 0)
> -=C2=A0	break;
> -=C2=A0
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/021-
> Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> b/src/patches/dnsmasq/021-
> Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> deleted file mode 100644
> index c3c74cc..0000000
> --- a/src/patches/dnsmasq/021-
> Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> +++ /dev/null
> @@ -1,133 +0,0 @@
> -From dd4ad9ac7ea6d51dcc34a1f2cd2da14efbb87714 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Thu, 17 Dec 2015 10:44:58 +0000
> -Subject: [PATCH] Tweaks to EDNS0 handling in DNS replies.
> -
> ----
> - src/dnssec.c=C2=A0=C2=A0|=C2=A0=C2=A0=C2=A020 +++++++++-----------
> - src/rfc1035.c |=C2=A0=C2=A0=C2=A057 +++++++++++++++++++++++++++++++++----=
---------
> -----------
> - 2 files changed, 42 insertions(+), 35 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index dc563e0..012b2a6 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -2129,18 +2129,16 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0/* Empty DS without NSECS */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_DS)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> --	=C2=A0=C2=A0=C2=A0=C2=A0else
> -+	=C2=A0=C2=A0=C2=A0=C2=A0
> -+	=C2=A0=C2=A0=C2=A0=C2=A0rc =3D zone_status(name, qclass, keyname, now);
> -+	=C2=A0=C2=A0=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> --		rc =3D zone_status(name, qclass, keyname, now);
> --		if (rc !=3D STAT_SECURE)
> --		=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0if (class)
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*class =3D qclass; /* Class for NEE=
D_DS or
> NEED_DNSKEY */
> --		=C2=A0=C2=A0=C2=A0=C2=A0return rc;
> --		=C2=A0=C2=A0}=C2=A0
> --	=09
> --		return STAT_BOGUS; /* signed zone, no NSECs */
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -+		if (class)
> -+		=C2=A0=C2=A0*class =3D qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> -+		return rc;
> -+	=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=A0return STAT_BOGUS; /* signed zone, no NSECs */
> -=C2=A0	=C2=A0=C2=A0}
> -=C2=A0
> -=C2=A0	=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> -diff --git a/src/rfc1035.c b/src/rfc1035.c
> -index def8fa0..188d05f 100644
> ---- a/src/rfc1035.c
> -+++ b/src/rfc1035.c
> -@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=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;
> -=C2=A0=C2=A0=C2=A0size_t len;
> --=C2=A0
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (ntohs(header->ancount) !=3D 0 ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ntohs(header->nscount) !=3D 0 ||
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ntohs(header->qdcount) =3D=3D 0 ||=C2=
=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0OPCODE(header) !=3D QUERY )
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Don't return AD set if checking disabled. */
> -=C2=A0=C2=A0=C2=A0if (header->hb4 & HB4_CD)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0sec_data =3D 0;
> -@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> -=C2=A0=C2=A0=C2=A0*ad_reqd =3D header->hb4 & HB4_AD;
> -=C2=A0=C2=A0=C2=A0*do_bit =3D 0;
> -=C2=A0
> --=C2=A0=C2=A0/* If there is an RFC2671 pseudoheader then it will be
> overwritten by
> -+=C2=A0=C2=A0/* If there is an=C2=A0=C2=A0additional data section then 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=A0the query. We check to see if the do bit is=
 set, if so we
> always
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0forward rather than answering from the cach=
e, which doesn't
> include
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0security information, unless we're in DNSSE=
C validation mode.
> */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the query. */
> -=C2=A0
> --=C2=A0=C2=A0if (find_pseudoheader(header, qlen, 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=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=C2=A0pheader +=3D 4; /* udp size, ext_rcod=
e */
> --=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 ((sec_reqd =3D flags & 0x8000))
> --	{
> --	=C2=A0=C2=A0*do_bit =3D 1;/* do bit */=C2=A0
> --	=C2=A0=C2=A0*ad_reqd =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=A0dryrun =3D 1;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> --=C2=A0=C2=A0if (ntohs(header->qdcount) =3D=3D 0 || OPCODE(header) !=3D QU=
ERY )
> --=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --=C2=A0=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;
> -=C2=A0=C2=A0=C2=A0
> -@@ -1730,8 +1735,12 @@ 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=A0else if ((crecp =3D cache_find_=
by_addr(NULL, &addr,
> now, is_arpa)))
> -=C2=A0		{
> --		=C2=A0=C2=A0/* Don't use cache when DNSSEC data required. */
> --		=C2=A0=C2=A0if ((crecp->flags & (F_HOSTS | F_DHCP |
> F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
> -+		=C2=A0=C2=A0/* Don't use cache when DNSSEC data required,
> unless we know that
> -+		=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=A0validation. */
> -+		=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(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
> -=C2=A0			{=C2=A0
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-
> existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-
> existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> deleted file mode 100644
> index 60503e9..0000000
> --- a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-
> existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> +++ /dev/null
> @@ -1,409 +0,0 @@
> -From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Thu, 17 Dec 2015 11:57:26 +0000
> -Subject: [PATCH] Tidy up DNSSEC non-existence code. Check zone
> status is NSEC
> - proof bad.
> -
> ----
> - src/dnssec.c |=C2=A0=C2=A0207 +++++++++++++++++++++++++------------------=
--
> -------------
> - 1 file changed, 90 insertions(+), 117 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index 012b2a6..ddae497 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -1367,59 +1367,6 @@ static int hostname_cmp(const char *a, const
> char *b)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> - }
> -=C2=A0
> --/* Find all the NSEC or NSEC3 records in a reply.
> --=C2=A0=C2=A0=C2=A0return an array of pointers to them. */
> --static int find_nsec_records(struct dns_header *header, size_t
> plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
> --{
> --=C2=A0=C2=A0static unsigned char **nsecset =3D NULL;
> --=C2=A0=C2=A0static int nsecset_sz =3D 0;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0int type_found =3D 0;
> --=C2=A0=C2=A0unsigned char *p =3D skip_questions(header, plen);
> --=C2=A0=C2=A0int type, class, rdlen, i, nsecs_found;
> --
> --=C2=A0=C2=A0/* Move to NS section */
> --=C2=A0=C2=A0if (!p || !(p =3D skip_section(p, ntohs(header->ancount), hea=
der,
> plen)))
> --=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0for (nsecs_found =3D 0, i =3D ntohs(header->nscount); i !=3D =
0; i--)
> --=C2=A0=C2=A0=C2=A0=C2=A0{
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *pstart =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=A0if (!(p =3D skip_name(p, header, plen=
, 10)))
> --	return 0;
> --=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, p);=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class, p);
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* TTL */
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, p);
> --
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (class =3D=3D class_reqd && (type =
=3D=3D T_NSEC || type =3D=3D
> T_NSEC3))
> --	{
> --	=C2=A0=C2=A0/* No mixed NSECing 'round here, thankyouverymuch */
> --	=C2=A0=C2=A0if (type_found =3D=3D T_NSEC && type =3D=3D T_NSEC3)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --	=C2=A0=C2=A0if (type_found =3D=3D T_NSEC3 && type =3D=3D T_NSEC)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> --
> --	=C2=A0=C2=A0type_found =3D type;
> --
> --	=C2=A0=C2=A0if (!expand_workspace(&nsecset, &nsecset_sz,
> nsecs_found))
> --	=C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0nsecset[nsecs_found++] =3D pstart;
> --	}
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdlen=
))
> --	return 0;
> --=C2=A0=C2=A0=C2=A0=C2=A0}
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0*nsecsetp =3D nsecset;
> --=C2=A0=C2=A0*nsecsetl =3D nsecs_found;
> --=C2=A0=C2=A0
> --=C2=A0=C2=A0return type_found;
> --}
> --
> - static int prove_non_existence_nsec(struct dns_header *header,
> size_t plen, unsigned char **nsecs, int nsec_count,
> -=C2=A0				=C2=A0=C2=A0=C2=A0=C2=A0char *workspace1, char
> *workspace2, char *name, int type, int *nons)
> - {
> -@@ -1436,12 +1383,12 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p =3D nsecs[i];
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!extract_name(header, plen, =
&p, workspace1, 1, 10))
> --	return STAT_BOGUS;
> -+	return 0;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 8; /* class, type, TTL */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, p);
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0psave =3D p;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!extract_name(header, plen, =
&p, workspace2, 1, 10))
> --	return STAT_BOGUS;
> -+	return 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=A0rc =3D hostname_cmp(workspace1, =
name);
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0/* 4035 para 5.4. Last sentence */
> -=C2=A0	=C2=A0=C2=A0if (type =3D=3D T_NSEC || type =3D=3D T_RRSIG)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_SECURE;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -=C2=A0
> -=C2=A0	=C2=A0=C2=A0/* NSEC with the same name as the RR we're testing, che=
ck
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0that the type in question doesn't app=
ear in the type
> map */
> -@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* A CNAME answer would also be=
 valid, so if there's
> a CNAME is should=C2=A0
> -=C2=A0		=C2=A0have been returned. */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((p[2] & (0x80 >> T_CNAME)) =
!=3D 0)
> --		return STAT_BOGUS;
> -+		return 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=A0/* If the SOA bit is set for a =
DS record, then we
> have the
> -=C2=A0		=C2=A0DS from the wrong side of the delegation. */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (type =3D=3D T_DS && (p[2] &=
 (0x80 >> T_SOA)) !=3D 0)
> --		return STAT_BOGUS;
> -+		return 0;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0
> -=C2=A0	=C2=A0=C2=A0while (rdlen >=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=A0if (!CHECK_LEN(header, p, plen,=
 rdlen))
> --		return STAT_BOGUS;
> -+		return 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 (p[0] =3D=3D type >> 8)
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0/* Does the NSEC say our type exists? */
> -=C2=A0		=C2=A0=C2=A0if (offset < p[1] && (p[offset+2] & mask) !=3D 0)
> --		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0		=C2=A0=C2=A0
> -=C2=A0		=C2=A0=C2=A0break; /* finshed checking */
> -=C2=A0		}
> -@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D=C2=A0=C2=A0p[1];
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	=C2=A0=C2=A0
> --	=C2=A0=C2=A0return STAT_SECURE;
> -+	=C2=A0=C2=A0return 1;
> -=C2=A0	}
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else if (rc =3D=3D -1)
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0/* Normal case, name falls between NSEC name and next
> domain name,
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0wrap around case, name falls between =
NSEC name (rc =3D=3D
> -1) and end */
> -=C2=A0	=C2=A0=C2=A0if (hostname_cmp(workspace2, name) >=3D 0 ||
> hostname_cmp(workspace1, workspace2) >=3D 0)
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_SECURE;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -=C2=A0	}
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else=C2=A0
> -=C2=A0	{
> -=C2=A0	=C2=A0=C2=A0/* wrap around case, name falls between start and next
> domain name */
> -=C2=A0	=C2=A0=C2=A0if (hostname_cmp(workspace1, workspace2) >=3D 0 &&
> hostname_cmp(workspace2, name) >=3D0 )
> --	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_SECURE;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -=C2=A0	}
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0return 0;
> - }
> -=C2=A0
> - /* return digest length, or zero on error */
> -@@ -1701,7 +1648,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=A0if (!(p =3D skip_name(nsecs[i], =
header, plen, 15)))
> --	return STAT_BOGUS; /* bad packet */
> -+	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=A0p +=3D 10; /* type, class, TTL, =
rdlen */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0algo =3D *p++;
> -@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0/* No usable NSEC3s */
> -=C2=A0=C2=A0=C2=A0if (i =3D=3D nsec_count)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0p++; /* flags */
> -=C2=A0=C2=A0=C2=A0GETSHORT (iterations, p);
> -=C2=A0=C2=A0=C2=A0salt_len =3D *p++;
> -=C2=A0=C2=A0=C2=A0salt =3D p;
> -=C2=A0=C2=A0=C2=A0if (!CHECK_LEN(header, salt, plen, salt_len))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0; /* bad packet */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Now prune so we only have NSEC3 records with same ite=
rations,
> salt and algo */
> -=C2=A0=C2=A0=C2=A0for (i =3D 0; i < nsec_count; i++)
> -@@ -1730,7 +1677,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=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
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(p =3D skip_name(nsec3p, he=
ader, plen, 15)))
> --	return STAT_BOGUS; /* bad packet */
> -+	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=A0p +=3D 10; /* type, class, TTL, =
rdlen */
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0	continue;
> -=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 (!CHECK_LEN(header, p, plen, =
salt_len))
> --	return STAT_BOGUS; /* bad packet */
> -+	return 0; /* bad packet */
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (memcmp(p, salt, salt_len) !=
=3D 0)
> -=C2=A0	continue;
> -@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Algo is checked as 1 above */
> -=C2=A0=C2=A0=C2=A0if (!(hash =3D hash_find("sha1")))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0
> -=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=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (check_nsec3_coverage(header, plen, digest_len, diges=
t, type,
> workspace1, workspace2, nsecs, nsec_count, nons))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_SECURE;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 1;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Can't find an NSEC3 which covers the name directly, w=
e need
> the "closest encloser NSEC3"=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0or an answer inferred from a wildcard =
record. */
> -@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0	break;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if ((digest_len =3D hash_name(cl=
osest_encloser, &digest, hash,
> salt, salt_len, iterations)) =3D=3D 0)
> --	return STAT_BOGUS;
> -+	return 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=A0for (i =3D 0; i < nsec_count; i+=
+)
> -=C2=A0	if ((p =3D nsecs[i]))
> -=C2=A0	=C2=A0=C2=A0{
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (!extract_name(header, plen, &p, workspa=
ce1, 1, 0)
> ||
> -=C2=A0		!(base32_len =3D base32_decode(workspace1, (unsigned
> char *)workspace2)))
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0	=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (digest_len =3D=3D base32_len &&
> -=C2=A0		memcmp(digest, workspace2, digest_len) =3D=3D 0)
> -@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> -=C2=A0=C2=A0=C2=A0while ((closest_encloser =3D strchr(closest_encloser, '.=
')));
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (!closest_encloser)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Look for NSEC3 that proves the non-existence of the n=
ext-
> closest encloser */
> -=C2=A0=C2=A0=C2=A0if ((digest_len =3D hash_name(next_closest, &digest, has=
h, salt,
> salt_len, iterations)) =3D=3D 0)
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (!check_nsec3_coverage(header, plen, digest_len, dige=
st, type,
> workspace1, workspace2, nsecs, nsec_count, NULL))
> --=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0/* Finally, check that there's no seat of wildcard synth=
esis */
> -=C2=A0=C2=A0=C2=A0if (!wildname)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(wildcard =3D strchr(next_c=
losest, '.')) || wildcard =3D=3D
> next_closest)
> --	return STAT_BOGUS;
> -+	return 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=A0wildcard--;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*wildcard =3D '*';
> -=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 ((digest_len =3D hash_name(wi=
ldcard, &digest, hash, salt,
> salt_len, iterations)) =3D=3D 0)
> --	return STAT_BOGUS;
> -+	return 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 (!check_nsec3_coverage(header=
, plen, digest_len, digest,
> type, workspace1, workspace2, nsecs, nsec_count, NULL))
> --	return STAT_BOGUS;
> -+	return 0;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0return STAT_SECURE;
> -+=C2=A0=C2=A0return 1;
> -+}
> -+
> -+static int prove_non_existence(struct dns_header *header, size_t
> plen, char *keyname, char *name, int qtype, int qclass, char
> *wildname, int *nons)
> -+{
> -+=C2=A0=C2=A0static unsigned char **nsecset =3D NULL;
> -+=C2=A0=C2=A0static int nsecset_sz =3D 0;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0int type_found =3D 0;
> -+=C2=A0=C2=A0unsigned char *p =3D skip_questions(header, plen);
> -+=C2=A0=C2=A0int type, class, rdlen, i, nsecs_found;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* Move to NS section */
> -+=C2=A0=C2=A0if (!p || !(p =3D skip_section(p, ntohs(header->ancount), hea=
der,
> plen)))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0for (nsecs_found =3D 0, i =3D ntohs(header->nscount); i !=3D =
0; i--)
> -+=C2=A0=C2=A0=C2=A0=C2=A0{
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *pstart =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=A0if (!(p =3D skip_name(p, header, plen=
, 10)))
> -+	return 0;
> -+=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, p);=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(class, p);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0p +=3D 4; /* TTL */
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0GETSHORT(rdlen, p);
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (class =3D=3D qclass && (type =3D=
=3D T_NSEC || type =3D=3D T_NSEC3))
> -+	{
> -+	=C2=A0=C2=A0/* No mixed NSECing 'round here, thankyouverymuch */
> -+	=C2=A0=C2=A0if (type_found !=3D 0 && type_found !=3D type)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+
> -+	=C2=A0=C2=A0type_found =3D type;
> -+
> -+	=C2=A0=C2=A0if (!expand_workspace(&nsecset, &nsecset_sz,
> nsecs_found))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return 0;=C2=A0
> -+	=C2=A0=C2=A0
> -+	=C2=A0=C2=A0nsecset[nsecs_found++] =3D pstart;
> -+	}
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdlen=
))
> -+	return 0;
> -+=C2=A0=C2=A0=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=A0return prove_non_existence_nsec(header, plen, nse=
cset,
> nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
> -+=C2=A0=C2=A0else
> -+=C2=A0=C2=A0=C2=A0=C2=A0return prove_non_existence_nsec3(header, plen, ns=
ecset,
> nsecs_found, daemon->workspacename, keyname, name, qtype, wildname,
> nons);
> - }
> -=C2=A0
> - /* Check signing status of name.
> -@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0=C2=A0=C2=A0static unsigned char **targets =3D NULL;
> -=C2=A0=C2=A0=C2=A0static int target_sz =3D 0;
> -=C2=A0
> --=C2=A0=C2=A0unsigned char *ans_start, *p1, *p2, **nsecs;
> -+=C2=A0=C2=A0unsigned char *ans_start, *p1, *p2;
> -=C2=A0=C2=A0=C2=A0int type1, class1, rdlen1, type2, class2, rdlen2, qclass=
, qtype,
> targetidx;
> --=C2=A0=C2=A0int i, j, rc, nsec_count;
> --=C2=A0=C2=A0int nsec_type;
> -+=C2=A0=C2=A0int i, j, rc;
> -=C2=A0
> -=C2=A0=C2=A0=C2=A0if (neganswer)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*neganswer =3D 0;
> -@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0			=C2=A0=C2=A0targets[j] =3D 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=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD)
> --		=C2=A0=C2=A0=C2=A0=C2=A0{
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0/* An attacker replay a wildcard an=
swer with
> a different
> --			=C2=A0answer and overlay a genuine RR. To prove
> this
> --			=C2=A0hasn't happened, the answer must prove
> that
> --			=C2=A0the gennuine record doesn't exist. Check
> that here. */
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(nsec_type =3D find_nsec_recor=
ds(header,
> plen, &nsecs, &nsec_count, class1)))
> --			return STAT_BOGUS; /* No NSECs or 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/* Note that we may not yet have va=
lidated
> the NSEC/NSEC3 RRsets. Since the check
> --			=C2=A0below returns either SECURE or BOGUS,
> that's not a problem. If the RRsets later fail
> --			=C2=A0we'll return BOGUS then. */
> --
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> --			rc =3D prove_non_existence_nsec(header, plen,
> nsecs, nsec_count, daemon->workspacename, keyname, name, type1,
> NULL);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0else
> --			rc =3D prove_non_existence_nsec3(header,
> plen, nsecs, nsec_count, daemon->workspacename,=C2=A0
> --						=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0keyname,
> name, type1, wildname, NULL);
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_BOGUS)
> --			return rc;
> --		=C2=A0=C2=A0=C2=A0=C2=A0}=C2=A0
> -+		=C2=A0=C2=A0=C2=A0/* An attacker replay a wildcard answer with a
> different
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0answer and overlay a genuine RR. To=
 prove
> this
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0hasn't happened, the answer must pr=
ove that
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0the gennuine record doesn't exist. =
Check that
> here.=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Note that we may not yet have valid=
ated the
> NSEC/NSEC3 RRsets.=C2=A0
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0That's not a problem since if the R=
Rsets
> later fail
> -+		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0we'll return BOGUS then. */
> -+		=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE_WILDCARD &&
> !prove_non_existence(header, plen, keyname, name, type1, class1,
> wildname, NULL))
> -+		=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -=C2=A0		}
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0	}
> -@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0
> -=C2=A0	/* For anything other than a DS record, this situation is
> OK if either
> -=C2=A0	=C2=A0=C2=A0=C2=A0the answer is in an unsigned zone, or there's a N=
SEC
> records. */
> --	if (!(nsec_type =3D find_nsec_records(header, plen, &nsecs,
> &nsec_count, qclass)))
> -+	if (!prove_non_existence(header, plen, keyname, name,
> qtype, qclass, NULL, nons))
> -=C2=A0	=C2=A0=C2=A0{
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0/* Empty DS without NSECS */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if (qtype =3D=3D T_DS)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS;
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0rc =3D zone_status(name, qclass, keyname, now);
> --	=C2=A0=C2=A0=C2=A0=C2=A0if (rc !=3D STAT_SECURE)
> -+	=C2=A0=C2=A0=C2=A0=C2=A0if ((rc =3D zone_status(name, qclass, keyname, n=
ow)) !=3D
> STAT_SECURE)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		if (class)
> -=C2=A0		=C2=A0=C2=A0*class =3D qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> -@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* signed zone, no NSECs=
 */
> -=C2=A0	=C2=A0=C2=A0}
> --
> --	=C2=A0=C2=A0if (nsec_type =3D=3D T_NSEC)
> --	=C2=A0=C2=A0rc =3D prove_non_existence_nsec(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, nons);
> --	else
> --	=C2=A0=C2=A0rc =3D prove_non_existence_nsec3(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
> --
> --	if (rc !=3D STAT_SECURE)
> --	=C2=A0=C2=A0return rc;
> -=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=A0return STAT_SECURE;
> ---=C2=A0
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/023-
> Fix_brace_botch_in_dnssec_validate_ds.patch
> b/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
> deleted file mode 100644
> index eda6fbd..0000000
> --- a/src/patches/dnsmasq/023-
> Fix_brace_botch_in_dnssec_validate_ds.patch
> +++ /dev/null
> @@ -1,98 +0,0 @@
> -From 3b799c826db05fc2da1c6d15cbe372e394209d27 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Thu, 17 Dec 2015 16:58:04 +0000
> -Subject: [PATCH] Fix brace botch in dnssec_validate_ds()
> -MIME-Version: 1.0
> -Content-Type: text/plain; charset=3Dutf8
> -Content-Transfer-Encoding: 8bit
> -
> -Thanks to Micha=C3=85=E2=80=9A K=C3=84=E2=84=A2pie=C3=85=E2=80=9E for spot=
ting this.
> ----
> - src/dnssec.c |=C2=A0=C2=A0=C2=A034 +++++++++++++++++-----------------
> - 1 file changed, 17 insertions(+), 17 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index ddae497..1f8c954 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -923,11 +923,11 @@ static int validate_rrset(time_t now, struct
> dns_header *header, size_t plen, in
> - /* The DNS packet is expected to contain the answer to a DNSKEY
> query.
> -=C2=A0=C2=A0=C2=A0=C2=A0Put all DNSKEYs in the answer which are valid into=
 the cache.
> -=C2=A0=C2=A0=C2=A0=C2=A0return codes:
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0STAT_OK=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Done, key(s) in cache.
> --	=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0No DNSKE=
Ys found, which=C2=A0=C2=A0can be
> validated with 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=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0or self-sign for DNSKEY RRset is not
> valid, bad packet.
> --	=C2=A0STAT_NEED_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0DS records to vali=
date a key not found,
> name in keyname=C2=A0
> --	=C2=A0STAT_NEED_DNSKEY=C2=A0=C2=A0DNSKEY records to validate a key not
> found, name in keyname=C2=A0
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0STAT_OK=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Done, key(s) in cache.
> -+	=C2=A0STAT_BOGUS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0No DNSKEYs found, which=C2=
=A0=C2=A0can be validated
> with 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=C2=A0=C2=A0=C2=A0or self-sign for DNSKEY RRset is not valid,
> bad packet.
> -+	=C2=A0STAT_NEED_DS=C2=A0=C2=A0=C2=A0DS records to validate a key not fou=
nd,
> name in keyname=C2=A0
> -+	=C2=A0STAT_NEED_KEY=C2=A0=C2=A0DNSKEY records to validate a key not foun=
d,
> name in keyname=C2=A0
> - */
> - int dnssec_validate_by_ds(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname, int class)
> - {
> -@@ -1224,13 +1224,13 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> -=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=A0p =3D psave;
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> --	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdle=
n))
> --		return STAT_BOGUS; /* bad packet */
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0}
> --	=C2=A0=C2=A0
> --	=C2=A0=C2=A0cache_end_insert();
> -+	=C2=A0=C2=A0if (!ADD_RDLEN(header, p, plen, rdlen))
> -+	=C2=A0=C2=A0=C2=A0=C2=A0return STAT_BOGUS; /* bad packet */
> -=C2=A0	}
> -+
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cache_end_insert();
> -+
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0else
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct
> dns_header *header, size_t plen, char *key
> -=C2=A0
> - /* Check signing status of name.
> -=C2=A0=C2=A0=C2=A0=C2=A0returns:
> --=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0zone is =
signed.
> --=C2=A0=C2=A0=C2=A0STAT_INSECURE=C2=A0=C2=A0=C2=A0=C2=A0zone proved unsign=
ed.
> --=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0require DS re=
cord of name returned in keyname.
> --=C2=A0=C2=A0=C2=A0STAT_NEED_DNSKEY require DNSKEY record of name returned=
 in
> keyname.
> -+=C2=A0=C2=A0=C2=A0STAT_SECURE=C2=A0=C2=A0=C2=A0zone is signed.
> -+=C2=A0=C2=A0=C2=A0STAT_INSECURE zone proved unsigned.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_DS=C2=A0=C2=A0require DS record of name retur=
ned in keyname.
> -+=C2=A0=C2=A0=C2=A0STAT_NEED_KEY require DNSKEY record of name returned in=
 keyname.
> -=C2=A0=C2=A0=C2=A0=C2=A0name returned unaltered.
> - */
> - static int zone_status(char *name, int class, char *keyname, time_t
> now)
> -@@ -2028,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (rc =3D=3D STAT_SECURE)
> -=C2=A0			rc =3D STAT_BOGUS;
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (class)
> --			=C2=A0*class =3D class1; /* Class for NEED_DS or
> NEED_DNSKEY */
> -+			=C2=A0*class =3D class1; /* Class for NEED_DS or
> NEED_KEY */
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0		=C2=A0=C2=A0else=C2=A0
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0rc =3D STAT_INSECURE;=C2=A0
> -@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0		{
> -=C2=A0		=C2=A0=C2=A0/* Zone is insecure, don't need to validate RRset
> */
> -=C2=A0		=C2=A0=C2=A0if (class)
> --		=C2=A0=C2=A0=C2=A0=C2=A0*class =3D class1; /* Class for NEED_DS or
> NEED_DNSKEY */
> -+		=C2=A0=C2=A0=C2=A0=C2=A0*class =3D class1; /* Class for NEED_DS or
> NEED_KEY */
> -=C2=A0		=C2=A0=C2=A0return rc;
> -=C2=A0		}=C2=A0
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0if ((rc =3D zone_status(name, qclass, keyna=
me, now)) !=3D
> STAT_SECURE)
> -=C2=A0	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0		if (class)
> --		=C2=A0=C2=A0*class =3D qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> -+		=C2=A0=C2=A0*class =3D qclass; /* Class for NEED_DS or NEED_KEY
> */
> -=C2=A0		return rc;
> -=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
> -1.7.10.4
> -
> diff --git a/src/patches/dnsmasq/024-
> Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p
> atch b/src/patches/dnsmasq/024-
> Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p
> atch
> deleted file mode 100644
> index abcae5c..0000000
> --- a/src/patches/dnsmasq/024-
> Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p
> atch
> +++ /dev/null
> @@ -1,145 +0,0 @@
> -From 14a4ae883d51130d33da7133287e8867c64bab65 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -Date: Thu, 17 Dec 2015 17:23:03 +0000
> -Subject: [PATCH] Do a better job of determining which DNSSEC sig
> algos are
> - supported.
> -
> ----
> - src/dnssec.c |=C2=A0=C2=A0=C2=A052 +++++++++++++++++++++++++++++++++++++-=
-------
> -------
> - 1 file changed, 37 insertions(+), 15 deletions(-)
> -
> -diff --git a/src/dnssec.c b/src/dnssec.c
> -index 1f8c954..82394ee 100644
> ---- a/src/dnssec.c
> -+++ b/src/dnssec.c
> -@@ -65,10 +65,9 @@ static char *algo_digest_name(int algo)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 8: return "sha256";
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 10: return "sha512";
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 12: return "gosthash94";
> --#ifndef NO_NETTLE_ECC
> -=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";
> --#endif
> -+
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0default: return NULL;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> - }
> -@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash
> *hash, void **ctxp, unsigned char
> - }
> -=C2=A0=C2=A0=C2=A0
> - static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned
> int key_len, unsigned char *sig, size_t sig_len,
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *digest, int algo)
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *digest, size_t
> digest_len, int algo)
> - {
> -=C2=A0=C2=A0=C2=A0unsigned char *p;
> -=C2=A0=C2=A0=C2=A0size_t exp_len;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0static struct rsa_public_key *key =3D NULL;
> -=C2=A0=C2=A0=C2=A0static mpz_t sig_mpz;
> -+
> -+=C2=A0=C2=A0(void)digest_len;
> -=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0if (key =3D=3D NULL)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata
> *key_data, unsigned int key_len,
> - }=C2=A0=C2=A0
> -=C2=A0
> - static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned
> int key_len, unsigned char *sig, size_t sig_len,
> --			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *digest, int algo)
> -+			=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *digest, size_t
> digest_len, int algo)
> - {
> -=C2=A0=C2=A0=C2=A0unsigned char *p;
> -=C2=A0=C2=A0=C2=A0unsigned int t;
> -@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata
> *key_data, unsigned int key_len,
> -=C2=A0=C2=A0=C2=A0static struct dsa_public_key *key =3D NULL;
> -=C2=A0=C2=A0=C2=A0static struct dsa_signature *sig_struct;
> -=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0(void)digest_len;
> -+
> -=C2=A0=C2=A0=C2=A0if (key =3D=3D NULL)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0if (!(sig_struct =3D whine_mallo=
c(sizeof(struct
> dsa_signature))) ||=C2=A0
> -@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct
> blockdata *key_data, unsigned int key_len
> - }=C2=A0
> - #endif=C2=A0
> -=C2=A0
> --static int verify(struct blockdata *key_data, unsigned int key_len,
> unsigned char *sig, size_t sig_len,
> --		=C2=A0=C2=A0unsigned char *digest, size_t digest_len, int
> algo)
> -+static int (*verify_func(int algo))(struct blockdata *key_data,
> unsigned int key_len, unsigned char *sig, size_t sig_len,
> -+				=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *digest, size_t
> digest_len, int algo)
> - {
> --=C2=A0=C2=A0(void)digest_len;
> --
> -+=C2=A0=C2=A0=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* Enure at runtime that we have support for this digest */
> -+=C2=A0=C2=A0if (!hash_find(algo_digest_name(algo)))
> -+=C2=A0=C2=A0=C2=A0=C2=A0return NULL;
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0/* This switch defines which sig algorithms we support, can't
> introspect Nettle for that. */
> -=C2=A0=C2=A0=C2=A0switch (algo)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 1: case 5: case 7: case 8: case 10:
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return dnsmasq_rsa_verify(key_data, k=
ey_len, sig, sig_len,
> digest, algo);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return dnsmasq_rsa_verify;
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 3: case 6:=C2=A0
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return dnsmasq_dsa_verify(key_data, k=
ey_len, sig, sig_len,
> digest, algo);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return dnsmasq_dsa_verify;
> -=C2=A0=C2=A0
> - #ifndef NO_NETTLE_ECC=C2=A0=C2=A0=C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0case 13: case 14:
> --=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return dnsmasq_ecdsa_verify(key_data,=
 key_len, sig, sig_len,
> digest, digest_len, algo);
> -+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return dnsmasq_ecdsa_verify;
> - #endif
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0}
> -=C2=A0=C2=A0=C2=A0
> --=C2=A0=C2=A0return 0;
> -+=C2=A0=C2=A0return NULL;
> -+}
> -+
> -+static int verify(struct blockdata *key_data, unsigned int key_len,
> unsigned char *sig, size_t sig_len,
> -+		=C2=A0=C2=A0unsigned char *digest, size_t digest_len, int
> algo)
> -+{
> -+
> -+=C2=A0=C2=A0int (*func)(struct blockdata *key_data, unsigned int key_len,
> unsigned char *sig, size_t sig_len,
> -+	=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0unsigned char *digest, size_t digest=
_len, int algo);
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0func =3D verify_func(algo);
> -+=C2=A0=C2=A0
> -+=C2=A0=C2=A0if (!func)
> -+=C2=A0=C2=A0=C2=A0=C2=A0return 0;
> -+
> -+=C2=A0=C2=A0return (*func)(key_data, key_len, sig, sig_len, digest,
> digest_len, algo);
> - }
> -=C2=A0
> - /* Convert from presentation format to wire format, in place.
> -@@ -732,7 +754,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=A0if (check_date_range(sig_incept=
ion, sig_expiration)
> &&
> -=C2=A0		=C2=A0=C2=A0labels <=3D name_labels &&
> -=C2=A0		=C2=A0=C2=A0type_covered =3D=3D type &&=C2=A0
> --		=C2=A0=C2=A0algo_digest_name(algo))
> -+		=C2=A0=C2=A0verify_func(algo))
> -=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
> -@@ -1865,7 +1887,7 @@ 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->flags & F_DNSSECOK)
> -=C2=A0			return STAT_INSECURE; /* proved no DS here
> */
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0}
> --		=C2=A0=C2=A0else if (!ds_digest_name(crecp->addr.ds.digest)
> || !algo_digest_name(crecp->addr.ds.algo))
> -+		=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=A0=C2=A0return STAT_INSECURE; /* algo we can't use=
 -
> insecure */
> -=C2=A0		=C2=A0=C2=A0else
> -=C2=A0		=C2=A0=C2=A0=C2=A0=C2=A0secure_ds =3D 1;
> -@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class,
> char *keyname, time_t now)
> -=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 &&
> !algo_digest_name(crecp->addr.key.algo))
> -+	=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))
> -=C2=A0		return STAT_INSECURE;
> -=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_DNSKEY)));
> ---=C2=A0
> -1.7.10.4
> -
> 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
> deleted file mode 100644
> index c016e73..0000000
> --- a/src/patches/dnsmasq/025-
> Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
> +++ /dev/null
> @@ -1,643 +0,0 @@
> -From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -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
> deleted file mode 100644
> index 910921b..0000000
> --- a/src/patches/dnsmasq/026-
> More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
> +++ /dev/null
> @@ -1,262 +0,0 @@
> -From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -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
> deleted file mode 100644
> index 031339e..0000000
> --- a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-
> one_in_DNSSEC_hostname_cmp.patch
> +++ /dev/null
> @@ -1,27 +0,0 @@
> -From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -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
> deleted file mode 100644
> index f3758fc..0000000
> --- a/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
> +++ /dev/null
> @@ -1,39 +0,0 @@
> -From a86fdf437ecc29398f9715ceb5240442a17ac014 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -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
> deleted file mode 100644
> index 33219d2..0000000
> --- a/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
> +++ /dev/null
> @@ -1,39 +0,0 @@
> -From ce5732e84fc46d7f99c152f736cfb4ef5ec98a01 Mon Sep 17 00:00:00
> 2001
> -From: Simon Kelley <simon(a)thekelleys.org.uk>
> -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
> -

--===============2142730740329272608==
Content-Type: application/pgp-signature
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="signature.asc"
MIME-Version: 1.0

LS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS0KVmVyc2lvbjogR251UEcgdjIKCmlRSWNCQUFC
Q2dBR0JRSlcwMVprQUFvSkVJQjU4UDl2a0FrSEhsUVAvajVZK05DM3cyNCtnWnhuMU50a1FpeUEK
d3dCU1gzNXNJcmdzcU5YcjJxamx3eWQxbHgxYWdCaGZiTmU1T05CYm1Pd2tZUi91SVZWNkdNajBo
UmVXcnl5MQpJem9uMysyTHAzM2ZiUlpOcXhhOW9wcHNFUE8veG9Zak8vU3pzZUs5Y1JZM1BUR2FG
K2RUN3lKd3pXejZ4ck5QClZBWnUxazdRbmFhZTR4ZGlzckY4RnNIOVZwd3RYTkFITzMxRGN3MmUw
RFV3OWN2SHJqUUhudTdTOTBOZnhnRDYKS1RhbjdFcDNMNnNLNG5lYWdkYTlTOThzOEJjUjJHbWp5
aTdmeDVLN3JVVXQvclBiUWx5OGhnMGpob2pLeVNhcwpuV2pDWFBLZDVjcTlNcWZWaE81Mmp5bzNM
VThoSTJjeU5Pa1BMYXViOE9FQllCTXRrZkFkTHZJUFZ2RVJERE5ICkpZM1JzY3o4V2dNd0paZEVw
d0ZWUHV3QjBmZWlFdXJYQ3ArWXNxNXIyeW1iaTNmeTBMNGpLb2FmRzF4SFdnT0EKNU1JUTF3UWpD
ZmJUdGxnT1NURVJKcXFjb2dSdEtoYURYREJkVVViMWkzN2VRU0lxWkxpaGZsWERUWWlxcmZRNQpF
VGxpSW1lc2dQRm01d1pJWmpnM2YwOER0YWZ2VkJmdGJWd0dWOVlCRDFONGlEMTVwZnAzaSs2L3Jy
YjVQVmFOCkFWS09OdlhmWDJHOTMxU2ZLZDN6ck1WK0cvVHBiaFV0MmJCMWwrWkttWjAzQXVSVGJB
WmpaajFoVFNhSmowdVcKNldKU0cxOSs5WWI3NldzRHBQdWhDczdrZElnQlNjWitUcThsKzViVVk5
Q1lVYllvMTIyN2grOXkvczA2YzA4dgoyZHlMVFBGS1dqVkViRmdnWmVwWgo9b1hkagotLS0tLUVO
RCBQR1AgU0lHTkFUVVJFLS0tLS0K

--===============2142730740329272608==--