public inbox for development@lists.ipfire.org
 help / color / mirror / Atom feed
From: Matthias Fischer <matthias.fischer@ipfire.org>
To: development@lists.ipfire.org
Subject: [PATCH] dnsmasq 276test8: latest patches from upstream (001-002)
Date: Thu, 04 Feb 2016 20:16:08 +0100	[thread overview]
Message-ID: <1454613368-17813-1-git-send-email-matthias.fischer@ipfire.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 443485 bytes --]

There were problems with patch 037 and the newcomer 057, so
I decided to start all over with '276test8'. All previous patches are
included!

Patch 057 (Final form of configuration for EDNS0 MAC-address code,
http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=1e5051228d543d0db4b32f24a2e6a97f2d061cf0
won't apply - it was always:

...
1 out of 3 hunks FAILED -- saving rejects to file src/dnsmasq.c.rej
...

This patch tries to remove this line:

-      daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_DNS_CLIENT))

which occurs exactly nowhere.

So I switched to '276test8' and started numbering again - building and test
runs are ok since then.

Signed-off-by: Matthias Fischer <matthias.fischer(a)ipfire.org>
---
 lfs/dnsmasq                                        |   62 +-
 src/patches/dnsmasq/001-Fix_FTBFS_on_illumos.patch |   26 +
 ...01-include_0_0_0_0_8_in_DNS_rebind_checks.patch |   41 -
 ...ke_names_of_ARP_script_actions_consistent.patch |   88 +
 ...subnet_to_allow_arbitary_subnet_addresses.patch |  271 ---
 ...h_zones_locally_when_localise_queries_set.patch |   34 -
 .../004-fix_behaviour_of_empty_dhcp-option.patch   |   38 -
 ...ution_to_ENOMEM_error_with_IPv6_multicast.patch |   50 -
 ...page_on_RDNSS_set_in_router_advertisement.patch |   35 -
 ...gned_dangling_CNAME_replies_to_DS_queries.patch |   30 -
 ...6_option_56_does_not_hold_an_address_list.patch |   25 -
 ...pect_the_--no_resolv_flag_in_inotify_code.patch |   47 -
 ..._5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch |   26 -
 ...11-Catch_errors_from_sendmsg_in_DHCP_code.patch |   32 -
 ...12-Update_list_of_subnet_for_--bogus-priv.patch |   48 -
 ...y_address_from_DNS_overlays_A_record_from.patch |   43 -
 ...14-Handle_unknown_DS_hash_algos_correctly.patch |   39 -
 .../015-Fix_crash_at_start_up_with_conf-dir.patch  |   38 -
 ...ajor_rationalisation_of_DNSSEC_validation.patch | 2209 --------------------
 ...hing_RRSIGs_and_returning_them_from_cache.patch |  612 ------
 ...caches_DS_records_to_a_more_logical_place.patch |  269 ---
 ...lise_RR-filtering_code_for_use_with_EDNS0.patch |  755 -------
 .../dnsmasq/020-DNSSEC_validation_tweak.patch      |  134 --
 ...1-Tweaks_to_EDNS0_handling_in_DNS_replies.patch |  133 --
 ..._code_Check_zone_status_is_NSEC_proof_bad.patch |  409 ----
 ...023-Fix_brace_botch_in_dnssec_validate_ds.patch |   98 -
 ...ning_which_DNSSEC_sig_algos_are_supported.patch |  145 --
 ...EDNS0_handling_and_computation_use_of_udp.patch |  643 ------
 ...aks_in_handling_unknown_DNSSEC_algorithms.patch |  262 ---
 ...obscure_off-by-one_in_DNSSEC_hostname_cmp.patch |   27 -
 .../028-Minor_tweak_to_previous_commit.patch       |   39 -
 .../dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch |   39 -
 ...plit_EDNS0_stuff_into_its_own_source_file.patch |  777 -------
 .../031-Handle_extending_EDNS0_OPT_RR.patch        |  295 ---
 ..._512_bytes_that_the_client_isnt_expecting.patch |   65 -
 ...ix_build_failure_when_DNSSEC_code_omitted.patch |   55 -
 ...go_with_DNSKEY_and_DS_also_digest_with_DS.patch |   81 -
 .../035-More_EDNS0_packet_size_tweaks.patch        |  138 --
 ...036-Cache_access_to_the_kernels_ARP_table.patch |  414 ----
 ...DNS-client-id_EDNS0_and_ARP_tracking_code.patch |  976 ---------
 ...38-Correct_logic_for_when_to_start_helper.patch |   25 -
 src/patches/dnsmasq/039-Trivial_code_tweak.patch   |   33 -
 ...SEC_sig_timestamps_when_far_in_the_future.patch |   50 -
 ...ist_code_resulting_in_100percent_CPU_spin.patch |   56 -
 ..._script_support_enabled_and_DHCP_disabled.patch |   48 -
 ...3-Update_copyright_notices_Happy_new_year.patch |  473 -----
 ...when_scripts_excluded_at_compilation_time.patch |   25 -
 ...orwarding_to_private_servers_for_a_domain.patch |   41 -
 ...ors_and_check_we_have_a_root-trust_anchor.patch |   70 -
 ...ze_calculation_when_hosts-file_read_fails.patch |   41 -
 ...main_servers_unless_trust-anchor_provided.patch |  217 --
 src/patches/dnsmasq/049-arp_c_tidy_up.patch        |   34 -
 ...NSSEC_validation_with_private_DNS_servers.patch |  139 --
 .../051-Fix_botch_in_forward_c_flags_code.patch    |   29 -
 .../052-Fix_sporadic_crash_in_find_mac.patch       |   27 -
 ..._code_and_set_conntrack_on_DNSSEC_queries.patch |  270 ---
 ...ms_in_last_commit_when_DNSSEC_not_enabled.patch |   58 -
 ...main-needed_set_and_no_servers_configured.patch |   91 -
 .../dnsmasq/056-Add_--max-port_config_option.patch |  166 --
 59 files changed, 118 insertions(+), 11323 deletions(-)
 create mode 100644 src/patches/dnsmasq/001-Fix_FTBFS_on_illumos.patch
 delete mode 100644 src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.patch
 create mode 100644 src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consistent.patch
 delete mode 100644 src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
 delete mode 100644 src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch
 delete mode 100644 src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-option.patch
 delete mode 100644 src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
 delete mode 100644 src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
 delete mode 100644 src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_queries.patch
 delete mode 100644 src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_address_list.patch
 delete mode 100644 src/patches/dnsmasq/009-Respect_the_--no_resolv_flag_in_inotify_code.patch
 delete mode 100644 src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
 delete mode 100644 src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.patch
 delete mode 100644 src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.patch
 delete mode 100644 src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
 delete mode 100644 src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.patch
 delete mode 100644 src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patch
 delete mode 100644 src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validation.patch
 delete mode 100644 src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
 delete mode 100644 src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch
 delete mode 100644 src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
 delete mode 100644 src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
 delete mode 100644 src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
 delete mode 100644 src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
 delete mode 100644 src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
 delete mode 100644 src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
 delete mode 100644 src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
 delete mode 100644 src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
 delete mode 100644 src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
 delete mode 100644 src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
 delete mode 100644 src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
 delete mode 100644 src/patches/dnsmasq/030-Split_EDNS0_stuff_into_its_own_source_file.patch
 delete mode 100644 src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch
 delete mode 100644 src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting.patch
 delete mode 100644 src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitted.patch
 delete mode 100644 src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch
 delete mode 100644 src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch
 delete mode 100644 src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch
 delete mode 100644 src/patches/dnsmasq/037-First_complete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch
 delete mode 100644 src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.patch
 delete mode 100644 src/patches/dnsmasq/039-Trivial_code_tweak.patch
 delete mode 100644 src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_broke_DNSSEC_sig_timestamps_when_far_in_the_future.patch
 delete mode 100644 src/patches/dnsmasq/041-Fix_botch_in_new_arp-cache_linked-list_code_resulting_in_100percent_CPU_spin.patch
 delete mode 100644 src/patches/dnsmasq/042-Handle_building_with_script_support_enabled_and_DHCP_disabled.patch
 delete mode 100644 src/patches/dnsmasq/043-Update_copyright_notices_Happy_new_year.patch
 delete mode 100644 src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compilation_time.patch
 delete mode 100644 src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch
 delete mode 100644 src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch
 delete mode 100644 src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch
 delete mode 100644 src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch
 delete mode 100644 src/patches/dnsmasq/049-arp_c_tidy_up.patch
 delete mode 100644 src/patches/dnsmasq/050-Complete_work_to_allow_DNSSEC_validation_with_private_DNS_servers.patch
 delete mode 100644 src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch
 delete mode 100644 src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch
 delete mode 100644 src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch
 delete mode 100644 src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch
 delete mode 100644 src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch
 delete mode 100644 src/patches/dnsmasq/056-Add_--max-port_config_option.patch

diff --git a/lfs/dnsmasq b/lfs/dnsmasq
index 95da5d7..e4af9d5 100644
--- a/lfs/dnsmasq
+++ b/lfs/dnsmasq
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 2.75
+VER        = 2.76test8
 
 THISAPP    = dnsmasq-$(VER)
 DL_FILE    = $(THISAPP).tar.xz
@@ -43,7 +43,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = 887236f1ddde6eb57cdb9d01916c9f72
+$(DL_FILE)_MD5 = fecf1d0be1266e033872e5ed4cb7fc72
 
 install : $(TARGET)
 
@@ -73,62 +73,8 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 	@$(PREBUILD)
 	@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_queries_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.patch
-	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/030-Split_EDNS0_stuff_into_its_own_source_file.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitted.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/037-First_complete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/039-Trivial_code_tweak.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_broke_DNSSEC_sig_timestamps_when_far_in_the_future.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/041-Fix_botch_in_new_arp-cache_linked-list_code_resulting_in_100percent_CPU_spin.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/042-Handle_building_with_script_support_enabled_and_DHCP_disabled.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/043-Update_copyright_notices_Happy_new_year.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compilation_time.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/049-arp_c_tidy_up.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/050-Complete_work_to_allow_DNSSEC_validation_with_private_DNS_servers.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch
-	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/056-Add_--max-port_config_option.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/001-Fix_FTBFS_on_illumos.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consistent.patch
 	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
 
 	cd $(DIR_APP) && sed -i src/config.h \
diff --git a/src/patches/dnsmasq/001-Fix_FTBFS_on_illumos.patch b/src/patches/dnsmasq/001-Fix_FTBFS_on_illumos.patch
new file mode 100644
index 0000000..10329df
--- /dev/null
+++ b/src/patches/dnsmasq/001-Fix_FTBFS_on_illumos.patch
@@ -0,0 +1,26 @@
+From 8de875f0fb594ffdea2692418f38c4c9436031f7 Mon Sep 17 00:00:00 2001
+From: Andy Stormont <astormont(a)racktopsystems.com>
+Date: Mon, 1 Feb 2016 12:07:57 +0000
+Subject: [PATCH] Fix FTBFS on illumos
+
+---
+ src/bpf.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/bpf.c b/src/bpf.c
+index 7c4bead..69dea13 100644
+--- a/src/bpf.c
++++ b/src/bpf.c
+@@ -20,7 +20,9 @@
+ #include <ifaddrs.h>
+ 
+ #include <sys/param.h>
++#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
+ #include <sys/sysctl.h>
++#endif
+ #include <net/if.h>
+ #include <net/route.h>
+ #include <net/if_dl.h>
+-- 
+2.1.0
+
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     |    7 +++++++
- src/rfc1035.c |    3 ++-
- 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
-+            Include 0.0.0.0/8 in DNS rebind checks. This range 
-+	    translates to hosts on  the local network, or, at 
-+	    least, 0.0.0.0 accesses the local host, so could
-+	    be targets for DNS rebinding. See RFC 5735 section 3 
-+	    for details. Thanks to Stephen Röttger for the bug report.
-+	    
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
- 	    dhcp-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)
-   in_addr_t ip_addr = ntohl(addr.s_addr);
- 
-   return
--    (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ || 
-+    (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||
-+    ((ip_addr & 0xFF000000) == 0x00000000)  /* RFC 5735 section 3. "here" network */ ||
-     ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
-     ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||
-     ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||
--- 
-1.7.10.4
diff --git a/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consistent.patch b/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consistent.patch
new file mode 100644
index 0000000..d510fe5
--- /dev/null
+++ b/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consistent.patch
@@ -0,0 +1,88 @@
+From e6e751b066f8f45bb708a2e4fd69890496b943f0 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Mon, 1 Feb 2016 17:59:07 +0000
+Subject: [PATCH] Make names of ARP script actions consistent.
+
+---
+ man/dnsmasq.8 | 8 ++++----
+ src/arp.c     | 2 +-
+ src/dnsmasq.h | 2 +-
+ src/helper.c  | 6 +++---
+ 4 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index b6fe6b4..7183265 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -1552,7 +1552,7 @@ with an "old" event.
+ 
+ 
+ There are four further actions which may appear as the first argument
+-to the script, "init", "arp", "arp-old" and "tftp". More may be added in the future, so
++to the script, "init", "arp-add", "arp-del" and "tftp". More may be added in the future, so
+ scripts should be written to ignore unknown actions. "init" is
+ described below in 
+ .B --leasefile-ro
+@@ -1560,10 +1560,10 @@ The "tftp" action is invoked when a TFTP file transfer completes: the
+ arguments are the file size in bytes, the address to which the file
+ was sent, and the complete pathname of the file.
+  
+-The "arp" and "arp-old" actions are only called if enabled with
++The "arp-add" and "arp-del" actions are only called if enabled with
+ .B --script-arp
+-They are are supplied with a MAC address and IP address as arguments. "arp" indicates
+-the arrival of a new entry in the ARP or neighbour table, and arp-old indicates the deletion of same.
++They are are supplied with a MAC address and IP address as arguments. "arp-add" indicates
++the arrival of a new entry in the ARP or neighbour table, and "arp-del" indicates the deletion of same.
+ 
+ .TP
+ .B --dhcp-luascript=<path>
+diff --git a/src/arp.c b/src/arp.c
+index d837ea3..3e347ae 100644
+--- a/src/arp.c
++++ b/src/arp.c
+@@ -216,7 +216,7 @@ int do_arp_script_run(void)
+     {
+ #ifdef HAVE_SCRIPT
+       if (option_bool(OPT_SCRIPT_ARP))
+-	queue_arp(ACTION_ARP_OLD, old->hwaddr, old->hwlen, old->family, &old->addr);
++	queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
+ #endif
+       arp = old;
+       old = arp->next;
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 9d4d6b3..549ef55 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -637,7 +637,7 @@ struct frec {
+ #define ACTION_ADD           4
+ #define ACTION_TFTP          5
+ #define ACTION_ARP           6
+-#define ACTION_ARP_OLD       7
++#define ACTION_ARP_DEL       7
+ 
+ #define LEASE_NEW            1  /* newly created */
+ #define LEASE_CHANGED        2  /* modified */
+diff --git a/src/helper.c b/src/helper.c
+index 6ee21bd..0afee46 100644
+--- a/src/helper.c
++++ b/src/helper.c
+@@ -221,12 +221,12 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
+ 	}
+       else if (data.action == ACTION_ARP)
+ 	{
+-	  action_str = "arp";
++	  action_str = "arp-add";
+ 	  is6 = (data.flags != AF_INET);
+ 	}
+-       else if (data.action == ACTION_ARP_OLD)
++       else if (data.action == ACTION_ARP_DEL)
+ 	{
+-	  action_str = "arp-old";
++	  action_str = "arp-del";
+ 	  is6 = (data.flags != AF_INET);
+ 	  data.action = ACTION_ARP;
+ 	}
+-- 
+2.1.0
+
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     |    4 ++++
- man/dnsmasq.8 |   32 ++++++++++++++++++++-----------
- src/dnsmasq.h |   13 ++++++++++---
- src/option.c  |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
- src/rfc1035.c |   39 +++++++++++++++++++++++++++++++-------
- 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
- 	    least, 0.0.0.0 accesses the local host, so could
- 	    be targets for DNS rebinding. See RFC 5735 section 3 
- 	    for details. Thanks to Stephen Röttger for the bug report.
-+
-+	    Enhance --add-subnet to allow arbitrary subnet addresses.
-+            Thanks to Ed Barsley for the patch.
-+	
- 	    
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-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 
--.B --add-subnet[[=<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[[=[<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=24,96
-+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.
-+.B --add-subnet=1.2.3.4/24
-+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
-+.B --add-subnet=1.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=<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 {
-   struct iname *next;
- };
- 
-+/* subnet parameters from command line */
-+struct mysubnet {
-+  union mysockaddr addr;
-+  int addr_used;
-+  int mask;
-+};
-+
- /* resolv-file parms from command-line */
- struct resolvc {
-   struct resolvc *next;
-@@ -935,9 +942,9 @@ extern struct daemon {
-   struct auth_zone *auth_zones;
-   struct interface_name *int_names;
-   char *mxtarget;
--  int addr4_netmask;
--  int addr6_netmask;
--  char *lease_file; 
-+  struct mysubnet *add_subnet4;
-+  struct mysubnet *add_subnet6;
-+  char *lease_file;
-   char *username, *groupname, *scriptuser;
-   char *luascript;
-   char *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 {
-   { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
-   { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
-   { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
--  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
-+  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
-   { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
-   { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
-   { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
-@@ -722,6 +722,20 @@ static void do_usage(void)
- 
- #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
- 
-+static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 
-+{
-+  if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
-+    addr->sa.sa_family = AF_INET;
-+#ifdef HAVE_IPV6
-+  else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
-+    addr->sa.sa_family = AF_INET6;
-+#endif
-+  else
-+    return _("bad address");
-+   
-+  return NULL;
-+}
-+
- char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
- {
-   int source_port = 0, serv_port = NAMESERVER_PORT;
-@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
- 	    li = match_suffix->next;
- 	    free(match_suffix->suffix);
- 	    free(match_suffix);
--	  }    
-+	  }
- 	break;
-       }
- 
-@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
-       set_option_bool(OPT_CLIENT_SUBNET);
-       if (arg)
- 	{
-+          char *err, *end;
- 	  comma = split(arg);
--	  if (!atoi_check(arg, &daemon->addr4_netmask) || 
--	      (comma && !atoi_check(comma, &daemon->addr6_netmask)))
--	     ret_err(gen_err);
-+
-+          struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
-+          if ((end = split_chr(arg, '/')))
-+	    {
-+	      /* has subnet+len */
-+	      err = parse_mysockaddr(arg, &new->addr);
-+	      if (err)
-+		ret_err(err);
-+	      if (!atoi_check(end, &new->mask))
-+		ret_err(gen_err);
-+	      new->addr_used = 1;
-+	    } 
-+	  else if (!atoi_check(arg, &new->mask))
-+	    ret_err(gen_err);
-+	    
-+          daemon->add_subnet4 = new;
-+
-+          new = opt_malloc(sizeof(struct mysubnet));
-+          if (comma)
-+            {
-+              if ((end = split_chr(comma, '/')))
-+                {
-+                  /* has subnet+len */
-+                  err = parse_mysockaddr(comma, &new->addr);
-+                  if (err)
-+                    ret_err(err);
-+                  if (!atoi_check(end, &new->mask))
-+                    ret_err(gen_err);
-+                  new->addr_used = 1;
-+                }
-+              else
-+                {
-+                  if (!atoi_check(comma, &new->mask))
-+                    ret_err(gen_err);
-+                }
-+            }
-+          daemon->add_subnet6 = new;
- 	}
-       break;
- 
-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
- };
- 
-+static void *get_addrp(union mysockaddr *addr, const short family) 
-+{
-+#ifdef HAVE_IPV6
-+  if (family == AF_INET6)
-+    return &addr->in6.sin6_addr;
-+#endif
-+
-+  return &addr->in.sin_addr;
-+}
-+
- static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
- {
-   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-   
-   int len;
-   void *addrp;
-+  int sa_family = source->sa.sa_family;
- 
- #ifdef HAVE_IPV6
-   if (source->sa.sa_family == AF_INET6)
-     {
--      opt->family = htons(2);
--      opt->source_netmask = daemon->addr6_netmask;
--      addrp = &source->in6.sin6_addr;
-+      opt->source_netmask = daemon->add_subnet6->mask;
-+      if (daemon->add_subnet6->addr_used) 
-+	{
-+	  sa_family = daemon->add_subnet6->addr.sa.sa_family;
-+	  addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
-+	} 
-+      else 
-+	addrp = &source->in6.sin6_addr;
-     }
-   else
- #endif
-     {
--      opt->family = htons(1);
--      opt->source_netmask = daemon->addr4_netmask;
--      addrp = &source->in.sin_addr;
-+      opt->source_netmask = daemon->add_subnet4->mask;
-+      if (daemon->add_subnet4->addr_used)
-+	{
-+	  sa_family = daemon->add_subnet4->addr.sa.sa_family;
-+	  addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
-+	} 
-+      else 
-+	addrp = &source->in.sin_addr;
-     }
-   
-   opt->scope_netmask = 0;
-@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
-   
-   if (opt->source_netmask != 0)
-     {
-+#ifdef HAVE_IPV6
-+      opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
-+#else
-+      opt->family = htons(1);
-+#endif
-       len = ((opt->source_netmask - 1) >> 3) + 1;
-       memcpy(opt->addr, addrp, len);
-       if (opt->source_netmask & 7)
-@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   
-   return len;
- }
--
--- 
-1.7.10.4
diff --git a/src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch b/src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_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_queries_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 |    4 ++--
- 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)
- 
- #ifdef HAVE_AUTH
-       /* find queries for zones we're authoritative for, and answer them directly */
--      if (!auth_dns)
-+      if (!auth_dns && !option_bool(OPT_LOCALISE))
- 	for (zone = daemon->auth_zones; zone; zone = zone->next)
- 	  if (in_zone(zone, daemon->namebuff, NULL))
- 	    {
-@@ -1904,7 +1904,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 	  
- #ifdef HAVE_AUTH
- 	  /* find queries for zones we're authoritative for, and answer them directly */
--	  if (!auth_dns)
-+	  if (!auth_dns && !option_bool(OPT_LOCALISE))
- 	    for (zone = daemon->auth_zones; zone; zone = zone->next)
- 	      if (in_zone(zone, daemon->namebuff, NULL))
- 		{
--- 
-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=option6:dns-server, which
- should inhibit sending option.
-
----
- src/rfc3315.c |    9 +++++----
- 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)
-       
-       if (opt_cfg->opt == OPTION6_REFRESH_TIME)
- 	done_refresh = 1;
-+       
-+      if (opt_cfg->opt == OPTION6_DNS_SERVER)
-+	done_dns = 1;
-       
--      if (opt_cfg->flags & DHOPT_ADDR6)
-+      /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */
-+      if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == OPTION6_DNS_SERVER)
- 	{
- 	  int len, j;
- 	  struct in6_addr *a;
- 	  
--	  if (opt_cfg->opt == OPTION6_DNS_SERVER)
--	    done_dns = 1;
--	  
- 	  for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0; 
- 	       j < opt_cfg->len; j += IN6ADDRSZ, a++)
- 	    if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
--- 
-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 |   13 ++++++++++---
- 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)
- 	    
- 	    if ((daemon->doing_dhcp6 || daemon->relay6) &&
- 		setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
--	      err = 1;
-+	      err = errno;
- 	    
- 	    inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
- 	    
- 	    if (daemon->doing_dhcp6 && 
- 		setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
--	      err = 1;
-+	      err = errno;
- 	    
- 	    inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
- 	    
- 	    if (daemon->doing_ra &&
- 		setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
--	      err = 1;
-+	      err = errno;
- 	    
- 	    if (err)
- 	      {
- 		char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
-+		errno = err;
-+
-+#ifdef HAVE_LINUX_NETWORK
-+		if (errno == ENOMEM)
-+		  my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
-+#endif
-+
- 		if (dienow)
- 		  die(s, iface->name, EC_BADNET);
- 		else
--- 
-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 |    6 +++---
- 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 
--the machine running dnsmasq. By default, he "managed address" bits are set, and
-+router  as the relevant link-local address on 
-+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 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=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
- Set non-default values for router advertisements sent via an
--- 
-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 |    7 ++-----
- 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
-    
-   /* If we return STAT_NO_SIG, name contains the name of the DS query */
-   if (val == STAT_NO_SIG)
--    {
--      *keyname = 0;
--      return val;
--    }  
--
-+    return val;
-+  
-   /* If the key needed to validate the DS is on the same domain as the DS, we'll
-      loop getting nowhere. Stop that now. This can happen of the DS answer comes
-      from the DS's zone, and not the parent zone. */
--- 
-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 |    2 +-
- 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[] = {
-   { "sntp-server", 31,  OT_ADDR_LIST },
-   { "information-refresh-time", 32, OT_TIME },
-   { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
--  { "ntp-server", 56,  OT_ADDR_LIST },
-+  { "ntp-server", 56,  0 },
-   { "bootfile-url", 59, OT_NAME },
-   { "bootfile-param", 60, OT_CSTRING },
-   { NULL, 0, 0 }
--- 
-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        |    7 ++++++-
- debian/changelog |    6 ++++++
- src/inotify.c    |    3 +++
- 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
- 
- 	    Enhance --add-subnet to allow arbitrary subnet addresses.
-             Thanks to Ed Barsley for the patch.
-+
-+	    Respect the --no-resolv flag in inotify code. Fixes bug
-+	    which caused dnsmasq to fail to start if a resolv-file 
-+	    was a dangling symbolic link, even of --no-resolv set.
-+	    Thanks to Alexander Kurtz for spotting the problem.
-+
- 	
--	    
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
- 	    dhcp-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()
-   
-   if (daemon->inotifyfd == -1)
-     die(_("failed to create inotify: %s"), NULL, EC_MISC);
-+
-+  if (option_bool(OPT_NO_RESOLV))
-+    return;
-   
-   for (res = daemon->resolv_files; res; res = res->next)
-     {
--- 
-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 |    3 +--
- 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)
-       if (opt_cfg->opt == OPTION6_DNS_SERVER)
- 	done_dns = 1;
-       
--      /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */
--      if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == OPTION6_DNS_SERVER)
-+      if (opt_cfg->flags & DHOPT_ADDR6)
- 	{
- 	  int len, j;
- 	  struct in6_addr *a;
--- 
-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.  Logs, eg,  iptables
- DROPS of dest 255.255.255.255
-
----
- src/dhcp.c |    7 ++++++-
- 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
-   
-   while(retry_send(sendmsg(fd, &msg, 0)));
-+
-+  /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
-+  if (errno != 0)
-+    my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
-+	      inet_ntoa(dest.sin_addr), strerror(errno));
- }
-- 
-+
- /* check against secondary interface addresses */
- static int check_listen_addrs(struct in_addr local, int if_index, char *label,
- 			      struct in_addr netmask, struct in_addr broadcast, void *vparam)
--- 
-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                         | Description           |
-+------------------------------+-----------------------+
-| 0.IN-ADDR.ARPA               | IPv4 "THIS" NETWORK   |
-| 127.IN-ADDR.ARPA             | IPv4 Loopback NETWORK |
-| 254.169.IN-ADDR.ARPA         | IPv4 LINK LOCAL       |
-| 2.0.192.IN-ADDR.ARPA         | IPv4 TEST-NET-1       |
-| 100.51.198.IN-ADDR.ARPA      | IPv4 TEST-NET-2       |
-| 113.0.203.IN-ADDR.ARPA       | IPv4 TEST-NET-3       |
-| 255.255.255.255.IN-ADDR.ARPA | IPv4 BROADCAST        |
-+------------------------------+-----------------------+
-
-Signed-off-by: Kevin Darbyshire-Bryant <kevin(a)darbyshire-bryant.me.uk>
----
- src/rfc1035.c |    8 ++++++--
- 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)
-   return
-     (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||
-     ((ip_addr & 0xFF000000) == 0x00000000)  /* RFC 5735 section 3. "here" network */ ||
--    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
-     ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||
-     ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||
--    ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ;
-+    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
-+    ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ||
-+    ((ip_addr & 0xFFFFFF00) == 0xC0000200)  /* 192.0.2.0/24   (test-net) */ ||
-+    ((ip_addr & 0xFFFFFF00) == 0xC6336400)  /* 198.51.100.0/24(test-net) */ ||
-+    ((ip_addr & 0xFFFFFF00) == 0xCB007100)  /* 203.0.113.0/24 (test-net) */ ||
-+    ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF)  /* 255.255.255.255/32 (broadcast)*/ ;
- }
- 
- static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
--- 
-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: =?utf8?q?Edwin=20T=C3=B6r=C3=B6k?= <edwin+ml-cerowrt(a)etorok.net>
-Date: Sat, 14 Nov 2015 17:45:48 +0000
-Subject: [PATCH] Fix crash when empty address from DNS overlays A record from
- hosts.
-
----
- CHANGELOG   |    5 +++++
- src/cache.c |    2 +-
- 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
- 	    was a dangling symbolic link, even of --no-resolv set.
- 	    Thanks to Alexander Kurtz for spotting the problem.
- 
-+	    Fix crash when an A or AAAA record is defined locally,
-+	    in a hosts file, and an upstream server sends a reply
-+	    that the same name is empty. Thanks to Edwin Török for
-+	    the patch.
-+
- 	
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-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,
- 	 existing record is for an A or AAAA and
- 	 the record we're trying to insert is the same, 
- 	 just drop the insert, but don't error the whole process. */
--      if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
-+      if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
- 	{
- 	  if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
- 	      new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
--- 
-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 |   13 +++++++++++++
- 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
-   if (crecp->flags & F_NEG)
-     return STAT_INSECURE_DS;
-   
-+  /* 4035 5.2 
-+     If the validator does not support any of the algorithms listed in an
-+     authenticated DS RRset, then the resolver has no supported
-+     authentication path leading from the parent to the child.  The
-+     resolver should treat this case as it would the case of an
-+     authenticated NSEC RRset proving that no DS RRset exists,  */
-+  for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
-+    if (hash_find(ds_digest_name(recp1->addr.ds.digest)))
-+      break;
-+  
-+  if (!recp1)
-+    return STAT_INSECURE_DS;
-+
-   /* NOTE, we need to find ONE DNSKEY which matches the DS */
-   for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--) 
-     {
--- 
-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=/path,*
-
-Thanks to Brian Carpenter and American Fuzzy Lop for finding the bug.
----
- src/option.c |   14 ++++++++++----
- 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
- 		li = opt_malloc(sizeof(struct list));
- 		if (*arg == '*')
- 		  {
--		    li->next = match_suffix;
--		    match_suffix = li;
--		    /* Have to copy: buffer is overwritten */
--		    li->suffix = opt_string_alloc(arg+1);
-+		    /* "*" with no suffix is a no-op */
-+		    if (arg[1] == 0)
-+		      free(li);
-+		    else
-+		      {
-+			li->next = match_suffix;
-+			match_suffix = li;
-+			/* Have to copy: buffer is overwritten */
-+			li->suffix = opt_string_alloc(arg+1);
-+		      }
- 		  }
- 		else
- 		  {
--- 
-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 |   19 +-
- src/dnssec.c  |  926 ++++++++++++++++++++++++++++++---------------------------
- src/forward.c |  741 ++++++++++-----------------------------------
- 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           5
- #define STAT_TRUNCATED          6
- #define STAT_SECURE_WILDCARD    7
--#define STAT_NO_SIG             8
--#define STAT_NO_DS              9
--#define STAT_NO_NS             10
--#define STAT_NEED_DS_NEG       11
--#define STAT_CHASE_CNAME       12
--#define STAT_INSECURE_DS       13
-+#define STAT_OK                 8
-+#define STAT_ABANDONED          9
- 
- #define FREC_NOREBIND           1
- #define FREC_CHECKING_DISABLED  2
-@@ -601,8 +597,7 @@ struct hostsfile {
- #define FREC_AD_QUESTION       32
- #define FREC_DO_QUESTION       64
- #define FREC_ADDED_PHEADER    128
--#define FREC_CHECK_NOSIGN     256
--#define FREC_TEST_PKTSZ       512
-+#define FREC_TEST_PKTSZ       256
- 
- #ifdef HAVE_DNSSEC
- #define HASH_SIZE 20 /* SHA-1 digest size */
-@@ -626,9 +621,7 @@ struct frec {
- #ifdef HAVE_DNSSEC 
-   int class, work_counter;
-   struct blockdata *stash; /* Saved reply, whilst we validate */
--  struct blockdata *orig_domain; /* domain of original query, whilst
--				    we're seeing is if in unsigned domain */
--  size_t stash_len, name_start, name_len;
-+  size_t stash_len;
-   struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
-   struct 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,
-+			  int 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)
-     case 8: return "sha256";
-     case 10: return "sha512";
-     case 12: return "gosthash94";
-+#ifndef NO_NETTLE_ECC
-     case 13: return "sha256";
-     case 14: return "sha384";
-+#endif
-     default: return NULL;
-     }
- }
-@@ -592,30 +594,30 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
-     }
- }
- 
--static int expand_workspace(unsigned char ***wkspc, int *sz, int new)
-+static int expand_workspace(unsigned char ***wkspc, int *szp, int new)
- {
-   unsigned char **p;
--  int new_sz = *sz;
--  
--  if (new_sz > new)
-+  int old = *szp;
-+
-+  if (old >= new+1)
-     return 1;
- 
-   if (new >= 100)
-     return 0;
- 
--  new_sz += 5;
-+  new += 5;
-   
--  if (!(p = whine_malloc((new_sz) * sizeof(unsigned char **))))
-+  if (!(p = whine_malloc(new * sizeof(unsigned char **))))
-     return 0;  
-   
--  if (*wkspc)
-+  if (old != 0 && *wkspc)
-     {
--      memcpy(p, *wkspc, *sz * sizeof(unsigned char **));
-+      memcpy(p, *wkspc, old * sizeof(unsigned char **));
-       free(*wkspc);
-     }
-   
-   *wkspc = p;
--  *sz = new_sz;
-+  *szp = new;
- 
-   return 1;
- }
-@@ -706,47 +708,28 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
-     } while (swap);
- }
- 
--/* Validate a single RRset (class, type, name) in the supplied DNS reply 
--   Return code:
--   STAT_SECURE   if it validates.
--   STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
--   (In this case *wildcard_out points to the "body" of the wildcard within name.) 
--   STAT_NO_SIG no RRsigs found.
--   STAT_INSECURE RRset empty.
--   STAT_BOGUS    signature is wrong, bad packet.
--   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
--
--   if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
--   otherwise find the key in the cache.
-+static unsigned char **rrset = NULL, **sigs = NULL;
- 
--   name 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, 
--			  char *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.
-+   Check signatures, and return keyname associated in keyname. */
-+static int explore_rrset(struct dns_header *header, size_t plen, int class, int type, 
-+			 char *name, char *keyname, int *sigcnt, int *rrcnt)
- {
--  static unsigned char **rrset = NULL, **sigs = NULL;
--  static int rrset_sz = 0, sig_sz = 0;
--  
-+  static int rrset_sz = 0, sig_sz = 0; 
-   unsigned char *p;
--  int rrsetidx, sigidx, res, rdlen, j, name_labels;
--  struct crec *crecp = NULL;
--  int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
--  u16 *rr_desc = get_desc(type);
-- 
--  if (wildcard_out)
--    *wildcard_out = NULL;
--  
-+  int rrsetidx, sigidx, j, rdlen, res;
-+  int name_labels = count_labels(name); /* For 4035 5.3.2 check */
-+  int gotkey = 0;
-+
-   if (!(p = skip_questions(header, plen)))
-     return STAT_BOGUS;
--  
--  name_labels = count_labels(name); /* For 4035 5.3.2 check */
- 
--  /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
-+   /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
-   for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount); 
-        j != 0; j--) 
-     {
-       unsigned char *pstart, *pdata;
--      int stype, sclass;
-+      int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
- 
-       pstart = p;
-       
-@@ -762,14 +745,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       GETSHORT(rdlen, p);
-       
-       if (!CHECK_LEN(header, p, plen, rdlen))
--	return STAT_BOGUS; 
-+	return 0; 
-       
-       if (res == 1 && sclass == class)
- 	{
- 	  if (stype == type)
- 	    {
- 	      if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
--		return STAT_BOGUS; 
-+		return 0; 
- 	      
- 	      rrset[rrsetidx++] = pstart;
- 	    }
-@@ -777,14 +760,54 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- 	  if (stype == T_RRSIG)
- 	    {
- 	      if (rdlen < 18)
--		return STAT_BOGUS; /* bad packet */ 
-+		return 0; /* bad packet */ 
- 	      
- 	      GETSHORT(type_covered, p);
-+	      algo = *p++;
-+	      labels = *p++;
-+	      p += 4; /* orig_ttl */
-+	      GETLONG(sig_expiration, p);
-+	      GETLONG(sig_inception, p);
-+	      p += 2; /* key_tag */
- 	      
--	      if (type_covered == type)
-+	      if (gotkey)
-+		{
-+		  /* If there's more than one SIG, ensure they all have same keyname */
-+		  if (extract_name(header, plen, &p, keyname, 0, 0) != 1)
-+		    return 0;
-+		}
-+	      else
-+		{
-+		  gotkey = 1;
-+		  
-+		  if (!extract_name(header, plen, &p, keyname, 1, 0))
-+		    return 0;
-+		  
-+		  /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
-+		     the name of the zone containing the RRset. We can't tell that
-+		     for certain, but we can check that  the RRset name is equal to
-+		     or encloses the signers name, which should be enough to stop 
-+		     an attacker using signatures made with the key of an unrelated 
-+		     zone he controls. Note that the root key is always allowed. */
-+		  if (*keyname != 0)
-+		    {
-+		      char *name_start;
-+		      for (name_start = name; !hostname_isequal(name_start, keyname); )
-+			if ((name_start = strchr(name_start, '.')))
-+			  name_start++; /* chop a label off and try again */
-+			else
-+			  return 0;
-+		    }
-+		}
-+		  
-+	      /* Don't count signatures for algos we don't support */
-+	      if (check_date_range(sig_inception, sig_expiration) &&
-+		  labels <= name_labels &&
-+		  type_covered == type && 
-+		  algo_digest_name(algo))
- 		{
- 		  if (!expand_workspace(&sigs, &sig_sz, sigidx))
--		    return STAT_BOGUS; 
-+		    return 0; 
- 		  
- 		  sigs[sigidx++] = pdata;
- 		} 
-@@ -794,17 +817,45 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- 	}
-       
-       if (!ADD_RDLEN(header, p, plen, rdlen))
--	return STAT_BOGUS;
-+	return 0;
-     }
-   
--  /* RRset empty */
--  if (rrsetidx == 0)
--    return STAT_INSECURE; 
-+  *sigcnt = sigidx;
-+  *rrcnt = rrsetidx;
-+
-+  return 1;
-+}
-+
-+/* Validate a single RRset (class, type, name) in the supplied DNS reply 
-+   Return code:
-+   STAT_SECURE   if it validates.
-+   STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
-+   (In this case *wildcard_out points to the "body" of the wildcard within name.) 
-+   STAT_BOGUS    signature is wrong, bad packet.
-+   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
-+   STAT_NEED_DS  need DS to complete validation (name is returned in keyname)
-+
-+   if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
-+   otherwise find the key in the cache.
- 
--  /* no RRSIGs */
--  if (sigidx == 0)
--    return STAT_NO_SIG; 
-+   name is unchanged on exit. keyname is used as workspace and trashed.
-+
-+   Call 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, 
-+			  char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
-+{
-+  unsigned char *p;
-+  int rdlen, j, name_labels;
-+  struct crec *crecp = NULL;
-+  int algo, labels, orig_ttl, key_tag;
-+  u16 *rr_desc = get_desc(type);
-+ 
-+  if (wildcard_out)
-+    *wildcard_out = NULL;
-   
-+  name_labels = count_labels(name); /* For 4035 5.3.2 check */
-+
-   /* Sort RRset records into canonical order. 
-      Note that at this point keyname and daemon->workspacename buffs are
-      unused, and used as workspace by the sort. */
-@@ -828,44 +879,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       algo = *p++;
-       labels = *p++;
-       GETLONG(orig_ttl, p);
--      GETLONG(sig_expiration, p);
--      GETLONG(sig_inception, p);
-+      p += 8; /* sig_expiration, sig_inception already checked */
-       GETSHORT(key_tag, p);
-       
-       if (!extract_name(header, plen, &p, keyname, 1, 0))
- 	return STAT_BOGUS;
- 
--      /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
--	 the name of the zone containing the RRset. We can't tell that
--	 for certain, but we can check that  the RRset name is equal to
--	 or encloses the signers name, which should be enough to stop 
--	 an attacker using signatures made with the key of an unrelated 
--	 zone he controls. Note that the root key is always allowed. */
--      if (*keyname != 0)
--	{
--	  int failed = 0;
--	  
--	  for (name_start = name; !hostname_isequal(name_start, keyname); )
--	    if ((name_start = strchr(name_start, '.')))
--	      name_start++; /* chop a label off and try again */
--	    else
--	      {
--		failed = 1;
--		break;
--	      }
--
--	  /* Bad sig, try another */
--	  if (failed)
--	    continue;
--	}
--      
--      /* Other 5.3.1 checks */
--      if (!check_date_range(sig_inception, sig_expiration) ||
--	  labels > name_labels ||
--	  !(hash = hash_find(algo_digest_name(algo))) ||
-+      if (!(hash = hash_find(algo_digest_name(algo))) ||
- 	  !hash_init(hash, &ctx, &digest))
- 	continue;
--	
-+      
-       /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
-       if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
- 	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.
-    Put all DNSKEYs in the answer which are valid into the cache.
-    return codes:
--         STAT_SECURE   At least one valid DNSKEY found and in cache.
--	 STAT_BOGUS    No DNSKEYs found, which  can be validated with DS,
--	               or self-sign for DNSKEY RRset is not valid, bad packet.
--	 STAT_NEED_DS  DS records to validate a key not found, name in keyname 
-+         STAT_OK           Done, key(s) in cache.
-+	 STAT_BOGUS        No DNSKEYs found, which  can be validated with DS,
-+	                   or self-sign for DNSKEY RRset is not valid, bad packet.
-+	 STAT_NEED_DS      DS records to validate a key not found, name in keyname 
-+	 STAT_NEED_DNSKEY  DNSKEY records to validate a key not found, name in keyname 
- */
- 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
-       return STAT_NEED_DS;
-     }
-   
--  /* If we've cached that DS provably doesn't exist, result must be INSECURE */
--  if (crecp->flags & F_NEG)
--    return STAT_INSECURE_DS;
--  
--  /* 4035 5.2 
--     If the validator does not support any of the algorithms listed in an
--     authenticated DS RRset, then the resolver has no supported
--     authentication path leading from the parent to the child.  The
--     resolver should treat this case as it would the case of an
--     authenticated NSEC RRset proving that no DS RRset exists,  */
--  for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
--    if (hash_find(ds_digest_name(recp1->addr.ds.digest)))
--      break;
--  
--  if (!recp1)
--    return STAT_INSECURE_DS;
--
-   /* NOTE, we need to find ONE DNSKEY which matches the DS */
-   for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--) 
-     {
-@@ -1070,7 +1077,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 	  void *ctx;
- 	  unsigned char *digest, *ds_digest;
- 	  const struct nettle_hash *hash;
--	  
-+	  int sigcnt, rrcnt;
-+
- 	  if (recp1->addr.ds.algo == algo && 
- 	      recp1->addr.ds.keytag == keytag &&
- 	      recp1->uid == (unsigned int)class &&
-@@ -1088,10 +1096,14 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 	      
- 	      from_wire(name);
- 	      
--	      if (recp1->addr.ds.keylen == (int)hash->digest_size &&
-+	      if (!(recp1->flags & F_NEG) &&
-+		  recp1->addr.ds.keylen == (int)hash->digest_size &&
- 		  (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
- 		  memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
--		  validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
-+		  explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
-+		  sigcnt != 0 && rrcnt != 0 &&
-+		  validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname, 
-+				 NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
- 		{
- 		  valid = 1;
- 		  break;
-@@ -1112,7 +1124,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 	{
- 	  /* Ensure we have type, class  TTL and length */
- 	  if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
--	    return STAT_INSECURE; /* bad packet */
-+	    return STAT_BOGUS; /* bad packet */
- 	  
- 	  GETSHORT(qtype, p); 
- 	  GETSHORT(qclass, p);
-@@ -1198,7 +1210,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
-       
-       /* commit cache insert. */
-       cache_end_insert();
--      return STAT_SECURE;
-+      return STAT_OK;
-     }
- 
-   log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
-@@ -1207,12 +1219,14 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 
- /* The DNS packet is expected to contain the answer to a DS query
-    Put all DSs in the answer which are valid into the cache.
-+   Also handles replies which prove that there's no DS at this location, 
-+   either because the zone is unsigned or this isn't a zone cut. These are
-+   cached too.
-    return codes:
--   STAT_SECURE      At least one valid DS found and in cache.
--   STAT_NO_DS       It's proved there's no DS here.
--   STAT_NO_NS       It's proved there's no DS _or_ NS here.
-+   STAT_OK          At least one valid DS found and in cache.
-    STAT_BOGUS       no DS in reply or not signed, fails validation, bad packet.
-    STAT_NEED_KEY    DNSKEY records to validate a DS not found, name in keyname
-+   STAT_NEED_DS     DS record needed.
- */
- 
- 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
-   if (qtype != T_DS || qclass != class)
-     val = STAT_BOGUS;
-   else
--    val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, &neganswer, &nons);
-+    val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
-   /* Note dnssec_validate_reply() will have cached positive answers */
-   
-   if (val == STAT_INSECURE)
-@@ -1242,22 +1256,21 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-   
-   if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
-     val = STAT_BOGUS;
--   
--  /* If we return STAT_NO_SIG, name contains the name of the DS query */
--  if (val == STAT_NO_SIG)
--    return val;
-   
-   /* If the key needed to validate the DS is on the same domain as the DS, we'll
-      loop getting nowhere. Stop that now. This can happen of the DS answer comes
-      from the DS's zone, and not the parent zone. */
--  if (val == STAT_BOGUS ||  (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-+  if (val == STAT_BOGUS || (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-     {
-       log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
-       return STAT_BOGUS;
-     }
-+  
-+  if (val != STAT_SECURE)
-+    return val;
- 
-   /* By here, the answer is proved secure, and a positive answer has been cached. */
--  if (val == STAT_SECURE && neganswer)
-+  if (neganswer)
-     {
-       int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
-       unsigned long ttl, minttl = ULONG_MAX;
-@@ -1317,15 +1330,14 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
- 	  
- 	  cache_end_insert();  
- 	  
--	  log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no delegation" : "no DS");
-+	  log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
- 	}
--
--      return nons ? STAT_NO_NS : STAT_NO_DS; 
-     }
- 
--  return val;
-+  return STAT_OK;
- }
- 
-+
- /* 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
-   int mask = 0x80 >> (type & 0x07);
- 
-   if (nons)
--    *nons = 0;
-+    *nons = 1;
-   
-   /* Find NSEC record that proves name doesn't exist */
-   for (i = 0; i < nsec_count; i++)
-@@ -1480,9 +1492,22 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
- 	  /* rdlen is now length of type map, and p points to it */
- 	  
- 	  /* If we can prove that there's no NS record, return that information. */
--	  if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
--	    *nons = 1;
-+	  if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
-+	    *nons = 0;
- 	  
-+	  if (rdlen >= 2 && p[0] == 0)
-+	    {
-+	      /* A CNAME answer would also be valid, so if there's a CNAME is should 
-+		 have been returned. */
-+	      if ((p[2] & (0x80 >> T_CNAME)) != 0)
-+		return STAT_BOGUS;
-+	      
-+	      /* If the SOA bit is set for a DS record, then we have the
-+		 DS from the wrong side of the delegation. */
-+	      if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
-+		return STAT_BOGUS;
-+	    }
-+
- 	  while (rdlen >= 2)
- 	    {
- 	      if (!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,
- 				char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
- {
--  int i, hash_len, salt_len, base32_len, rdlen;
-+  int i, hash_len, salt_len, base32_len, rdlen, flags;
-   unsigned char *p, *psave;
- 
-   for (i = 0; i < nsec_count; i++)
-@@ -1599,7 +1624,9 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
- 	p += 8; /* class, type, TTL */
- 	GETSHORT(rdlen, p);
- 	psave = p;
--	p += 4; /* algo, flags, iterations */
-+	p++; /* algo */
-+	flags = *p++; /* flags */
-+	p += 2; /* iterations */
- 	salt_len = *p++; /* salt_len */
- 	p += salt_len; /* salt */
- 	hash_len = *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
- 		  return 0;
- 		
- 		/* If we can prove that there's no NS record, return that information. */
--		if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
--		  *nons = 1;
-+		if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
-+		  *nons = 0;
- 		
-+		if (rdlen >= 2 && p[0] == 0)
-+		  {
-+		    /* A CNAME answer would also be valid, so if there's a CNAME is should 
-+		       have been returned. */
-+		    if ((p[2] & (0x80 >> T_CNAME)) != 0)
-+		      return 0;
-+		    
-+		    /* If the SOA bit is set for a DS record, then we have the
-+		       DS from the wrong side of the delegation. */
-+		    if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
-+		      return 0;
-+		  }
-+
- 		while (rdlen >= 2)
- 		  {
- 		    if (p[0] == type >> 8)
- 		      {
- 			/* Does the NSEC3 say our type exists? */
- 			if (offset < p[1] && (p[offset+2] & mask) != 0)
--			  return STAT_BOGUS;
-+			  return 0;
- 			
- 			break; /* finshed checking */
- 		      }
-@@ -1643,7 +1683,7 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
- 		    rdlen -= p[1];
- 		    p +=  p[1];
- 		  }
--
-+		
- 		return 1;
- 	      }
- 	    else if (rc < 0)
-@@ -1651,16 +1691,27 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
- 		/* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
- 		   wrap around case, name-hash falls between NSEC3 name-hash and end */
- 		if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
--		  return 1;
-+		  {
-+		    if ((flags & 0x01) && nons) /* opt out */
-+		      *nons = 0;
-+
-+		    return 1;
-+		  }
- 	      }
- 	    else 
- 	      {
- 		/* wrap around case, name falls between start and next domain name */
- 		if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
--		  return 1;
-+		  {
-+		    if ((flags & 0x01) && nons) /* opt out */
-+		      *nons = 0;
-+
-+		    return 1;
-+		  }
- 	      }
- 	  }
-       }
-+
-   return 0;
- }
- 
-@@ -1673,7 +1724,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   char *closest_encloser, *next_closest, *wildcard;
-   
-   if (nons)
--    *nons = 0;
-+    *nons = 1;
-   
-   /* Look though the NSEC3 records to find the first one with 
-      an algorithm we support (currently only algo == 1).
-@@ -1813,16 +1864,81 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   
-   return STAT_SECURE;
- }
--    
--/* 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.
-+   returns:
-+   STAT_SECURE zone is signed.
-+   STAT_INSECURE zone proved unsigned.
-+   STAT_NEED_DS require DS record of name returned in keyname.
-+   
-+   name returned unaltered.
-+*/
-+static int zone_status(char *name, int class, char *keyname, time_t now)
-+{
-+  int name_start = strlen(name);
-+  struct crec *crecp;
-+  char *p;
-+  
-+  while (1)
-+    {
-+      strcpy(keyname, &name[name_start]);
-+      
-+      if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
-+	return STAT_NEED_DS;
-+      else
-+	do 
-+	  {
-+	    if (crecp->uid == (unsigned int)class)
-+	      {
-+		/* F_DNSSECOK misused in DS cache records to non-existance of NS record.
-+		   F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
-+		   but that's because there's no NS record either, ie this isn't the start
-+		   of a zone. We only prove that the DNS tree below a node is unsigned when
-+		   we prove that we're at a zone cut AND there's no DS record.
-+		*/	  
-+		if (crecp->flags & F_NEG)
-+		  {
-+		    if (crecp->flags & F_DNSSECOK)
-+		      return STAT_INSECURE; /* proved no DS here */
-+		  }
-+		else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
-+		  return STAT_INSECURE; /* algo we can't use - insecure */
-+	      }
-+	  }
-+	while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
-+      
-+      if (name_start == 0)
-+	break;
-+
-+      for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
-+      
-+      if (p != name)
-+        p++;
-+      
-+      name_start = p - name;
-+    } 
-+
-+  return STAT_SECURE;
-+}
-+       
-+/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) 
-+   Return code:
-+   STAT_SECURE   if it validates.
-+   STAT_INSECURE at least one RRset not validated, because in unsigned zone.
-+   STAT_BOGUS    signature is wrong, bad packet, no validation where there should be.
-+   STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
-+   STAT_NEED_DS  need DS to complete validation (name is returned in keyname) 
-+*/
- 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 *class, int check_unsigned, int *neganswer, int *nons)
- {
--  unsigned char *ans_start, *qname, *p1, *p2, **nsecs;
--  int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype;
--  int i, j, rc, nsec_count, cname_count = CNAME_CHAIN;
--  int nsec_type = 0, have_answer = 0;
-+  static unsigned char **targets = NULL;
-+  static int target_sz = 0;
-+
-+  unsigned char *ans_start, *p1, *p2, **nsecs;
-+  int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
-+  int i, j, rc, nsec_count;
-+  int nsec_type;
- 
-   if (neganswer)
-     *neganswer = 0;
-@@ -1833,70 +1949,51 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-   if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
-     return STAT_INSECURE;
- 
--  qname = p1 = (unsigned char *)(header+1);
-+  p1 = (unsigned char *)(header+1);
-   
-+   /* Find all the targets we're looking for answers to.
-+     The zeroth array element is for the query, subsequent ones
-+     for CNAME targets, unless the query is for a CNAME. */
-+
-+  if (!expand_workspace(&targets, &target_sz, 0))
-+    return STAT_BOGUS;
-+  
-+  targets[0] = p1;
-+  targetidx = 1;
-+   
-   if (!extract_name(header, plen, &p1, name, 1, 4))
-     return STAT_BOGUS;
--
-+  
-   GETSHORT(qtype, p1);
-   GETSHORT(qclass, p1);
-   ans_start = p1;
--
--  if (qtype == T_ANY)
--    have_answer = 1;
-  
--  /* Can't validate an RRISG query */
-+  /* Can't validate an RRSIG query */
-   if (qtype == T_RRSIG)
-     return STAT_INSECURE;
-- 
-- cname_loop:
--  for (j = ntohs(header->ancount); j != 0; j--) 
--    {
--      /* leave pointer to missing name in qname */
--           
--      if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
--	return STAT_BOGUS; /* bad packet */
--      
--      GETSHORT(type2, p1); 
--      GETSHORT(class2, p1);
--      p1 += 4; /* TTL */
--      GETSHORT(rdlen2, p1);
--
--      if (rc == 1 && qclass == class2)
--	{
--	  /* Do we have an answer for the question? */
--	  if (type2 == qtype)
--	    {
--	      have_answer = 1;
--	      break;
--	    }
--	  else if (type2 == T_CNAME)
--	    {
--	      qname = p1;
--	      
--	      /* looped CNAMES */
--	      if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
--		return STAT_BOGUS;
--	       
--	      p1 = ans_start;
--	      goto cname_loop;
--	    }
--	} 
--
--      if (!ADD_RDLEN(header, p1, plen, rdlen2))
--	return STAT_BOGUS;
--    }
--   
--  if (neganswer && !have_answer)
--    *neganswer = 1;
-   
--  /* No data, therefore no sigs */
--  if (ntohs(header->ancount) + ntohs(header->nscount) == 0)
--    {
--      *keyname = 0;
--      return STAT_NO_SIG;
--    }
--
-+  if (qtype != T_CNAME)
-+    for (j = ntohs(header->ancount); j != 0; j--) 
-+      {
-+	if (!(p1 = skip_name(p1, header, plen, 10)))
-+	  return STAT_BOGUS; /* bad packet */
-+	
-+	GETSHORT(type2, p1); 
-+	p1 += 6; /* class, TTL */
-+	GETSHORT(rdlen2, p1);  
-+	
-+	if (type2 == T_CNAME)
-+	  {
-+	    if (!expand_workspace(&targets, &target_sz, targetidx))
-+	      return STAT_BOGUS;
-+	    
-+	    targets[targetidx++] = p1; /* pointer to target name */
-+	  }
-+	
-+	if (!ADD_RDLEN(header, p1, plen, rdlen2))
-+	  return STAT_BOGUS;
-+      }
-+  
-   for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
-     {
-       if (!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
- 	  /* Not done, validate now */
- 	  if (j == i)
- 	    {
--	      int ttl, keytag, algo, digest, type_covered;
-+	      int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
- 	      unsigned char *psave;
- 	      struct all_addr a;
- 	      struct blockdata *key;
-@@ -1939,143 +2036,186 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 	      char *wildname;
- 	      int have_wildcard = 0;
- 
--	      rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
--	      
--	      if (rc == STAT_SECURE_WILDCARD)
--		{
--		  have_wildcard = 1;
--
--		  /* An attacker replay a wildcard answer with a different
--		     answer and overlay a genuine RR. To prove this
--		     hasn't happened, the answer must prove that
--		     the gennuine record doesn't exist. Check that here. */
--		  if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
--		    return STAT_BOGUS; /* No NSECs or bad packet */
--		  
--		  if (nsec_type == T_NSEC)
--		    rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
--		  else
--		    rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
--						   keyname, name, type1, wildname, NULL);
--		  
--		  if (rc != STAT_SECURE)
--		    return rc;
--		} 
--	      else if (rc != STAT_SECURE)
--		{
--		  if (class)
--		    *class = class1; /* Class for DS or DNSKEY */
-+	      if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
-+		return STAT_BOGUS;
- 
--		  if (rc == STAT_NO_SIG)
-+	      /* No signatures for RRset. We can be configured to assume this is OK and return a INSECURE result. */
-+	      if (sigcnt == 0)
-+		{
-+		  if (check_unsigned)
- 		    {
--		      /* If we dropped off the end of a CNAME chain, return
--			 STAT_NO_SIG and the last name is keyname. This is used for proving non-existence
--			 if DS records in CNAME chains. */
--		      if (cname_count == CNAME_CHAIN || i < ntohs(header->ancount)) 
--			/* No CNAME chain, or no sig in answer section, return empty name. */
--			*keyname = 0;
--		      else if (!extract_name(header, plen, &qname, keyname, 1, 0))
--			return STAT_BOGUS;
-+		      rc = zone_status(name, class1, keyname, now);
-+		      if (rc == STAT_SECURE)
-+			rc = STAT_BOGUS;
-+		       if (class)
-+			 *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
- 		    }
-- 
-+		  else 
-+		    rc = STAT_INSECURE; 
-+		  
- 		  return rc;
- 		}
- 	      
--	      /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
--	      cache_start_insert();
-+	      /* explore_rrset() gives us key name from sigs in keyname.
-+		 Can't overwrite name here. */
-+	      strcpy(daemon->workspacename, keyname);
-+	      rc = zone_status(daemon->workspacename, class1, keyname, now);
-+	      if (rc != STAT_SECURE)
-+		{
-+		  /* Zone is insecure, don't need to validate RRset */
-+		  if (class)
-+		    *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-+		  return rc;
-+		} 
-+	      
-+	      rc = validate_rrset(now, header, plen, class1, type1, sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
- 	      
--	      for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
-+	      if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
- 		{
--		  if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
--		    return STAT_BOGUS; /* bad packet */
-+		  if (class)
-+		    *class = class1; /* Class for DS or DNSKEY */
-+		  return rc;
-+		} 
-+	      else 
-+		{
-+		  /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
-+		 
-+		  /* Note if we've validated either the answer to the question
-+		     or the target of a CNAME. Any not noted will need NSEC or
-+		     to be in unsigned space. */
-+
-+		  for (j = 0; j <targetidx; j++)
-+		    if ((p2 = targets[j]))
-+		      {
-+			if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
-+			  return STAT_BOGUS; /* bad packet */
-+			
-+			if (class1 == qclass && rc == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
-+			  targets[j] = NULL;
-+		      }
-+			    
-+		  if (rc == STAT_SECURE_WILDCARD)
-+		    {
-+		      have_wildcard = 1;
- 		      
--		  GETSHORT(type2, p2);
--		  GETSHORT(class2, p2);
--		  GETLONG(ttl, p2);
--		  GETSHORT(rdlen2, p2);
--		       
--		  if (!CHECK_LEN(header, p2, plen, rdlen2))
--		    return STAT_BOGUS; /* bad packet */
--		  
--		  if (class2 == class1 && rc == 1)
--		    { 
--		      psave = p2;
-+		      /* An attacker replay a wildcard answer with a different
-+			 answer and overlay a genuine RR. To prove this
-+			 hasn't happened, the answer must prove that
-+			 the gennuine record doesn't exist. Check that here. */
-+		      if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
-+			return STAT_BOGUS; /* No NSECs or bad packet */
-+		      
-+		      /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. Since the check
-+			 below returns either SECURE or BOGUS, that's not a problem. If the RRsets later fail
-+			 we'll return BOGUS then. */
- 
--		      if (type1 == T_DS && type2 == T_DS)
--			{
--			  if (rdlen2 < 4)
--			    return STAT_BOGUS; /* bad packet */
--			  
--			  GETSHORT(keytag, p2);
--			  algo = *p2++;
--			  digest = *p2++;
--			  
--			  /* Cache needs to known class for DNSSEC stuff */
--			  a.addr.dnssec.class = class2;
--			  
--			  if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
--			    {
--			      if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
--				blockdata_free(key);
--			      else
--				{
--				  a.addr.keytag = keytag;
--				  log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
--				  crecp->addr.ds.digest = digest;
--				  crecp->addr.ds.keydata = key;
--				  crecp->addr.ds.algo = algo;
--				  crecp->addr.ds.keytag = keytag;
--				  crecp->addr.ds.keylen = rdlen2 - 4; 
--				} 
--			    }
--			}
--		      else if (type2 == T_RRSIG)
--			{
--			  if (rdlen2 < 18)
--			    return STAT_BOGUS; /* bad packet */
-+		      if (nsec_type == T_NSEC)
-+			rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
-+		      else
-+			rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
-+						       keyname, name, type1, wildname, NULL);
-+		      
-+		      if (rc == STAT_BOGUS)
-+			return rc;
-+		    } 
-+		  
-+		  /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
-+		  /* Also note if the RRset is the answer to the question, or the target of a CNAME */
-+		  cache_start_insert();
-+		  
-+		  for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
-+		    {
-+		      if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
-+			return STAT_BOGUS; /* bad packet */
-+		      
-+		      GETSHORT(type2, p2);
-+		      GETSHORT(class2, p2);
-+		      GETLONG(ttl, p2);
-+		      GETSHORT(rdlen2, p2);
-+		      
-+		      if (!CHECK_LEN(header, p2, plen, rdlen2))
-+			return STAT_BOGUS; /* bad packet */
-+		      
-+		      if (class2 == class1 && rc == 1)
-+			{ 
-+			  psave = p2;
- 			  
--			  GETSHORT(type_covered, p2);
--
--			  if (type_covered == type1 && 
--			      (type_covered == T_A || type_covered == T_AAAA ||
--			       type_covered == T_CNAME || type_covered == T_DS || 
--			       type_covered == T_DNSKEY || type_covered == T_PTR)) 
-+			  if (type1 == T_DS && type2 == T_DS)
- 			    {
--			      a.addr.dnssec.type = type_covered;
--			      a.addr.dnssec.class = class1;
-+			      if (rdlen2 < 4)
-+				return STAT_BOGUS; /* bad packet */
- 			      
--			      algo = *p2++;
--			      p2 += 13; /* labels, orig_ttl, expiration, inception */
- 			      GETSHORT(keytag, p2);
-+			      algo = *p2++;
-+			      digest = *p2++;
-+			      
-+			      /* Cache needs to known class for DNSSEC stuff */
-+			      a.addr.dnssec.class = class2;
- 			      
--			      /* We don't cache sigs for wildcard answers, because to reproduce the
--				 answer from the cache will require one or more NSEC/NSEC3 records 
--				 which we don't cache. The lack of the RRSIG ensures that a query for
--				 this RRset asking for a secure answer will always be forwarded. */
--			      if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
-+			      if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
- 				{
--				  if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
-+				  if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
- 				    blockdata_free(key);
- 				  else
- 				    {
--				      crecp->addr.sig.keydata = key;
--				      crecp->addr.sig.keylen = rdlen2;
--				      crecp->addr.sig.keytag = keytag;
--				      crecp->addr.sig.type_covered = type_covered;
--				      crecp->addr.sig.algo = algo;
-+				      a.addr.keytag = keytag;
-+				      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+				      crecp->addr.ds.digest = digest;
-+				      crecp->addr.ds.keydata = key;
-+				      crecp->addr.ds.algo = algo;
-+				      crecp->addr.ds.keytag = keytag;
-+				      crecp->addr.ds.keylen = rdlen2 - 4; 
-+				    } 
-+				}
-+			    }
-+			  else if (type2 == T_RRSIG)
-+			    {
-+			      if (rdlen2 < 18)
-+				return STAT_BOGUS; /* bad packet */
-+			      
-+			      GETSHORT(type_covered, p2);
-+			      
-+			      if (type_covered == type1 && 
-+				  (type_covered == T_A || type_covered == T_AAAA ||
-+				   type_covered == T_CNAME || type_covered == T_DS || 
-+				   type_covered == T_DNSKEY || type_covered == T_PTR)) 
-+				{
-+				  a.addr.dnssec.type = type_covered;
-+				  a.addr.dnssec.class = class1;
-+				  
-+				  algo = *p2++;
-+				  p2 += 13; /* labels, orig_ttl, expiration, inception */
-+				  GETSHORT(keytag, p2);
-+				  
-+				  /* We don't cache sigs for wildcard answers, because to reproduce the
-+				     answer from the cache will require one or more NSEC/NSEC3 records 
-+				     which we don't cache. The lack of the RRSIG ensures that a query for
-+				     this RRset asking for a secure answer will always be forwarded. */
-+				  if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
-+				    {
-+				      if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
-+					blockdata_free(key);
-+				      else
-+					{
-+					  crecp->addr.sig.keydata = key;
-+					  crecp->addr.sig.keylen = rdlen2;
-+					  crecp->addr.sig.keytag = keytag;
-+					  crecp->addr.sig.type_covered = type_covered;
-+					  crecp->addr.sig.algo = algo;
-+					}
- 				    }
- 				}
- 			    }
-+			  
-+			  p2 = psave;
- 			}
- 		      
--		      p2 = psave;
-+		      if (!ADD_RDLEN(header, p2, plen, rdlen2))
-+			return STAT_BOGUS; /* bad packet */
- 		    }
- 		  
--		  if (!ADD_RDLEN(header, p2, plen, rdlen2))
--		    return STAT_BOGUS; /* bad packet */
-+		  cache_end_insert();
- 		}
--		  
--	      cache_end_insert();
- 	    }
- 	}
- 
-@@ -2083,143 +2223,49 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 	return STAT_BOGUS;
-     }
- 
--  /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
--  if (have_answer)
--    return STAT_SECURE;
--     
--  /* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
--  /* First marshall the NSEC records, if we've not done it previously */
--  if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
--    {
--      /* No NSEC records. If we dropped off the end of a CNAME chain, return
--	 STAT_NO_SIG and the last name is keyname. This is used for proving non-existence
--	 if DS records in CNAME chains. */
--      if (cname_count == CNAME_CHAIN) /* No CNAME chain, return empty name. */
--	*keyname = 0;
--      else if (!extract_name(header, plen, &qname, keyname, 1, 0))
--	return STAT_BOGUS;
--      return STAT_NO_SIG; /* No NSECs, this is probably a dangling CNAME pointing into
--			     an unsigned zone. Return STAT_NO_SIG to cause this to be proved. */
--    }
--   
--  /* Get name of missing answer */
--  if (!extract_name(header, plen, &qname, name, 1, 0))
--    return STAT_BOGUS;
--  
--  if (nsec_type == T_NSEC)
--    return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
--  else
--    return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
--}
--
--/* Chase the CNAME chain in the packet until the first record which _doesn't validate.
--   Needed for proving answer in unsigned space.
--   Return STAT_NEED_* 
--          STAT_BOGUS - error
--          STAT_INSECURE - name of first non-secure record in name 
--*/
--int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
--{
--  unsigned char *p = (unsigned char *)(header+1);
--  int type, class, qclass, rdlen, j, rc;
--  int cname_count = CNAME_CHAIN;
--  char *wildname;
--
--  /* Get question */
--  if (!extract_name(header, plen, &p, name, 1, 4))
--    return STAT_BOGUS;
--  
--  p +=2; /* type */
--  GETSHORT(qclass, p);
--
--  while (1)
--    {
--      for (j = ntohs(header->ancount); j != 0; j--) 
--	{
--	  if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
--	    return STAT_BOGUS; /* bad packet */
--	  
--	  GETSHORT(type, p); 
--	  GETSHORT(class, p);
--	  p += 4; /* TTL */
--	  GETSHORT(rdlen, p);
--
--	  /* Not target, loop */
--	  if (rc == 2 || qclass != class)
--	    {
--	      if (!ADD_RDLEN(header, p, plen, rdlen))
--		return STAT_BOGUS;
--	      continue;
--	    }
--	  
--	  /* Got to end of CNAME chain. */
--	  if (type != T_CNAME)
--	    return STAT_INSECURE;
--	  
--	  /* validate CNAME chain, return if insecure or need more data */
--	  rc = validate_rrset(now, header, plen, class, type, name, keyname, &wildname, NULL, 0, 0, 0);
--	   
--	  if (rc == STAT_SECURE_WILDCARD)
--	    {
--	      int nsec_type, nsec_count, i;
--	      unsigned char **nsecs;
--
--	      /* An attacker can replay a wildcard answer with a different
--		 answer and overlay a genuine RR. To prove this
--		 hasn't happened, the answer must prove that
--		 the genuine record doesn't exist. Check that here. */
--	      if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class)))
--		return STAT_BOGUS; /* No NSECs or bad packet */
--	      
--	      /* Note that we're called here because something didn't validate in validate_reply,
--		 so we can't assume that any NSEC records have been validated. We do them by steam here */
--
--	      for (i = 0; i < nsec_count; i++)
--		{
--		  unsigned char *p1 = nsecs[i];
--		  
--		  if (!extract_name(header, plen, &p1, daemon->workspacename, 1, 0))
--		    return STAT_BOGUS;
--
--		  rc = validate_rrset(now, header, plen, class, nsec_type, daemon->workspacename, keyname, NULL, NULL, 0, 0, 0);
-+  /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
-+  for (j = 0; j <targetidx; j++)
-+    if ((p2 = targets[j]))
-+      {
-+	if (neganswer)
-+	  *neganswer = 1;
- 
--		  /* NSECs can't be wildcards. */
--		  if (rc == STAT_SECURE_WILDCARD)
--		    rc = STAT_BOGUS;
-+	if (!extract_name(header, plen, &p2, name, 1, 10))
-+	  return STAT_BOGUS; /* bad packet */
-+	    
-+	/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
- 
--		  if (rc != STAT_SECURE)
-+	/* For anything other than a DS record, this situation is OK if either
-+	   the answer is in an unsigned zone, or there's a NSEC records. */
-+	if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
-+	  {
-+	    /* Empty DS without NSECS */
-+	    if (qtype == T_DS)
-+	      return STAT_BOGUS;
-+	    else
-+	      {
-+		rc = zone_status(name, qclass, keyname, now);
-+		if (rc != STAT_SECURE)
-+		  {
-+		    if (class)
-+		      *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
- 		    return rc;
--		}
--
--	      if (nsec_type == T_NSEC)
--		rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type, NULL);
--	      else
--		rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
--					       keyname, name, type, wildname, NULL);
--	      
--	      if (rc != STAT_SECURE)
--		return rc;
--	    }
--	  
--	  if (rc != STAT_SECURE)
--	    {
--	      if (rc == STAT_NO_SIG)
--		rc = STAT_INSECURE;
--	      return rc;
--	    }
-+		  } 
-+		
-+		return STAT_BOGUS; /* signed zone, no NSECs */
-+	      }
-+	  }
- 
--	  /* Loop down CNAME chain/ */
--	  if (!cname_count-- || 
--	      !extract_name(header, plen, &p, name, 1, 0) ||
--	      !(p = skip_questions(header, plen)))
--	    return STAT_BOGUS;
--	  
--	  break;
--	}
-+	  if (nsec_type == T_NSEC)
-+	  rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
-+	else
-+	  rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
- 
--      /* End of CNAME chain */
--      return STAT_INSECURE;	
--    }
-+	if (rc != STAT_SECURE)
-+	  return rc;
-+      }
-+  
-+  return STAT_SECURE;
- }
- 
- 
-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);
- 
--#ifdef HAVE_DNSSEC
--static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, 
--			   int 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, 
--			   char *name, char *keyname);
--#endif
--
--
- /* Send a UDP packet with its source address set as "source" 
-    unless nowild is true, when we just send it with the kernel default */
- int send_from(int fd, int nowild, char *packet, size_t len, 
-@@ -825,236 +816,142 @@ void reply_query(int fd, int family, time_t now)
- #ifdef HAVE_DNSSEC
-       if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
- 	{
--	  int status;
-+	  int status = 0;
- 
- 	  /* We've had a reply already, which we're validating. Ignore this duplicate */
- 	  if (forward->blocking_query)
- 	    return;
--
--	  if (header->hb3 & HB3_TC)
--	    {
--	      /* Truncated answer can't be validated.
-+	  
-+	   /* Truncated answer can't be validated.
- 		 If this is an answer to a DNSSEC-generated query, we still
- 		 need to get the client to retry over TCP, so return
- 		 an answer with the TC bit set, even if the actual answer fits.
- 	      */
--	      status = STAT_TRUNCATED;
--	    }
--	  else if (forward->flags & FREC_DNSKEY_QUERY)
--	    status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--	  else if (forward->flags & FREC_DS_QUERY)
--	    {
--	      status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--	      /* Provably no DS, everything below is insecure, even if signatures are offered */
--	      if (status == STAT_NO_DS)
--		/* We only cache sigs when we've validated a reply.
--		   Avoid caching a reply with sigs if there's a vaildated break in the 
--		   DS chain, so we don't return replies from cache missing sigs. */
--              	status = STAT_INSECURE_DS;
--	      else if (status == STAT_NO_SIG)
--                {
--                  if (option_bool(OPT_DNSSEC_NO_SIGN))
--                    {
--		      status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
--		      if (status == STAT_INSECURE)
--			status = STAT_INSECURE_DS;
--		    }
--		  else
--		    status = STAT_INSECURE_DS;
--		}
--              else if (status == STAT_NO_NS)
--		status = STAT_BOGUS;
--	    }
--	  else if (forward->flags & FREC_CHECK_NOSIGN)
--	    {
--	      status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--	      if (status != STAT_NEED_KEY)
--		status = do_check_sign(forward, status, now, daemon->namebuff, daemon->keyname);
--	    }
--	  else
-+	  if (header->hb3 & HB3_TC)
-+	    status = STAT_TRUNCATED;
-+	  
-+	  while (1)
- 	    {
--	      status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);
--	      if (status == STAT_NO_SIG)
-+	      /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
-+		 would invite infinite loops, since the answers to DNSKEY and DS queries
-+		 will not be cached, so they'll be repeated. */
-+	      if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
- 		{
--		  if (option_bool(OPT_DNSSEC_NO_SIGN))
--		    status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
-+		  if (forward->flags & FREC_DNSKEY_QUERY)
-+		    status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
-+		  else if (forward->flags & FREC_DS_QUERY)
-+		    status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
- 		  else
--		    status = STAT_INSECURE;
-+		    status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, 
-+						   option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
- 		}
--	    }
--	  /* Can't validate, as we're missing key data. Put this
--	     answer aside, whilst we get that. */     
--	  if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG || status == STAT_NEED_KEY)
--	    {
--	      struct frec *new, *orig;
--	      
--	      /* Free any saved query */
--	      if (forward->stash)
--		blockdata_free(forward->stash);
--	      
--	      /* Now save reply pending receipt of key data */
--	      if (!(forward->stash = blockdata_alloc((char *)header, n)))
--		return;
--	      forward->stash_len = n;
- 	      
--	    anotherkey:	      
--	      /* Find the original query that started it all.... */
--	      for (orig = forward; orig->dependent; orig = orig->dependent);
--
--	      if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
--		status = STAT_INSECURE;
--	      else
-+	      /* Can't validate, as we're missing key data. Put this
-+		 answer aside, whilst we get that. */     
-+	      if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
- 		{
--		  int fd;
--		  struct frec *next = new->next;
--		  *new = *forward; /* copy everything, then overwrite */
--		  new->next = next;
--		  new->blocking_query = NULL;
--		  new->sentto = server;
--		  new->rfd4 = NULL;
--		  new->orig_domain = NULL;
--#ifdef HAVE_IPV6
--		  new->rfd6 = NULL;
--#endif
--		  new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_CHECK_NOSIGN);
-+		  struct frec *new, *orig;
- 		  
--		  new->dependent = forward; /* to find query awaiting new one. */
--		  forward->blocking_query = new; /* for garbage cleaning */
--		  /* validate routines leave name of required record in daemon->keyname */
--		  if (status == STAT_NEED_KEY)
--		    {
--		      new->flags |= FREC_DNSKEY_QUERY; 
--		      nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
--						 daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
--		    }
--		  else 
--		    {
--		      if (status == STAT_NEED_DS_NEG)
--			new->flags |= FREC_CHECK_NOSIGN;
--		      else
--			new->flags |= FREC_DS_QUERY;
--		      nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
--						 daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
--		    }
--		  if ((hash = hash_questions(header, nn, daemon->namebuff)))
--		    memcpy(new->hash, hash, HASH_SIZE);
--		  new->new_id = get_id();
--		  header->id = htons(new->new_id);
--		  /* Save query for retransmission */
--		  if (!(new->stash = blockdata_alloc((char *)header, nn)))
-+		  /* Free any saved query */
-+		  if (forward->stash)
-+		    blockdata_free(forward->stash);
-+		  
-+		  /* Now save reply pending receipt of key data */
-+		  if (!(forward->stash = blockdata_alloc((char *)header, n)))
- 		    return;
--		      
--		  new->stash_len = nn;
-+		  forward->stash_len = n;
- 		  
--		  /* Don't resend this. */
--		  daemon->srv_save = NULL;
-+		  /* Find the original query that started it all.... */
-+		  for (orig = forward; orig->dependent; orig = orig->dependent);
- 		  
--		  if (server->sfd)
--		    fd = server->sfd->fd;
-+		  if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
-+		    status = STAT_ABANDONED;
- 		  else
- 		    {
--		      fd = -1;
-+		      int fd;
-+		      struct frec *next = new->next;
-+		      *new = *forward; /* copy everything, then overwrite */
-+		      new->next = next;
-+		      new->blocking_query = NULL;
-+		      new->sentto = server;
-+		      new->rfd4 = NULL;
- #ifdef HAVE_IPV6
--		      if (server->addr.sa.sa_family == AF_INET6)
-+		      new->rfd6 = NULL;
-+#endif
-+		      new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
-+		      
-+		      new->dependent = forward; /* to find query awaiting new one. */
-+		      forward->blocking_query = new; /* for garbage cleaning */
-+		      /* validate routines leave name of required record in daemon->keyname */
-+		      if (status == STAT_NEED_KEY)
-+			{
-+			  new->flags |= FREC_DNSKEY_QUERY; 
-+			  nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
-+						     daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
-+			}
-+		      else 
- 			{
--			  if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
--			    fd = new->rfd6->fd;
-+			  new->flags |= FREC_DS_QUERY;
-+			  nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
-+						     daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
- 			}
-+		      if ((hash = hash_questions(header, nn, daemon->namebuff)))
-+			memcpy(new->hash, hash, HASH_SIZE);
-+		      new->new_id = get_id();
-+		      header->id = htons(new->new_id);
-+		      /* Save query for retransmission */
-+		      new->stash = blockdata_alloc((char *)header, nn);
-+		      new->stash_len = nn;
-+		      
-+		      /* Don't resend this. */
-+		      daemon->srv_save = NULL;
-+		      
-+		      if (server->sfd)
-+			fd = server->sfd->fd;
- 		      else
-+			{
-+			  fd = -1;
-+#ifdef HAVE_IPV6
-+			  if (server->addr.sa.sa_family == AF_INET6)
-+			    {
-+			      if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
-+				fd = new->rfd6->fd;
-+			    }
-+			  else
- #endif
-+			    {
-+			      if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
-+				fd = new->rfd4->fd;
-+			    }
-+			}
-+		      
-+		      if (fd != -1)
- 			{
--			  if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
--			    fd = new->rfd4->fd;
-+			  while (retry_send(sendto(fd, (char *)header, nn, 0, 
-+						   &server->addr.sa, 
-+						   sa_len(&server->addr)))); 
-+			  server->queries++;
- 			}
--		    }
--		  
--		  if (fd != -1)
--		    {
--		      while (retry_send(sendto(fd, (char *)header, nn, 0, 
--					       &server->addr.sa, 
--					       sa_len(&server->addr)))); 
--		      server->queries++;
--		    }
--		  
-+		    }		  
- 		  return;
- 		}
--	    }
- 	  
--	  /* Ok, we reached far enough up the chain-of-trust that we can validate something.
--	     Now wind back down, pulling back answers which wouldn't previously validate
--	     and validate them with the new data. Note that if an answer needs multiple
--	     keys to validate, we may find another key is needed, in which case we set off
--	     down another branch of the tree. Once we get to the original answer 
--	     (FREC_DNSSEC_QUERY not set) and it validates, return it to the original requestor. */
--	  while (forward->dependent)
--	    {
-+	      /* Validated original answer, all done. */
-+	      if (!forward->dependent)
-+		break;
-+	      
-+	      /* validated subsdiary query, (and cached result)
-+		 pop that and return to the previous query we were working on. */
- 	      struct frec *prev = forward->dependent;
- 	      free_frec(forward);
- 	      forward = prev;
- 	      forward->blocking_query = NULL; /* already gone */
- 	      blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
- 	      n = forward->stash_len;
--	      
--	      if (status == STAT_SECURE)
--		{
--		  if (forward->flags & FREC_DNSKEY_QUERY)
--		    status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--		  else if (forward->flags & FREC_DS_QUERY)
--		    {
--		      status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--		       /* Provably no DS, everything below is insecure, even if signatures are offered */
--		      if (status == STAT_NO_DS)
--			/* We only cache sigs when we've validated a reply.
--			   Avoid caching a reply with sigs if there's a vaildated break in the 
--			   DS chain, so we don't return replies from cache missing sigs. */
--			status = STAT_INSECURE_DS;
--		       else if (status == STAT_NO_SIG)
--			 {
--			   if (option_bool(OPT_DNSSEC_NO_SIGN))
--			     {
--			       status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname); 
--			       if (status == STAT_INSECURE)
--				 status = STAT_INSECURE_DS;
--			     }
--			   else
--			     status = STAT_INSECURE_DS;
--			 }
--		       else if (status == STAT_NO_NS)
--			 status = STAT_BOGUS;
--		    }
--		  else if (forward->flags & FREC_CHECK_NOSIGN)
--		    {
--		      status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
--		      if (status != STAT_NEED_KEY)
--			status = do_check_sign(forward, status, now, daemon->namebuff, daemon->keyname);
--		    }
--		  else
--		    {
--		      status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);	
--		      if (status == STAT_NO_SIG)
--			{
--			  if (option_bool(OPT_DNSSEC_NO_SIGN))
--			    status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
--			  else
--			    status = STAT_INSECURE;
--			}
--		    }
--	       
--		  if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG || status == STAT_NEED_KEY)
--		    goto anotherkey;
--		}
- 	    }
-+	
- 	  
- 	  no_cache_dnssec = 0;
--
--	  if (status == STAT_INSECURE_DS)
--	    {
--	      /* We only cache sigs when we've validated a reply.
--		 Avoid caching a reply with sigs if there's a vaildated break in the 
--		 DS chain, so we don't return replies from cache missing sigs. */
--	      status = STAT_INSECURE;
--	      no_cache_dnssec = 1;
--	    }
- 	  
- 	  if (status == STAT_TRUNCATED)
- 	    header->hb3 |= HB3_TC;
-@@ -1062,7 +959,7 @@ void reply_query(int fd, int family, time_t now)
- 	    {
- 	      char *result, *domain = "result";
- 	      
--	      if (forward->work_counter == 0)
-+	      if (status == STAT_ABANDONED)
- 		{
- 		  result = "ABANDONED";
- 		  status = STAT_BOGUS;
-@@ -1072,7 +969,7 @@ void reply_query(int fd, int family, time_t now)
- 	      
- 	      if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
- 		domain = daemon->namebuff;
--
-+	      
- 	      log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
- 	    }
- 	  
-@@ -1415,315 +1312,49 @@ void receive_query(struct listener *listen, time_t now)
- }
- 
- #ifdef HAVE_DNSSEC
--
--/* UDP: we've got an unsigned answer, return STAT_INSECURE if we can prove there's no DS
--   and therefore the answer shouldn't be signed, or STAT_BOGUS if it should be, or 
--   STAT_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, 
--			   char *name, char *keyname)
--{
--  int status = dnssec_chase_cname(now, header, plen, name, keyname);
--  
--  if (status != STAT_INSECURE)
--    return status;
--
--  /* Store the domain we're trying to check. */
--  forward->name_start = strlen(name);
--  forward->name_len = forward->name_start + 1;
--  if (!(forward->orig_domain = blockdata_alloc(name, forward->name_len)))
--    return STAT_BOGUS;
--  
--  return do_check_sign(forward, 0, now, name, keyname);
--}
-- 
--/* We either have a a reply (header non-NULL, or we need to start by looking in the cache */ 
--static int do_check_sign(struct frec *forward, int status, time_t now, char *name, char *keyname)
--{
--  /* get domain we're checking back from blockdata store, it's stored on the original query. */
--  while (forward->dependent && !forward->orig_domain)
--    forward = forward->dependent;
--
--  blockdata_retrieve(forward->orig_domain, forward->name_len, name);
--  
--  while (1)
--    {
--      char *p; 
--
--      if (status == 0)
--	{
--	  struct crec *crecp;
--
--	  /* Haven't received answer, see if in cache */
--	  if (!(crecp = cache_find_by_name(NULL, &name[forward->name_start], now, F_DS)))
--	    {
--	      /* put name of DS record we're missing into keyname */
--	      strcpy(keyname, &name[forward->name_start]);
--	      /* and wait for reply to arrive */
--	      return STAT_NEED_DS_NEG;
--	    }
--
--	  /* F_DNSSECOK misused in DS cache records to non-existance of NS record */ 
--	  if (!(crecp->flags & F_NEG))
--	    status = STAT_SECURE;
--	  else if (crecp->flags & F_DNSSECOK)
--	    status = STAT_NO_DS;
--	  else
--	    status = STAT_NO_NS;
--	}
--      
--      /* Have entered non-signed part of DNS tree. */ 
--      if (status == STAT_NO_DS)
--	return forward->dependent ? STAT_INSECURE_DS : STAT_INSECURE;
--
--      if (status == STAT_BOGUS)
--	return STAT_BOGUS;
--
--      if (status == STAT_NO_SIG && *keyname != 0)
--	{
--	  /* There is a validated CNAME chain that doesn't end in a DS record. Start 
--	     the search again in that domain. */
--	  blockdata_free(forward->orig_domain);
--	  forward->name_start = strlen(keyname);
--	  forward->name_len = forward->name_start + 1;
--	  if (!(forward->orig_domain = blockdata_alloc(keyname, forward->name_len)))
--	    return STAT_BOGUS;
--	  
--	  strcpy(name, keyname);
--	  status = 0; /* force to cache when we iterate. */
--	  continue;
--	}
--      
--      /* There's a proven DS record, or we're within a zone, where there doesn't need
--	 to be a DS record. Add a name and try again. 
--	 If we've already tried the whole name, then fail */
--
--      if (forward->name_start == 0)
--	return STAT_BOGUS;
--      
--      for (p = &name[forward->name_start-2]; (*p != '.') && (p != name); p--);
--      
--      if (p != name)
--	p++;
--      
--      forward->name_start = p - name;
--      status = 0; /* force to cache when we iterate. */
--    }
--}
--
--/* Move down from the root, until we find a signed non-existance of a DS, in which case
--   an unsigned answer is OK, or we find a signed DS, in which case there should be 
--   a signature, and the answer is BOGUS */
--static int  tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, size_t plen, int class, char *name, 
--					char *keyname, struct server *server, int *keycount)
--{
--  size_t m;
--  unsigned char *packet, *payload;
--  u16 *length;
--  int status, name_len;
--  struct blockdata *block;
--
--  char *name_start;
--
--  /* Get first insecure entry in CNAME chain */
--  status = tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, class, name, keyname, server, keycount);
--  if (status == STAT_BOGUS)
--    return STAT_BOGUS;
--  
--  if (!(packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16))))
--    return STAT_BOGUS;
--  
--  payload = &packet[2];
--  header = (struct dns_header *)payload;
--  length = (u16 *)packet;
--
--  /* Stash the name away, since the buffer will be trashed when we recurse */
--  name_len = strlen(name) + 1;
--  name_start = name + name_len - 1;
--  
--  if (!(block = blockdata_alloc(name, name_len)))
--    {
--      free(packet);
--      return STAT_BOGUS;
--    }
--
--  while (1)
--    {
--      unsigned char c1, c2;
--      struct crec *crecp;
--
--      if (--(*keycount) == 0)
--	{
--	  free(packet);
--	  blockdata_free(block);
--	  return STAT_BOGUS;    
--	}
--      
--      while ((crecp = cache_find_by_name(NULL, name_start, now, F_DS)))
--	{      
--	  if ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))
--	    {
--	      /* Found a secure denial of DS - delegation is indeed insecure */
--	      free(packet);
--	      blockdata_free(block);
--	      return STAT_INSECURE;
--	    }
--      
--	  /* Here, either there's a secure DS, or no NS and no DS, and therefore no delegation.
--	     Add another label and continue. */
-- 
--	  if (name_start == name)
--	    {
--	      free(packet);
--	      blockdata_free(block);
--	      return STAT_BOGUS; /* run out of labels */
--	    }
--	  
--	  name_start -= 2;
--	  while (*name_start != '.' && name_start != name) 
--	    name_start--;
--	  if (name_start != name)
--	    name_start++;
--	}
--      
--      /* Can't find it in the cache, have to send a query */
--
--      m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr, server->edns_pktsz);
--      
--      *length = htons(m);
--      
--      if (read_write(server->tcpfd, packet, m + sizeof(u16), 0) &&
--	  read_write(server->tcpfd, &c1, 1, 1) &&
--	  read_write(server->tcpfd, &c2, 1, 1) &&
--	  read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
--	{
--	  m = (c1 << 8) | c2;
--	  
--	  /* Note this trashes all three name workspaces */
--	  status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name, keyname, server, keycount);
--	  
--	  if (status == STAT_NO_DS)
--	    {
--	      /* Found a secure denial of DS - delegation is indeed insecure */
--	      free(packet);
--	      blockdata_free(block);
--	      return STAT_INSECURE;
--	    }
--	  
--	  if (status == STAT_NO_SIG && *keyname != 0)
--	    {
--	      /* There is a validated CNAME chain that doesn't end in a DS record. Start 
--		 the search again in that domain. */
--	      blockdata_free(block);
--	      name_len = strlen(keyname) + 1;
--	      name_start = name + name_len - 1;
--	      
--	      if (!(block = blockdata_alloc(keyname, name_len)))
--		return STAT_BOGUS;
--	      
--	      strcpy(name, keyname);
--	      continue;
--	    }
--	  
--	  if (status == STAT_BOGUS)
--	    {
--	      free(packet);
--	      blockdata_free(block);
--	      return STAT_BOGUS;
--	    }
--	  
--	  /* Here, either there's a secure DS, or no NS and no DS, and therefore no delegation.
--	     Add another label and continue. */
--	  
--	  /* Get name we're checking back. */
--	  blockdata_retrieve(block, name_len, name);
--	  
--	  if (name_start == name)
--	    {
--	      free(packet);
--	      blockdata_free(block);
--	      return STAT_BOGUS; /* run out of labels */
--	    }
--	  
--	  name_start -= 2;
--	  while (*name_start != '.' && name_start != name) 
--	    name_start--;
--	  if (name_start != name)
--	    name_start++;
--	}
--      else
--	{
--	  /* IO failure */
--	  free(packet);
--	  blockdata_free(block);
--	  return STAT_BOGUS; /* run out of labels */
--	}
--    }
--}
--
- static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, 
- 			   int class, char *name, char *keyname, struct server *server, int *keycount)
- {
-   /* Recurse up the key heirarchy */
-   int new_status;
-+  unsigned char *packet = NULL;
-+  size_t m; 
-+  unsigned char *payload = NULL;
-+  struct dns_header *new_header = NULL;
-+  u16 *length = NULL;
-+  unsigned char c1, c2;
- 
--  /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
--  if (--(*keycount) == 0)
--    return STAT_INSECURE;
--  
--  if (status == STAT_NEED_KEY)
--    new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
--  else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
-+  while (1)
-     {
--      new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
--      if (status == STAT_NEED_DS)
-+      /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
-+      if (--(*keycount) == 0)
-+	new_status = STAT_ABANDONED;
-+      else if (status == STAT_NEED_KEY)
-+	new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
-+      else if (status == STAT_NEED_DS)
-+	new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
-+      else 
-+	new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
-+      
-+      if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
-+	break;
-+
-+      /* Can't validate because we need a key/DS whose name now in keyname.
-+	 Make query for same, and recurse to validate */
-+      if (!packet)
- 	{
--	  if (new_status == STAT_NO_DS)
--	    new_status = STAT_INSECURE_DS;
--	  if (new_status == STAT_NO_SIG)
--	   {
--	     if (option_bool(OPT_DNSSEC_NO_SIGN))
--	       {
--		 new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
--		 if (new_status == STAT_INSECURE)
--		   new_status = STAT_INSECURE_DS;
--	       }
--	     else
--	       new_status = STAT_INSECURE_DS;
--	   }
--	  else if (new_status == STAT_NO_NS)
--	    new_status = STAT_BOGUS;
-+	  packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
-+	  payload = &packet[2];
-+	  new_header = (struct dns_header *)payload;
-+	  length = (u16 *)packet;
- 	}
--    }
--  else if (status == STAT_CHASE_CNAME)
--    new_status = dnssec_chase_cname(now, header, n, name, keyname);
--  else 
--    {
--      new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL, NULL);
-       
--      if (new_status == STAT_NO_SIG)
-+      if (!packet)
- 	{
--	  if (option_bool(OPT_DNSSEC_NO_SIGN))
--	    new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
--	  else
--	    new_status = STAT_INSECURE;
-+	  new_status = STAT_ABANDONED;
-+	  break;
- 	}
--    }
--
--  /* Can't validate because we need a key/DS whose name now in keyname.
--     Make query for same, and recurse to validate */
--  if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY)
--    {
--      size_t m; 
--      unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
--      unsigned char *payload = &packet[2];
--      struct dns_header *new_header = (struct dns_header *)payload;
--      u16 *length = (u16 *)packet;
--      unsigned char c1, c2;
--       
--      if (!packet)
--	return STAT_INSECURE;
--
--    another_tcp_key:
-+	 
-       m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class, 
- 				new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
-       
-@@ -1733,65 +1364,22 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
- 	  !read_write(server->tcpfd, &c1, 1, 1) ||
- 	  !read_write(server->tcpfd, &c2, 1, 1) ||
- 	  !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
--	new_status = STAT_INSECURE;
--      else
- 	{
--	  m = (c1 << 8) | c2;
--	  
--	  new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
--	  
--	  if (new_status == STAT_SECURE)
--	    {
--	      /* Reached a validated record, now try again at this level.
--		 Note that we may get ANOTHER NEED_* if an answer needs more than one key.
--		 If so, go round again. */
--	      
--	      if (status == STAT_NEED_KEY)
--		new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
--	      else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
--		{
--		  new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
--		  if (status == STAT_NEED_DS)
--		    {
--		      if (new_status == STAT_NO_DS)
--			new_status = STAT_INSECURE_DS;
--		      else if (new_status == STAT_NO_SIG)
--			{
--			  if (option_bool(OPT_DNSSEC_NO_SIGN))
--			    {
--			      new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount); 
--			      if (new_status == STAT_INSECURE)
--				new_status = STAT_INSECURE_DS;
--			    }
--			  else
--			    new_status = STAT_INSECURE_DS;
--			}
--		      else if (new_status == STAT_NO_NS)
--			new_status = STAT_BOGUS;
--		    }
--		}
--	      else if (status == STAT_CHASE_CNAME)
--		new_status = dnssec_chase_cname(now, header, n, name, keyname);
--	      else 
--		{
--		  new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL, NULL);
--		  
--		  if (new_status == STAT_NO_SIG)
--		    {
--		      if (option_bool(OPT_DNSSEC_NO_SIGN))
--			new_status = tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, server, keycount);
--		      else
--			new_status = STAT_INSECURE;
--		    }
--		}
--	      
--	      if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY)
--		goto another_tcp_key;
--	    }
-+	  new_status = STAT_ABANDONED;
-+	  break;
- 	}
-+
-+      m = (c1 << 8) | c2;
-       
--      free(packet);
-+      new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
-+      
-+      if (new_status != STAT_OK)
-+	break;
-     }
-+
-+  if (packet)
-+    free(packet);
-+    
-   return new_status;
- }
- #endif
-@@ -2075,19 +1663,10 @@ unsigned char *tcp_request(int confd, time_t now,
- 		      if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled)
- 			{
- 			  int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
--			  int status = tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
-+			  int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
- 			  char *result, *domain = "result";
--
--			  if (status == STAT_INSECURE_DS)
--			    {
--			      /* We only cache sigs when we've validated a reply.
--				 Avoid caching a reply with sigs if there's a vaildated break in the 
--				 DS chain, so we don't return replies from cache missing sigs. */
--			      status = STAT_INSECURE;
--			      no_cache_dnssec = 1;
--			    }
- 			  
--			  if (keycount == 0)
-+			  if (status == STAT_ABANDONED)
- 			    {
- 			      result = "ABANDONED";
- 			      status = STAT_BOGUS;
-@@ -2179,7 +1758,6 @@ static struct frec *allocate_frec(time_t now)
-       f->dependent = NULL;
-       f->blocking_query = NULL;
-       f->stash = NULL;
--      f->orig_domain = NULL;
- #endif
-       daemon->frec_list = f;
-     }
-@@ -2248,12 +1826,6 @@ static void free_frec(struct frec *f)
-       f->stash = NULL;
-     }
- 
--  if (f->orig_domain)
--    {
--      blockdata_free(f->orig_domain);
--      f->orig_domain = NULL;
--    }
--
-   /* Anything we're waiting on is pointless now, too */
-   if (f->blocking_query)
-     free_frec(f->blocking_query);
-@@ -2281,14 +1853,23 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
-       target = f;
-     else 
-       {
--	if (difftime(now, f->time) >= 4*TIMEOUT)
--	  {
--	    free_frec(f);
--	    target = f;
--	  }
--	
--	if (!oldest || difftime(f->time, oldest->time) <= 0)
--	  oldest = f;
-+#ifdef HAVE_DNSSEC
-+	    /* Don't free DNSSEC sub-queries here, as we may end up with
-+	       dangling references to them. They'll go when their "real" query 
-+	       is freed. */
-+	    if (!f->dependent)
-+#endif
-+	      {
-+		if (difftime(now, f->time) >= 4*TIMEOUT)
-+		  {
-+		    free_frec(f);
-+		    target = f;
-+		  }
-+	     
-+	    
-+		if (!oldest || difftime(f->time, oldest->time) <= 0)
-+		  oldest = f;
-+	      }
-       }
- 
-   if (target)
--- 
-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=0
----
- src/cache.c   |   38 ++---------
- src/dnsmasq.h |   10 +--
- src/dnssec.c  |   94 ++++-----------------------
- src/rfc1035.c |  197 ++++++---------------------------------------------------
- 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)
- {
-   if (crecp->flags & F_DNSKEY)
--    {
--      if (crecp->flags & F_DS)
--	blockdata_free(crecp->addr.sig.keydata);
--      else
--	blockdata_free(crecp->addr.key.keydata);
--    }
-+    blockdata_free(crecp->addr.key.keydata);
-   else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
-     blockdata_free(crecp->addr.ds.keydata);
- }
-@@ -369,13 +364,8 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
- 		}
- 	      
- #ifdef HAVE_DNSSEC
--	      /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also 
--		 type-covered sensitive for  RRSIG */
--	      if ((flags & (F_DNSKEY | F_DS)) &&
--		  (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
--		  crecp->uid == addr->addr.dnssec.class &&
--		  (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) || 
--		   crecp->addr.sig.type_covered == addr->addr.dnssec.type))
-+	      /* Deletion has to be class-sensitive for DS and DNSKEY */
-+	      if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
- 		{
- 		  if (crecp->flags & F_CONFIG)
- 		    return crecp;
-@@ -532,13 +522,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
- 	    struct all_addr free_addr = new->addr.addr;;
- 
- #ifdef HAVE_DNSSEC
--	    /* For DNSSEC records, addr holds class and type_covered for RRSIG */
-+	    /* For DNSSEC records, addr holds class. */
- 	    if (new->flags & (F_DS | F_DNSKEY))
--	      {
--		free_addr.addr.dnssec.class = new->uid;
--		if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
--		  free_addr.addr.dnssec.type = new->addr.sig.type_covered;
--	      }
-+	      free_addr.addr.dnssec.class = new->uid;
- #endif
- 	    
- 	    free_avail = 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
- 	  if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
- 	    {
- 	      if ((crecp->flags & F_FORWARD) && 
--#ifdef HAVE_DNSSEC
--		  (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
--#endif
- 		  (crecp->flags & prot) &&
- 		  hostname_isequal(cache_get_name(crecp), name))
- 		{
-@@ -713,9 +696,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
- 
-   if (ans && 
-       (ans->flags & F_FORWARD) &&
--#ifdef HAVE_DNSSEC
--      (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
--#endif
-       (ans->flags & prot) &&     
-       hostname_isequal(cache_get_name(ans), name))
-     return ans;
-@@ -1472,11 +1452,7 @@ void dump_cache(time_t now)
- #ifdef HAVE_DNSSEC
- 	    else if (cache->flags & F_DS)
- 	      {
--		if (cache->flags & F_DNSKEY)
--		  /* RRSIG */
--		  sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
--			  cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
--		else if (!(cache->flags & F_NEG))
-+		if (!(cache->flags & F_NEG))
- 		  sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
- 			  cache->addr.ds.algo, cache->addr.ds.digest);
- 	      }
-@@ -1502,8 +1478,6 @@ void dump_cache(time_t now)
- 	    else if (cache->flags & F_CNAME)
- 	      t = "C";
- #ifdef HAVE_DNSSEC
--	    else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
--	      t = "G"; /* DNSKEY and DS set -> RRISG */
- 	    else if (cache->flags & F_DS)
- 	      t = "S";
- 	    else 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 {
-       unsigned char algo;
-       unsigned char digest; 
-     } ds; 
--    struct {
--      struct blockdata *keydata;
--      unsigned short keylen, type_covered, keytag;
--      char algo;
--    } sig;
-   } addr;
-   time_t ttd; /* time to die */
--  /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
-+  /* used as class if DNSKEY/DS, index to source for F_HOSTS */
-   unsigned int uid; 
-   unsigned short flags;
-   union {
-@@ -445,8 +440,7 @@ struct crec {
- #define F_SECSTAT   (1u<<24)
- #define F_NO_RR     (1u<<25)
- #define F_IPSET     (1u<<26)
--#define F_NSIGMATCH (1u<<27)
--#define F_NOEXTRA   (1u<<28)
-+#define F_NOEXTRA   (1u<<27)
- 
- /* 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
- {
-   unsigned char *psave, *p = (unsigned char *)(header+1);
-   struct crec *crecp, *recp1;
--  int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
-+  int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
-   struct blockdata *key;
-   struct all_addr a;
- 
-@@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 
-   if (valid)
-     {
--      /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
-+      /* DNSKEY RRset determined to be OK, now cache it. */
-       cache_start_insert();
-       
-       p = skip_questions(header, plen);
-@@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 		  if ((key = blockdata_alloc((char*)p, rdlen - 4)))
- 		    {
- 		      if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
--			blockdata_free(key);
-+			{
-+			  blockdata_free(key);
-+			  return STAT_BOGUS;
-+			}
- 		      else
- 			{
- 			  a.addr.keytag = keytag;
-@@ -1169,38 +1172,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 			}
- 		    }
- 		}
--	      else if (qtype == T_RRSIG)
--		{
--		  /* RRSIG, cache if covers DNSKEY RRset */
--		  if (rdlen < 18)
--		    return STAT_BOGUS; /* bad packet */
--		  
--		  GETSHORT(type_covered, p);
--		  
--		  if (type_covered == T_DNSKEY)
--		    {
--		      a.addr.dnssec.class = class;
--		      a.addr.dnssec.type = type_covered;
--		      
--		      algo = *p++;
--		      p += 13; /* labels, orig_ttl, expiration, inception */
--		      GETSHORT(keytag, p);	
--		      if ((key = blockdata_alloc((char*)psave, rdlen)))
--			{
--			  if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
--			    blockdata_free(key);
--			  else
--			    {
--			      crecp->addr.sig.keydata = key;
--			      crecp->addr.sig.keylen = rdlen;
--			      crecp->addr.sig.keytag = keytag;
--			      crecp->addr.sig.type_covered = type_covered;
--			      crecp->addr.sig.algo = algo;
--			    }
--			}
--		    }
--		}
--	      
-+	      	      
- 	      p = psave;
- 	    }
- 
-@@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
- 	  cache_start_insert();
- 	  
- 	  a.addr.dnssec.class = class;
--	  cache_insert(name, &a, now, ttl, flags);
-+	  if (!cache_insert(name, &a, now, ttl, flags))
-+	    return STAT_BOGUS;
- 	  
- 	  cache_end_insert();  
- 	  
-@@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 	  /* Not done, validate now */
- 	  if (j == i)
- 	    {
--	      int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
-+	      int ttl, keytag, algo, digest, sigcnt, rrcnt;
- 	      unsigned char *psave;
- 	      struct all_addr a;
- 	      struct blockdata *key;
- 	      struct crec *crecp;
- 	      char *wildname;
--	      int have_wildcard = 0;
--
-+	      
- 	      if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
- 		return STAT_BOGUS;
- 
-@@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 			    
- 		  if (rc == STAT_SECURE_WILDCARD)
- 		    {
--		      have_wildcard = 1;
--		      
- 		      /* An attacker replay a wildcard answer with a different
- 			 answer and overlay a genuine RR. To prove this
- 			 hasn'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
- 			return rc;
- 		    } 
- 		  
--		  /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
-+		  /* If we just validated a DS RRset, cache it */
- 		  /* Also note if the RRset is the answer to the question, or the target of a CNAME */
- 		  cache_start_insert();
- 		  
-@@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 				    } 
- 				}
- 			    }
--			  else if (type2 == T_RRSIG)
--			    {
--			      if (rdlen2 < 18)
--				return STAT_BOGUS; /* bad packet */
--			      
--			      GETSHORT(type_covered, p2);
--			      
--			      if (type_covered == type1 && 
--				  (type_covered == T_A || type_covered == T_AAAA ||
--				   type_covered == T_CNAME || type_covered == T_DS || 
--				   type_covered == T_DNSKEY || type_covered == T_PTR)) 
--				{
--				  a.addr.dnssec.type = type_covered;
--				  a.addr.dnssec.class = class1;
--				  
--				  algo = *p2++;
--				  p2 += 13; /* labels, orig_ttl, expiration, inception */
--				  GETSHORT(keytag, p2);
--				  
--				  /* We don't cache sigs for wildcard answers, because to reproduce the
--				     answer from the cache will require one or more NSEC/NSEC3 records 
--				     which we don't cache. The lack of the RRSIG ensures that a query for
--				     this RRset asking for a secure answer will always be forwarded. */
--				  if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
--				    {
--				      if (!(crecp = cache_insert(name, &a, now, ttl,  F_FORWARD | F_DNSKEY | F_DS)))
--					blockdata_free(key);
--				      else
--					{
--					  crecp->addr.sig.keydata = key;
--					  crecp->addr.sig.keylen = rdlen2;
--					  crecp->addr.sig.keytag = keytag;
--					  crecp->addr.sig.type_covered = type_covered;
--					  crecp->addr.sig.algo = algo;
--					}
--				    }
--				}
--			    }
--			  
-+
- 			  p2 = psave;
- 			}
- 		      
-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)
-   struct naptr *naptr;
- 
-   /* Note: the call to cache_find_by_name is intended to find any record which matches
--     ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
--     cache_find_by name ordinarily only returns records with an exact match on those bits (ie
--     for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
-+     ie A, AAAA, CNAME. */
- 
--  if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
-+  if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
-       (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
-     return 1;
-   
-@@ -1566,9 +1564,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-       GETSHORT(flags, pheader);
-       
-       if ((sec_reqd = flags & 0x8000))
--	*do_bit = 1;/* do bit */ 
-+	{
-+	  *do_bit = 1;/* do bit */ 
-+	  *ad_reqd = 1;
-+	}
- 
--      *ad_reqd = 1;
-       dryrun = 1;
-     }
- 
-@@ -1636,98 +1636,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 	    }
- 	}
- 
--#ifdef HAVE_DNSSEC
--      if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
--	{
--	  int gotone = 0;
--	  struct blockdata *keydata;
--
--	  /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
--	  if (sec_reqd)
--	    {
--	      crecp = NULL;
--	      while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
--		if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
--		  break;
--	    }
--	  
--	  if (!sec_reqd || crecp)
--	    {
--	      if (qtype == T_DS)
--		{
--		  crecp = NULL;
--		  while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
--		    if (crecp->uid == qclass)
--		      {
--			gotone = 1; 
--			if (!dryrun)
--			  {
--			    if (crecp->flags & F_NEG)
--			      {
--				if (crecp->flags & F_NXDOMAIN)
--				  nxdomain = 1;
--				log_query(F_UPSTREAM, name, NULL, "no DS");	
--			      }
--			    else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
--			      {			     			      
--				struct all_addr a;
--				a.addr.keytag =  crecp->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, 
--							crec_ttl(crecp, now), &nameoffset,
--							T_DS, qclass, "sbbt", 
--							crecp->addr.ds.keytag, crecp->addr.ds.algo, 
--							crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
--				  anscount++;
--				
--			      } 
--			  }
--		      }
--		}
--	      else /* DNSKEY */
--		{
--		  crecp = NULL;
--		  while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
--		    if (crecp->uid == qclass)
--		      {
--			gotone = 1;
--			if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
--			  {			     			      
--			    struct all_addr a;
--			    a.addr.keytag =  crecp->addr.key.keytag;
--			    log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
--			    if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--						    crec_ttl(crecp, now), &nameoffset,
--						    T_DNSKEY, qclass, "sbbt", 
--						    crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
--			      anscount++;
--			  }
--		      }
--		}
--	    }
--	  
--	  /* Now do RRSIGs */
--	  if (gotone)
--	    {
--	      ans = 1;
--	      auth = 0;
--	      if (!dryrun && sec_reqd)
--		{
--		  crecp = NULL;
--		  while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
--		    if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
--			(keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
--		      {
--			add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--					    crec_ttl(crecp, now), &nameoffset,
--					    T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
--			anscount++;
--		      }
--		}
--	    }
--	}
--#endif	     
--      
-       if (qclass == C_IN)
- 	{
- 	  struct txt_record *t;
-@@ -1736,6 +1644,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 	    if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
- 	      {
- 		ans = 1;
-+		sec_data = 0;
- 		if (!dryrun)
- 		  {
- 		    log_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,
- 	      
- 	      if (intr)
- 		{
-+		  sec_data = 0;
- 		  ans = 1;
- 		  if (!dryrun)
- 		    {
-@@ -1805,6 +1715,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 	      else if (ptr)
- 		{
- 		  ans = 1;
-+		  sec_data = 0;
- 		  if (!dryrun)
- 		    {
- 		      log_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,
- 		}
- 	      else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
- 		{
--		  if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
--		    {
--		      if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
--			crecp = NULL;
--#ifdef HAVE_DNSSEC
--		      else if (crecp->flags & F_DNSSECOK)
--			{
--			  int gotsig = 0;
--			  struct crec *rr_crec = NULL;
--
--			  while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
--			    {
--			      if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
--				{
--				  char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
--				  gotsig = 1;
--				  
--				  if (!dryrun && 
--				      add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--							  rr_crec->ttd - now, &nameoffset,
--							  T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
--				    anscount++;
--				}
--			    } 
--			  
--			  if (!gotsig)
--			    crecp = NULL;
--			}
--#endif
--		    }
--
--		  if (crecp)
-+		  /* Don't use cache when DNSSEC data required. */
-+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
- 		    {
- 		      do 
- 			{ 
-@@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 			  
- 			  if (!(crecp->flags & F_DNSSECOK))
- 			    sec_data = 0;
--			  
-+			   
-+			  ans = 1;
-+			   
- 			  if (crecp->flags & F_NEG)
- 			    {
--			      ans = 1;
- 			      auth = 0;
- 			      if (crecp->flags & F_NXDOMAIN)
- 				nxdomain = 1;
- 			      if (!dryrun)
- 				log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
- 			    }
--			  else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
-+			  else
- 			    {
--			      ans = 1;
- 			      if (!(crecp->flags & (F_HOSTS | F_DHCP)))
- 				auth = 0;
- 			      if (!dryrun)
-@@ -1892,6 +1773,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 	      else if (is_rev_synth(is_arpa, &addr, name))
- 		{
- 		  ans = 1;
-+		  sec_data = 0;
- 		  if (!dryrun)
- 		    {
- 		      log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL); 
-@@ -1908,6 +1790,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 		{
- 		  /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
- 		  ans = 1;
-+		  sec_data = 0;
- 		  nxdomain = 1;
- 		  if (!dryrun)
- 		    log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, 
-@@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 		  if (i == 4)
- 		    {
- 		      ans = 1;
-+		      sec_data = 0;
- 		      if (!dryrun)
- 			{
- 			  addr.addr.addr4.s_addr = htonl(a);
-@@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 				continue;
- #endif	
- 			      ans = 1;	
-+			      sec_data = 0;
- 			      if (!dryrun)
- 				{
- 				  gotit = 1;
-@@ -2032,48 +1917,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 		      crecp = save;
- 		    }
- 
--		  /* If the client asked for DNSSEC and we can't provide RRSIGs, either
--		     because we've not doing DNSSEC or the cached answer is signed by negative,
--		     don't answer from the cache, forward instead. */
--		  if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
--		    {
--		      if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
--			crecp = NULL;
--#ifdef HAVE_DNSSEC
--		      else if (crecp->flags & F_DNSSECOK)
--			{
--			  /* We're returning validated data, need to return the RRSIG too. */
--			  struct crec *rr_crec = NULL;
--			  int sigtype = type;
--			  /* The signature may have expired even though the data is still in cache, 
--			     forward instead of answering from cache if so. */
--			  int gotsig = 0;
--			  
--			  if (crecp->flags & F_CNAME)
--			    sigtype = T_CNAME;
--			  
--			  while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
--			    {
--			      if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
--				{
--				  char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
--				  gotsig = 1;
--				  
--				  if (!dryrun && 
--				      add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
--							  rr_crec->ttd - now, &nameoffset,
--							  T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
--				    anscount++;
--				}
--			    }
--			  
--			  if (!gotsig)
--			    crecp = NULL;
--			}
--#endif
--		    }		 
--
--		  if (crecp)
-+		  /* If the client asked for DNSSEC  don't use cached data. */
-+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
- 		    do
- 		      { 
- 			/* don't answer wildcard queries with data not from /etc/hosts
--- 
-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 |  179 +++++++++++++++++++++++++++++-----------------------------
- 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)
- {
-   unsigned char *p = (unsigned char *)(header+1);
--  int qtype, qclass, val, i, neganswer, nons;
-+  int qtype, qclass, rc, i, neganswer, nons;
-+  int aclass, atype, rdlen;
-+  unsigned long ttl;
-+  struct all_addr a;
- 
-   if (ntohs(header->qdcount) != 1 ||
-       !(p = skip_name(p, header, plen, 4)))
-@@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
-   GETSHORT(qclass, p);
- 
-   if (qtype != T_DS || qclass != class)
--    val = STAT_BOGUS;
-+    rc = STAT_BOGUS;
-   else
--    val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
-+    rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
-   /* Note dnssec_validate_reply() will have cached positive answers */
-   
--  if (val == STAT_INSECURE)
--    val = STAT_BOGUS;
--
-+  if (rc == STAT_INSECURE)
-+    rc = STAT_BOGUS;
-+ 
-   p = (unsigned char *)(header+1);
-   extract_name(header, plen, &p, name, 1, 4);
-   p += 4; /* qtype, qclass */
-   
--  if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
--    val = STAT_BOGUS;
--  
-   /* If the key needed to validate the DS is on the same domain as the DS, we'll
-      loop getting nowhere. Stop that now. This can happen of the DS answer comes
-      from the DS's zone, and not the parent zone. */
--  if (val == STAT_BOGUS || (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-+  if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
-     {
-       log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
-       return STAT_BOGUS;
-     }
-   
--  if (val != STAT_SECURE)
--    return val;
--
--  /* By here, the answer is proved secure, and a positive answer has been cached. */
--  if (neganswer)
-+  if (rc != STAT_SECURE)
-+    return rc;
-+   
-+  if (!neganswer)
-     {
--      int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
--      unsigned long ttl, minttl = ULONG_MAX;
--      struct all_addr a;
-+      cache_start_insert();
-+      
-+      for (i = 0; i < ntohs(header->ancount); i++)
-+	{
-+	  if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
-+	    return STAT_BOGUS; /* bad packet */
-+	  
-+	  GETSHORT(atype, p);
-+	  GETSHORT(aclass, p);
-+	  GETLONG(ttl, p);
-+	  GETSHORT(rdlen, p);
-+	  
-+	  if (!CHECK_LEN(header, p, plen, rdlen))
-+	    return STAT_BOGUS; /* bad packet */
-+	  
-+	  if (aclass == class && atype == T_DS && rc == 1)
-+	    { 
-+	      int algo, digest, keytag;
-+	      unsigned char *psave = p;
-+	      struct blockdata *key;
-+	      struct crec *crecp;
- 
-+	      if (rdlen < 4)
-+		return STAT_BOGUS; /* bad packet */
-+	      
-+	      GETSHORT(keytag, p);
-+	      algo = *p++;
-+	      digest = *p++;
-+	      
-+	      /* Cache needs to known class for DNSSEC stuff */
-+	      a.addr.dnssec.class = class;
-+	      
-+	      if ((key = blockdata_alloc((char*)p, rdlen - 4)))
-+		{
-+		  if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
-+		    {
-+		      blockdata_free(key);
-+		      return STAT_BOGUS;
-+		    }
-+		  else
-+		    {
-+		      a.addr.keytag = keytag;
-+		      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+		      crecp->addr.ds.digest = digest;
-+		      crecp->addr.ds.keydata = key;
-+		      crecp->addr.ds.algo = algo;
-+		      crecp->addr.ds.keytag = keytag;
-+		      crecp->addr.ds.keylen = rdlen - 4; 
-+		    } 
-+		}
-+	      
-+	      p = psave;
-+	      
-+	      if (!ADD_RDLEN(header, p, plen, rdlen))
-+		return STAT_BOGUS; /* bad packet */
-+	    }
-+	  
-+	  cache_end_insert();
-+	}
-+    }
-+  else
-+    {
-+      int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
-+      unsigned long minttl = ULONG_MAX;
-+      
-+      if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
-+	return STAT_BOGUS;
-+      
-       if (RCODE(header) == NXDOMAIN)
- 	flags |= F_NXDOMAIN;
-       
-@@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
- 	  if (!(p = skip_name(p, header, plen, 0)))
- 	    return STAT_BOGUS;
- 	  
--	  GETSHORT(qtype, p); 
--	  GETSHORT(qclass, p);
-+	  GETSHORT(atype, p); 
-+	  GETSHORT(aclass, p);
- 	  GETLONG(ttl, p);
- 	  GETSHORT(rdlen, p);
--
-+	  
- 	  if (!CHECK_LEN(header, p, plen, rdlen))
- 	    return STAT_BOGUS; /* bad packet */
--	    
--	  if (qclass != class || qtype != T_SOA)
-+	  
-+	  if (aclass != class || atype != T_SOA)
- 	    {
- 	      p += rdlen;
- 	      continue;
- 	    }
--           
-+	  
- 	  if (ttl < minttl)
- 	    minttl = ttl;
- 	  
-@@ -1306,7 +1369,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
- 	  log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
- 	}
-     }
--
-+      
-   return STAT_OK;
- }
- 
-@@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 	  /* Not done, validate now */
- 	  if (j == i)
- 	    {
--	      int ttl, keytag, algo, digest, sigcnt, rrcnt;
--	      unsigned char *psave;
--	      struct all_addr a;
--	      struct blockdata *key;
--	      struct crec *crecp;
-+	      int sigcnt, rrcnt;
- 	      char *wildname;
- 	      
- 	      if (!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
- 		 Can't overwrite name here. */
- 	      strcpy(daemon->workspacename, keyname);
- 	      rc = zone_status(daemon->workspacename, class1, keyname, now);
-+
- 	      if (rc != STAT_SECURE)
- 		{
- 		  /* 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
- 		      if (rc == STAT_BOGUS)
- 			return rc;
- 		    } 
--		  
--		  /* If we just validated a DS RRset, cache it */
--		  /* Also note if the RRset is the answer to the question, or the target of a CNAME */
--		  cache_start_insert();
--		  
--		  for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
--		    {
--		      if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
--			return STAT_BOGUS; /* bad packet */
--		      
--		      GETSHORT(type2, p2);
--		      GETSHORT(class2, p2);
--		      GETLONG(ttl, p2);
--		      GETSHORT(rdlen2, p2);
--		      
--		      if (!CHECK_LEN(header, p2, plen, rdlen2))
--			return STAT_BOGUS; /* bad packet */
--		      
--		      if (class2 == class1 && rc == 1)
--			{ 
--			  psave = p2;
--			  
--			  if (type1 == T_DS && type2 == T_DS)
--			    {
--			      if (rdlen2 < 4)
--				return STAT_BOGUS; /* bad packet */
--			      
--			      GETSHORT(keytag, p2);
--			      algo = *p2++;
--			      digest = *p2++;
--			      
--			      /* Cache needs to known class for DNSSEC stuff */
--			      a.addr.dnssec.class = class2;
--			      
--			      if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
--				{
--				  if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
--				    blockdata_free(key);
--				  else
--				    {
--				      a.addr.keytag = keytag;
--				      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
--				      crecp->addr.ds.digest = digest;
--				      crecp->addr.ds.keydata = key;
--				      crecp->addr.ds.algo = algo;
--				      crecp->addr.ds.keytag = keytag;
--				      crecp->addr.ds.keylen = rdlen2 - 4; 
--				    } 
--				}
--			    }
--
--			  p2 = psave;
--			}
--		      
--		      if (!ADD_RDLEN(header, p2, plen, rdlen2))
--			return STAT_BOGUS; /* bad packet */
--		    }
--		  
--		  cache_end_insert();
- 		}
- 	    }
- 	}
--- 
-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       |    3 +-
- bld/Android.mk |    2 +-
- src/dnsmasq.h  |    5 +
- src/dnssec.c   |  307 +-------------------------------------------------
- src/forward.c  |    2 +-
- src/rrfilter.c |  339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 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 = cache.o rfc1035.o util.o option.o forward.o network.o \
-        dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
-        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
-        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
--       domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o
-+       domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
-+       poll.o rrfilter.o
- 
- hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
-        dns-protocol.h radv-protocol.h ip6addr.h
-diff --git a/bld/Android.mk b/bld/Android.mk
-index 5364ee7..67b9c4b 100644
---- a/bld/Android.mk
-+++ b/bld/Android.mk
-@@ -10,7 +10,7 @@ LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
- 		    dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
- 		    radv.c slaac.c auth.c ipset.c domain.c \
- 	            dnssec.c dnssec-openssl.c blockdata.c tables.c \
--		    loop.c inotify.c poll.c
-+		    loop.c inotify.c poll.c rrfilter.c
- 
- LOCAL_MODULE := dnsmasq
- 
-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);
- 
-+/* 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)
-     && serial_compare_32(curtime, date_end) == SERIAL_LT;
- }
- 
--static u16 *get_desc(int type)
--{
--  /* List of RRtypes which include domains in the data.
--     0 -> domain
--     integer -> no of plain bytes
--     -1 -> end
--
--     zero is not a valid RRtype, so the final entry is returned for
--     anything which needs no mangling.
--  */
--  
--  static u16 rr_desc[] = 
--    { 
--      T_NS, 0, -1, 
--      T_MD, 0, -1,
--      T_MF, 0, -1,
--      T_CNAME, 0, -1,
--      T_SOA, 0, 0, -1,
--      T_MB, 0, -1,
--      T_MG, 0, -1,
--      T_MR, 0, -1,
--      T_PTR, 0, -1,
--      T_MINFO, 0, 0, -1,
--      T_MX, 2, 0, -1,
--      T_RP, 0, 0, -1,
--      T_AFSDB, 2, 0, -1,
--      T_RT, 2, 0, -1,
--      T_SIG, 18, 0, -1,
--      T_PX, 2, 0, 0, -1,
--      T_NXT, 0, -1,
--      T_KX, 2, 0, -1,
--      T_SRV, 6, 0, -1,
--      T_DNAME, 0, -1,
--      0, -1 /* wildcard/catchall */
--    }; 
--  
--  u16 *p = rr_desc;
--  
--  while (*p != type && *p != 0)
--    while (*p++ != (u16)-1);
--
--  return p+1;
--}
--
- /* Return bytes of canonicalised rdata, when the return value is zero, the remaining 
-    data, 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,
-     }
- }
- 
--static int expand_workspace(unsigned char ***wkspc, int *szp, int new)
--{
--  unsigned char **p;
--  int old = *szp;
--
--  if (old >= new+1)
--    return 1;
--
--  if (new >= 100)
--    return 0;
--
--  new += 5;
--  
--  if (!(p = whine_malloc(new * sizeof(unsigned char **))))
--    return 0;  
--  
--  if (old != 0 && *wkspc)
--    {
--      memcpy(p, *wkspc, old * sizeof(unsigned char **));
--      free(*wkspc);
--    }
--  
--  *wkspc = p;
--  *szp = new;
--
--  return 1;
--}
--
- /* Bubble sort the RRset into the canonical order. 
-    Note that the byte-streams from two RRs may get unsynced: consider 
-    RRs which have two domain-names at the start and then other data.
-@@ -849,7 +777,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-   int rdlen, j, name_labels;
-   struct crec *crecp = NULL;
-   int algo, labels, orig_ttl, key_tag;
--  u16 *rr_desc = get_desc(type);
-+  u16 *rr_desc = rrfilter_desc(type);
-  
-   if (wildcard_out)
-     *wildcard_out = NULL;
-@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
-   return ret;
- }
- 
--/* Go through a domain name, find "pointers" and fix them up based on how many bytes
--   we've chopped out of the packet, or check they don't point into an elided part.  */
--static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
--{
--  unsigned char *ansp = *namep;
--
--  while(1)
--    {
--      unsigned int label_type;
--      
--      if (!CHECK_LEN(header, ansp, plen, 1))
--	return 0;
--      
--      label_type = (*ansp) & 0xc0;
--
--      if (label_type == 0xc0)
--	{
--	  /* pointer for compression. */
--	  unsigned int offset;
--	  int i;
--	  unsigned char *p;
--	  
--	  if (!CHECK_LEN(header, ansp, plen, 2))
--	    return 0;
--
--	  offset = ((*ansp++) & 0x3f) << 8;
--	  offset |= *ansp++;
--
--	  p = offset + (unsigned char *)header;
--	  
--	  for (i = 0; i < rr_count; i++)
--	    if (p < rrs[i])
--	      break;
--	    else
--	      if (i & 1)
--		offset -= rrs[i] - rrs[i-1];
--
--	  /* does the pointer end up in an elided RR? */
--	  if (i & 1)
--	    return 0;
--
--	  /* No, scale the pointer */
--	  if (fixup)
--	    {
--	      ansp -= 2;
--	      *ansp++ = (offset >> 8) | 0xc0;
--	      *ansp++ = offset & 0xff;
--	    }
--	  break;
--	}
--      else if (label_type == 0x80)
--	return 0; /* reserved */
--      else if (label_type == 0x40)
--	{
--	  /* Extended label type */
--	  unsigned int count;
--	  
--	  if (!CHECK_LEN(header, ansp, plen, 2))
--	    return 0;
--	  
--	  if (((*ansp++) & 0x3f) != 1)
--	    return 0; /* we only understand bitstrings */
--	  
--	  count = *(ansp++); /* Bits in bitstring */
--	  
--	  if (count == 0) /* count == 0 means 256 bits */
--	    ansp += 32;
--	  else
--	    ansp += ((count-1)>>3)+1;
--	}
--      else
--	{ /* label type == 0 Bottom six bits is length */
--	  unsigned int len = (*ansp++) & 0x3f;
--	  
--	  if (!ADD_RDLEN(header, ansp, plen, len))
--	    return 0;
--
--	  if (len == 0)
--	    break; /* zero length label marks the end. */
--	}
--    }
--
--  *namep = ansp;
--
--  return 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)
--{
--  int i, type, class, rdlen;
--  unsigned char *pp;
--  
--  for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
--    {
--      pp = p;
--
--      if (!(p = skip_name(p, header, plen, 10)))
--	return 0;
--      
--      GETSHORT(type, p); 
--      GETSHORT(class, p);
--      p += 4; /* TTL */
--      GETSHORT(rdlen, p);
--
--      if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
--	{
--	  /* fixup name of RR */
--	  if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
--	    return 0;
--	  
--	  if (class == C_IN)
--	    {
--	      u16 *d;
-- 
--	      for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
--		{
--		  if (*d != 0)
--		    pp += *d;
--		  else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
--		    return 0;
--		}
--	    }
--	}
--      
--      if (!ADD_RDLEN(header, p, plen, rdlen))
--	return 0;
--    }
--  
--  return 1;
--}
--	
--
--size_t filter_rrsigs(struct dns_header *header, size_t plen)
--{
--  static unsigned char **rrs;
--  static int rr_sz = 0;
--  
--  unsigned char *p = (unsigned char *)(header+1);
--  int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
--
--  if (ntohs(header->qdcount) != 1 ||
--      !(p = skip_name(p, header, plen, 4)))
--    return plen;
--  
--  GETSHORT(qtype, p);
--  GETSHORT(qclass, p);
--
--  /* First pass, find pointers to start and end of all the records we wish to elide:
--     records added for DNSSEC, unless explicity queried for */
--  for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; 
--       i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
--       i++)
--    {
--      unsigned char *pstart = p;
--      int type, class;
--
--      if (!(p = skip_name(p, header, plen, 10)))
--	return plen;
--      
--      GETSHORT(type, p); 
--      GETSHORT(class, p);
--      p += 4; /* TTL */
--      GETSHORT(rdlen, p);
--      
--      if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) && 
--	  (type != qtype || class != qclass))
--	{
--	  if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
--	    return plen; 
--	  
--	  rrs[rr_found++] = pstart;
--
--	  if (!ADD_RDLEN(header, p, plen, rdlen))
--	    return plen;
--	  
--	  rrs[rr_found++] = p;
--	  
--	  if (i < ntohs(header->ancount))
--	    chop_an++;
--	  else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
--	    chop_ns++;
--	  else
--	    chop_ar++;
--	}
--      else if (!ADD_RDLEN(header, p, plen, rdlen))
--	return plen;
--    }
--  
--  /* Nothing to do. */
--  if (rr_found == 0)
--    return plen;
--
--  /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
--     point to records we're going to elide. This is theoretically possible, but unlikely. If
--     it happens, we give up and leave the answer unchanged. */
--  p = (unsigned char *)(header+1);
--  
--  /* question first */
--  if (!check_name(&p, header, plen, 0, rrs, rr_found))
--    return plen;
--  p += 4; /* qclass, qtype */
--  
--  /* Now answers and NS */
--  if (!check_rrs(p, header, plen, 0, rrs, rr_found))
--    return plen;
--  
--  /* Third pass, elide records */
--  for (p = rrs[0], i = 1; i < rr_found; i += 2)
--    {
--      unsigned char *start = rrs[i];
--      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
--      
--      memmove(p, start, end-start);
--      p += end-start;
--    }
--     
--  plen = p - (unsigned char *)header;
--  header->ancount = htons(ntohs(header->ancount) - chop_an);
--  header->nscount = htons(ntohs(header->nscount) - chop_ns);
--  header->arcount = htons(ntohs(header->arcount) - chop_ar);
--
--  /* Fourth pass, fix up pointers in the remaining records */
--  p = (unsigned char *)(header+1);
--  
--  check_name(&p, header, plen, 1, rrs, rr_found);
--  p += 4; /* qclass, qtype */
--  
--  check_rrs(p, header, plen, 1, rrs, rr_found);
--  
--  return plen;
--}
--
- unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
- {
-   int 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
- 
-   /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
-   if (!do_bit)
--    n = filter_rrsigs(header, n);
-+    n = rrfilter(header, n, 1);
- #endif
- 
-   /* 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
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; version 2 dated June, 1991, or
-+   (at your option) version 3 dated 29 June, 2007.
-+ 
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+     
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+/* Code to safely remove RRs from an DNS answer */ 
-+
-+#include "dnsmasq.h"
-+
-+/* Go through a domain name, find "pointers" and fix them up based on how many bytes
-+   we've chopped out of the packet, or check they don't point into an elided part.  */
-+static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
-+{
-+  unsigned char *ansp = *namep;
-+
-+  while(1)
-+    {
-+      unsigned int label_type;
-+      
-+      if (!CHECK_LEN(header, ansp, plen, 1))
-+	return 0;
-+      
-+      label_type = (*ansp) & 0xc0;
-+
-+      if (label_type == 0xc0)
-+	{
-+	  /* pointer for compression. */
-+	  unsigned int offset;
-+	  int i;
-+	  unsigned char *p;
-+	  
-+	  if (!CHECK_LEN(header, ansp, plen, 2))
-+	    return 0;
-+
-+	  offset = ((*ansp++) & 0x3f) << 8;
-+	  offset |= *ansp++;
-+
-+	  p = offset + (unsigned char *)header;
-+	  
-+	  for (i = 0; i < rr_count; i++)
-+	    if (p < rrs[i])
-+	      break;
-+	    else
-+	      if (i & 1)
-+		offset -= rrs[i] - rrs[i-1];
-+
-+	  /* does the pointer end up in an elided RR? */
-+	  if (i & 1)
-+	    return 0;
-+
-+	  /* No, scale the pointer */
-+	  if (fixup)
-+	    {
-+	      ansp -= 2;
-+	      *ansp++ = (offset >> 8) | 0xc0;
-+	      *ansp++ = offset & 0xff;
-+	    }
-+	  break;
-+	}
-+      else if (label_type == 0x80)
-+	return 0; /* reserved */
-+      else if (label_type == 0x40)
-+	{
-+	  /* Extended label type */
-+	  unsigned int count;
-+	  
-+	  if (!CHECK_LEN(header, ansp, plen, 2))
-+	    return 0;
-+	  
-+	  if (((*ansp++) & 0x3f) != 1)
-+	    return 0; /* we only understand bitstrings */
-+	  
-+	  count = *(ansp++); /* Bits in bitstring */
-+	  
-+	  if (count == 0) /* count == 0 means 256 bits */
-+	    ansp += 32;
-+	  else
-+	    ansp += ((count-1)>>3)+1;
-+	}
-+      else
-+	{ /* label type == 0 Bottom six bits is length */
-+	  unsigned int len = (*ansp++) & 0x3f;
-+	  
-+	  if (!ADD_RDLEN(header, ansp, plen, len))
-+	    return 0;
-+
-+	  if (len == 0)
-+	    break; /* zero length label marks the end. */
-+	}
-+    }
-+
-+  *namep = ansp;
-+
-+  return 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)
-+{
-+  int i, j, type, class, rdlen;
-+  unsigned char *pp;
-+  
-+  for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
-+    {
-+      pp = p;
-+
-+      if (!(p = skip_name(p, header, plen, 10)))
-+	return 0;
-+      
-+      GETSHORT(type, p); 
-+      GETSHORT(class, p);
-+      p += 4; /* TTL */
-+      GETSHORT(rdlen, p);
-+
-+      /* If this RR is to be elided, don't fix up its contents */
-+      for (j = 0; j < rr_count; j += 2)
-+	if (rrs[j] == pp)
-+	  break;
-+
-+      if (j >= rr_count)
-+	{
-+	  /* fixup name of RR */
-+	  if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
-+	    return 0;
-+	  
-+	  if (class == C_IN)
-+	    {
-+	      u16 *d;
-+ 
-+	      for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; d++)
-+		{
-+		  if (*d != 0)
-+		    pp += *d;
-+		  else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
-+		    return 0;
-+		}
-+	    }
-+	}
-+      
-+      if (!ADD_RDLEN(header, p, plen, rdlen))
-+	return 0;
-+    }
-+  
-+  return 1;
-+}
-+	
-+
-+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
-+size_t rrfilter(struct dns_header *header, size_t plen, int mode)
-+{
-+  static unsigned char **rrs;
-+  static int rr_sz = 0;
-+
-+  unsigned char *p = (unsigned char *)(header+1);
-+  int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
-+
-+  if (ntohs(header->qdcount) != 1 ||
-+      !(p = skip_name(p, header, plen, 4)))
-+    return plen;
-+  
-+  GETSHORT(qtype, p);
-+  GETSHORT(qclass, p);
-+
-+  /* First pass, find pointers to start and end of all the records we wish to elide:
-+     records added for DNSSEC, unless explicity queried for */
-+  for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; 
-+       i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
-+       i++)
-+    {
-+      unsigned char *pstart = p;
-+      int type, class;
-+
-+      if (!(p = skip_name(p, header, plen, 10)))
-+	return plen;
-+      
-+      GETSHORT(type, p); 
-+      GETSHORT(class, p);
-+      p += 4; /* TTL */
-+      GETSHORT(rdlen, p);
-+        
-+      if (!ADD_RDLEN(header, p, plen, rdlen))
-+	return plen;
-+
-+      /* Don't remove the answer. */
-+      if (i < ntohs(header->ancount) && type == qtype && class == qclass)
-+	continue;
-+      
-+      if (mode == 0) /* EDNS */
-+	{
-+	  /* EDNS mode, remove T_OPT from additional section only */
-+	  if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
-+	    continue;
-+	}
-+      else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
-+	/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
-+	continue;
-+      
-+      
-+      if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
-+	return plen; 
-+      
-+      rrs[rr_found++] = pstart;
-+      rrs[rr_found++] = p;
-+      
-+      if (i < ntohs(header->ancount))
-+	chop_an++;
-+      else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
-+	chop_ns++;
-+      else
-+	chop_ar++;
-+    }
-+  
-+  /* Nothing to do. */
-+  if (rr_found == 0)
-+    return plen;
-+
-+  /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
-+     point to records we're going to elide. This is theoretically possible, but unlikely. If
-+     it happens, we give up and leave the answer unchanged. */
-+  p = (unsigned char *)(header+1);
-+  
-+  /* question first */
-+  if (!check_name(&p, header, plen, 0, rrs, rr_found))
-+    return plen;
-+  p += 4; /* qclass, qtype */
-+  
-+  /* Now answers and NS */
-+  if (!check_rrs(p, header, plen, 0, rrs, rr_found))
-+    return plen;
-+  
-+  /* Third pass, elide records */
-+  for (p = rrs[0], i = 1; i < rr_found; i += 2)
-+    {
-+      unsigned char *start = rrs[i];
-+      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
-+      
-+      memmove(p, start, end-start);
-+      p += end-start;
-+    }
-+     
-+  plen = p - (unsigned char *)header;
-+  header->ancount = htons(ntohs(header->ancount) - chop_an);
-+  header->nscount = htons(ntohs(header->nscount) - chop_ns);
-+  header->arcount = htons(ntohs(header->arcount) - chop_ar);
-+
-+  /* Fourth pass, fix up pointers in the remaining records */
-+  p = (unsigned char *)(header+1);
-+  
-+  check_name(&p, header, plen, 1, rrs, rr_found);
-+  p += 4; /* qclass, qtype */
-+  
-+  check_rrs(p, header, plen, 1, rrs, rr_found);
-+  
-+  return plen;
-+}
-+
-+/* This is used in the DNSSEC code too, hence it's exported */
-+u16 *rrfilter_desc(int type)
-+{
-+  /* List of RRtypes which include domains in the data.
-+     0 -> domain
-+     integer -> no of plain bytes
-+     -1 -> end
-+
-+     zero is not a valid RRtype, so the final entry is returned for
-+     anything which needs no mangling.
-+  */
-+  
-+  static u16 rr_desc[] = 
-+    { 
-+      T_NS, 0, -1, 
-+      T_MD, 0, -1,
-+      T_MF, 0, -1,
-+      T_CNAME, 0, -1,
-+      T_SOA, 0, 0, -1,
-+      T_MB, 0, -1,
-+      T_MG, 0, -1,
-+      T_MR, 0, -1,
-+      T_PTR, 0, -1,
-+      T_MINFO, 0, 0, -1,
-+      T_MX, 2, 0, -1,
-+      T_RP, 0, 0, -1,
-+      T_AFSDB, 2, 0, -1,
-+      T_RT, 2, 0, -1,
-+      T_SIG, 18, 0, -1,
-+      T_PX, 2, 0, 0, -1,
-+      T_NXT, 0, -1,
-+      T_KX, 2, 0, -1,
-+      T_SRV, 6, 0, -1,
-+      T_DNAME, 0, -1,
-+      0, -1 /* wildcard/catchall */
-+    }; 
-+  
-+  u16 *p = rr_desc;
-+  
-+  while (*p != type && *p != 0)
-+    while (*p++ != (u16)-1);
-+
-+  return p+1;
-+}
-+
-+int expand_workspace(unsigned char ***wkspc, int *szp, int new)
-+{
-+  unsigned char **p;
-+  int old = *szp;
-+
-+  if (old >= new+1)
-+    return 1;
-+
-+  if (new >= 100)
-+    return 0;
-+
-+  new += 5;
-+  
-+  if (!(p = whine_malloc(new * sizeof(unsigned char **))))
-+    return 0;  
-+  
-+  if (old != 0 && *wkspc)
-+    {
-+      memcpy(p, *wkspc, old * sizeof(unsigned char **));
-+      free(*wkspc);
-+    }
-+  
-+  *wkspc = p;
-+  *szp = new;
-+
-+  return 1;
-+}
--- 
-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 |   82 ++++++++++++++++++++++++++++++++++++++--------------------
- 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
-    STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
-    STAT_NEED_DS  need DS to complete validation (name is returned in keyname)
- 
--   if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
-+   If key is non-NULL, use that key, which has the algo and tag given in the params of those names,
-    otherwise find the key in the cache.
- 
--   name is unchanged on exit. keyname is used as workspace and trashed.
-+   Name is unchanged on exit. keyname is used as workspace and trashed.
- 
-    Call 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
-   return STAT_BOGUS;
- }
-  
-+
- /* The DNS packet is expected to contain the answer to a DNSKEY query.
-    Put all DNSKEYs in the answer which are valid into the cache.
-    return codes:
-@@ -1831,15 +1832,15 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- 
- /* Check signing status of name.
-    returns:
--   STAT_SECURE zone is signed.
--   STAT_INSECURE zone proved unsigned.
--   STAT_NEED_DS require DS record of name returned in keyname.
--   
-+   STAT_SECURE      zone is signed.
-+   STAT_INSECURE    zone proved unsigned.
-+   STAT_NEED_DS     require DS record of name returned in keyname.
-+   STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
-    name returned unaltered.
- */
- static int zone_status(char *name, int class, char *keyname, time_t now)
- {
--  int name_start = strlen(name);
-+  int secure_ds, name_start = strlen(name);
-   struct crec *crecp;
-   char *p;
-   
-@@ -1850,27 +1851,52 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-       if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
- 	return STAT_NEED_DS;
-       else
--	do 
--	  {
--	    if (crecp->uid == (unsigned int)class)
--	      {
--		/* F_DNSSECOK misused in DS cache records to non-existance of NS record.
--		   F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
--		   but that's because there's no NS record either, ie this isn't the start
--		   of a zone. We only prove that the DNS tree below a node is unsigned when
--		   we prove that we're at a zone cut AND there's no DS record.
--		*/	  
--		if (crecp->flags & F_NEG)
--		  {
--		    if (crecp->flags & F_DNSSECOK)
--		      return STAT_INSECURE; /* proved no DS here */
--		  }
--		else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
--		  return STAT_INSECURE; /* algo we can't use - insecure */
--	      }
--	  }
--	while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
--      
-+	{
-+	  secure_ds = 0;
-+	  
-+	  do 
-+	    {
-+	      if (crecp->uid == (unsigned int)class)
-+		{
-+		  /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
-+		     F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
-+		     but that's because there's no NS record either, ie this isn't the start
-+		     of a zone. We only prove that the DNS tree below a node is unsigned when
-+		     we prove that we're at a zone cut AND there's no DS record.
-+		  */	  
-+		  if (crecp->flags & F_NEG)
-+		    {
-+		      if (crecp->flags & F_DNSSECOK)
-+			return STAT_INSECURE; /* proved no DS here */
-+		    }
-+		  else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
-+		    return STAT_INSECURE; /* algo we can't use - insecure */
-+		  else
-+		    secure_ds = 1;
-+		}
-+	    }
-+	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
-+	}
-+
-+      if (secure_ds)
-+	{
-+	  /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
-+	     that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
-+	     one we can use. However the DNSKEY RRset may contain more than one key and
-+	     one of the other keys may use an algorithm we don't support. If that's 
-+	     the case the zone is insecure for us. */
-+	  
-+	  if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
-+	    return STAT_NEED_KEY;
-+
-+	  do 
-+	    {
-+	      if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
-+		return STAT_INSECURE;
-+	    }
-+	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
-+	}
-+
-       if (name_start == 0)
- 	break;
- 
--- 
-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  |   20 +++++++++-----------
- src/rfc1035.c |   57 +++++++++++++++++++++++++++++++++------------------------
- 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
- 	    /* Empty DS without NSECS */
- 	    if (qtype == T_DS)
- 	      return STAT_BOGUS;
--	    else
-+	    
-+	    rc = zone_status(name, qclass, keyname, now);
-+	    if (rc != STAT_SECURE)
- 	      {
--		rc = zone_status(name, qclass, keyname, now);
--		if (rc != STAT_SECURE)
--		  {
--		    if (class)
--		      *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
--		    return rc;
--		  } 
--		
--		return STAT_BOGUS; /* signed zone, no NSECs */
--	      }
-+		if (class)
-+		  *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
-+		return rc;
-+	      } 
-+	    
-+	    return STAT_BOGUS; /* signed zone, no NSECs */
- 	  }
- 
- 	  if (nsec_type == 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,
-   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
-   struct mx_srv_record *rec;
-   size_t len;
-- 
-+  
-+  if (ntohs(header->ancount) != 0 ||
-+      ntohs(header->nscount) != 0 ||
-+      ntohs(header->qdcount) == 0 || 
-+      OPCODE(header) != QUERY )
-+    return 0;
-+  
-   /* Don't return AD set if checking disabled. */
-   if (header->hb4 & HB4_CD)
-     sec_data = 0;
-@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   *ad_reqd = header->hb4 & HB4_AD;
-   *do_bit = 0;
- 
--  /* If there is an RFC2671 pseudoheader then it will be overwritten by
-+  /* If there is an  additional data section then it will be overwritten by
-      partial replies, so we have to do a dry run to see if we can answer
--     the query. We check to see if the do bit is set, if so we always
--     forward rather than answering from the cache, which doesn't include
--     security information, unless we're in DNSSEC validation mode. */
-+     the query. */
- 
--  if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
--    { 
--      unsigned short flags;
--      
--      have_pseudoheader = 1;
-+  if (ntohs(header->arcount) != 0)
-+    {
-+      dryrun = 1;
- 
--      pheader += 4; /* udp size, ext_rcode */
--      GETSHORT(flags, pheader);
--      
--      if ((sec_reqd = flags & 0x8000))
--	{
--	  *do_bit = 1;/* do bit */ 
--	  *ad_reqd = 1;
-+      /* If there's an additional section, there might be an EDNS(0) pseudoheader */
-+      if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
-+	{ 
-+	  unsigned short flags;
-+	  
-+	  have_pseudoheader = 1;
-+	  
-+	  pheader += 4; /* udp size, ext_rcode */
-+	  GETSHORT(flags, pheader);
-+	  
-+	  if ((sec_reqd = flags & 0x8000))
-+	    {
-+	      *do_bit = 1;/* do bit */ 
-+	      *ad_reqd = 1;
-+	    }
- 	}
--
--      dryrun = 1;
-     }
- 
--  if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
--    return 0;
--  
-   for (rec = daemon->mxnames; rec; rec = rec->next)
-     rec->offset = 0;
-   
-@@ -1730,8 +1735,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 		}
- 	      else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
- 		{
--		  /* Don't use cache when DNSSEC data required. */
--		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
-+		  /* Don't use cache when DNSSEC data required, unless we know that
-+		     the zone is unsigned, which implies that we're doing
-+		     validation. */
-+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
-+		      !sec_reqd || 
-+		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
- 		    {
- 		      do 
- 			{ 
--- 
-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 |  207 +++++++++++++++++++++++++---------------------------------
- 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)
-     }
- }
- 
--/* Find all the NSEC or NSEC3 records in a reply.
--   return 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)
--{
--  static unsigned char **nsecset = NULL;
--  static int nsecset_sz = 0;
--  
--  int type_found = 0;
--  unsigned char *p = skip_questions(header, plen);
--  int type, class, rdlen, i, nsecs_found;
--
--  /* Move to NS section */
--  if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
--    return 0;
--  
--  for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
--    {
--      unsigned char *pstart = p;
--      
--      if (!(p = skip_name(p, header, plen, 10)))
--	return 0;
--      
--      GETSHORT(type, p); 
--      GETSHORT(class, p);
--      p += 4; /* TTL */
--      GETSHORT(rdlen, p);
--
--      if (class == class_reqd && (type == T_NSEC || type == T_NSEC3))
--	{
--	  /* No mixed NSECing 'round here, thankyouverymuch */
--	  if (type_found == T_NSEC && type == T_NSEC3)
--	    return 0;
--	  if (type_found == T_NSEC3 && type == T_NSEC)
--	    return 0;
--
--	  type_found = type;
--
--	  if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
--	    return 0; 
--	  
--	  nsecset[nsecs_found++] = pstart;
--	}
--      
--      if (!ADD_RDLEN(header, p, plen, rdlen))
--	return 0;
--    }
--  
--  *nsecsetp = nsecset;
--  *nsecsetl = nsecs_found;
--  
--  return type_found;
--}
--
- static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
- 				    char *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
-     {
-       p = nsecs[i];
-       if (!extract_name(header, plen, &p, workspace1, 1, 10))
--	return STAT_BOGUS;
-+	return 0;
-       p += 8; /* class, type, TTL */
-       GETSHORT(rdlen, p);
-       psave = p;
-       if (!extract_name(header, plen, &p, workspace2, 1, 10))
--	return STAT_BOGUS;
-+	return 0;
-       
-       rc = hostname_cmp(workspace1, name);
-       
-@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
- 	{
- 	  /* 4035 para 5.4. Last sentence */
- 	  if (type == T_NSEC || type == T_RRSIG)
--	    return STAT_SECURE;
-+	    return 1;
- 
- 	  /* NSEC with the same name as the RR we're testing, check
- 	     that the type in question doesn't appear in the type map */
-@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
- 	      /* A CNAME answer would also be valid, so if there's a CNAME is should 
- 		 have been returned. */
- 	      if ((p[2] & (0x80 >> T_CNAME)) != 0)
--		return STAT_BOGUS;
-+		return 0;
- 	      
- 	      /* If the SOA bit is set for a DS record, then we have the
- 		 DS from the wrong side of the delegation. */
- 	      if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
--		return STAT_BOGUS;
-+		return 0;
- 	    }
- 
- 	  while (rdlen >= 2)
- 	    {
- 	      if (!CHECK_LEN(header, p, plen, rdlen))
--		return STAT_BOGUS;
-+		return 0;
- 	      
- 	      if (p[0] == type >> 8)
- 		{
- 		  /* Does the NSEC say our type exists? */
- 		  if (offset < p[1] && (p[offset+2] & mask) != 0)
--		    return STAT_BOGUS;
-+		    return 0;
- 		  
- 		  break; /* finshed checking */
- 		}
-@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
- 	      p +=  p[1];
- 	    }
- 	  
--	  return STAT_SECURE;
-+	  return 1;
- 	}
-       else if (rc == -1)
- 	{
- 	  /* Normal case, name falls between NSEC name and next domain name,
- 	     wrap around case, name falls between NSEC name (rc == -1) and end */
- 	  if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
--	    return STAT_SECURE;
-+	    return 1;
- 	}
-       else 
- 	{
- 	  /* wrap around case, name falls between start and next domain name */
- 	  if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
--	    return STAT_SECURE;
-+	    return 1;
- 	}
-     }
-   
--  return STAT_BOGUS;
-+  return 0;
- }
- 
- /* 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
-   for (i = 0; i < nsec_count; i++)
-     {
-       if (!(p = skip_name(nsecs[i], header, plen, 15)))
--	return STAT_BOGUS; /* bad packet */
-+	return 0; /* bad packet */
-       
-       p += 10; /* type, class, TTL, rdlen */
-       algo = *p++;
-@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- 
-   /* No usable NSEC3s */
-   if (i == nsec_count)
--    return STAT_BOGUS;
-+    return 0;
- 
-   p++; /* flags */
-   GETSHORT (iterations, p);
-   salt_len = *p++;
-   salt = p;
-   if (!CHECK_LEN(header, salt, plen, salt_len))
--    return STAT_BOGUS; /* bad packet */
-+    return 0; /* bad packet */
-     
-   /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
-   for (i = 0; i < nsec_count; i++)
-@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       nsecs[i] = NULL; /* Speculative, will be restored if OK. */
-       
-       if (!(p = skip_name(nsec3p, header, plen, 15)))
--	return STAT_BOGUS; /* bad packet */
-+	return 0; /* bad packet */
-       
-       p += 10; /* type, class, TTL, rdlen */
-       
-@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- 	continue;
-       
-       if (!CHECK_LEN(header, p, plen, salt_len))
--	return STAT_BOGUS; /* bad packet */
-+	return 0; /* bad packet */
- 
-       if (memcmp(p, salt, salt_len) != 0)
- 	continue;
-@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- 
-   /* Algo is checked as 1 above */
-   if (!(hash = hash_find("sha1")))
--    return STAT_BOGUS;
-+    return 0;
- 
-   if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
--    return STAT_BOGUS;
-+    return 0;
-   
-   if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
--    return STAT_SECURE;
-+    return 1;
- 
-   /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3" 
-      or 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
- 	break;
- 
-       if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
--	return STAT_BOGUS;
-+	return 0;
-       
-       for (i = 0; i < nsec_count; i++)
- 	if ((p = nsecs[i]))
- 	  {
- 	    if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
- 		!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
--	      return STAT_BOGUS;
-+	      return 0;
- 	  
- 	    if (digest_len == base32_len &&
- 		memcmp(digest, workspace2, digest_len) == 0)
-@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-   while ((closest_encloser = strchr(closest_encloser, '.')));
-   
-   if (!closest_encloser)
--    return STAT_BOGUS;
-+    return 0;
-   
-   /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
-   if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
--    return STAT_BOGUS;
-+    return 0;
- 
-   if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
--    return STAT_BOGUS;
-+    return 0;
-   
-   /* Finally, check that there's no seat of wildcard synthesis */
-   if (!wildname)
-     {
-       if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
--	return STAT_BOGUS;
-+	return 0;
-       
-       wildcard--;
-       *wildcard = '*';
-       
-       if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
--	return STAT_BOGUS;
-+	return 0;
-       
-       if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
--	return STAT_BOGUS;
-+	return 0;
-     }
-   
--  return STAT_SECURE;
-+  return 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)
-+{
-+  static unsigned char **nsecset = NULL;
-+  static int nsecset_sz = 0;
-+  
-+  int type_found = 0;
-+  unsigned char *p = skip_questions(header, plen);
-+  int type, class, rdlen, i, nsecs_found;
-+  
-+  /* Move to NS section */
-+  if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
-+    return 0;
-+  
-+  for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
-+    {
-+      unsigned char *pstart = p;
-+      
-+      if (!(p = skip_name(p, header, plen, 10)))
-+	return 0;
-+      
-+      GETSHORT(type, p); 
-+      GETSHORT(class, p);
-+      p += 4; /* TTL */
-+      GETSHORT(rdlen, p);
-+
-+      if (class == qclass && (type == T_NSEC || type == T_NSEC3))
-+	{
-+	  /* No mixed NSECing 'round here, thankyouverymuch */
-+	  if (type_found != 0 && type_found != type)
-+	    return 0;
-+
-+	  type_found = type;
-+
-+	  if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
-+	    return 0; 
-+	  
-+	  nsecset[nsecs_found++] = pstart;
-+	}
-+      
-+      if (!ADD_RDLEN(header, p, plen, rdlen))
-+	return 0;
-+    }
-+  
-+  if (type_found == T_NSEC)
-+    return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
-+  else
-+    return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
- }
- 
- /* Check signing status of name.
-@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
-   static unsigned char **targets = NULL;
-   static int target_sz = 0;
- 
--  unsigned char *ans_start, *p1, *p2, **nsecs;
-+  unsigned char *ans_start, *p1, *p2;
-   int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
--  int i, j, rc, nsec_count;
--  int nsec_type;
-+  int i, j, rc;
- 
-   if (neganswer)
-     *neganswer = 0;
-@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 			  targets[j] = NULL;
- 		      }
- 			    
--		  if (rc == STAT_SECURE_WILDCARD)
--		    {
--		      /* An attacker replay a wildcard answer with a different
--			 answer and overlay a genuine RR. To prove this
--			 hasn't happened, the answer must prove that
--			 the gennuine record doesn't exist. Check that here. */
--		      if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
--			return STAT_BOGUS; /* No NSECs or bad packet */
--		      
--		      /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. Since the check
--			 below returns either SECURE or BOGUS, that's not a problem. If the RRsets later fail
--			 we'll return BOGUS then. */
--
--		      if (nsec_type == T_NSEC)
--			rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
--		      else
--			rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
--						       keyname, name, type1, wildname, NULL);
--		      
--		      if (rc == STAT_BOGUS)
--			return rc;
--		    } 
-+		   /* An attacker replay a wildcard answer with a different
-+		      answer and overlay a genuine RR. To prove this
-+		      hasn't happened, the answer must prove that
-+		      the gennuine record doesn't exist. Check that here. 
-+		      Note that we may not yet have validated the NSEC/NSEC3 RRsets. 
-+		      That's not a problem since if the RRsets later fail
-+		      we'll return BOGUS then. */
-+		  if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
-+		    return STAT_BOGUS;
- 		}
- 	    }
- 	}
-@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 
- 	/* For anything other than a DS record, this situation is OK if either
- 	   the answer is in an unsigned zone, or there's a NSEC records. */
--	if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
-+	if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
- 	  {
- 	    /* Empty DS without NSECS */
- 	    if (qtype == T_DS)
- 	      return STAT_BOGUS;
- 	    
--	    rc = zone_status(name, qclass, keyname, now);
--	    if (rc != STAT_SECURE)
-+	    if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
- 	      {
- 		if (class)
- 		  *class = 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
- 	    
- 	    return STAT_BOGUS; /* signed zone, no NSECs */
- 	  }
--
--	  if (nsec_type == T_NSEC)
--	  rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
--	else
--	  rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
--
--	if (rc != STAT_SECURE)
--	  return rc;
-       }
-   
-   return STAT_SECURE;
--- 
-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=utf8
-Content-Transfer-Encoding: 8bit
-
-Thanks to Michał Kępień for spotting this.
----
- src/dnssec.c |   34 +++++++++++++++++-----------------
- 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.
-    Put all DNSKEYs in the answer which are valid into the cache.
-    return codes:
--         STAT_OK           Done, key(s) in cache.
--	 STAT_BOGUS        No DNSKEYs found, which  can be validated with DS,
--	                   or self-sign for DNSKEY RRset is not valid, bad packet.
--	 STAT_NEED_DS      DS records to validate a key not found, name in keyname 
--	 STAT_NEED_DNSKEY  DNSKEY records to validate a key not found, name in keyname 
-+         STAT_OK        Done, key(s) in cache.
-+	 STAT_BOGUS     No DNSKEYs found, which  can be validated with DS,
-+	                or self-sign for DNSKEY RRset is not valid, bad packet.
-+	 STAT_NEED_DS   DS records to validate a key not found, name in keyname 
-+	 STAT_NEED_KEY  DNSKEY records to validate a key not found, name in keyname 
- */
- 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
- 		}
- 	      
- 	      p = psave;
--	      
--	      if (!ADD_RDLEN(header, p, plen, rdlen))
--		return STAT_BOGUS; /* bad packet */
- 	    }
--	  
--	  cache_end_insert();
-+	  if (!ADD_RDLEN(header, p, plen, rdlen))
-+	    return STAT_BOGUS; /* bad packet */
- 	}
-+
-+      cache_end_insert();
-+
-     }
-   else
-     {
-@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
- 
- /* Check signing status of name.
-    returns:
--   STAT_SECURE      zone is signed.
--   STAT_INSECURE    zone proved unsigned.
--   STAT_NEED_DS     require DS record of name returned in keyname.
--   STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
-+   STAT_SECURE   zone is signed.
-+   STAT_INSECURE zone proved unsigned.
-+   STAT_NEED_DS  require DS record of name returned in keyname.
-+   STAT_NEED_KEY require DNSKEY record of name returned in keyname.
-    name 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
- 		      if (rc == STAT_SECURE)
- 			rc = STAT_BOGUS;
- 		       if (class)
--			 *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-+			 *class = class1; /* Class for NEED_DS or NEED_KEY */
- 		    }
- 		  else 
- 		    rc = STAT_INSECURE; 
-@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 		{
- 		  /* Zone is insecure, don't need to validate RRset */
- 		  if (class)
--		    *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
-+		    *class = class1; /* Class for NEED_DS or NEED_KEY */
- 		  return rc;
- 		} 
- 	      
-@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- 	    if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
- 	      {
- 		if (class)
--		  *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
-+		  *class = qclass; /* Class for NEED_DS or NEED_KEY */
- 		return rc;
- 	      } 
- 	    
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch b/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
deleted file mode 100644
index abcae5c..0000000
--- a/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
+++ /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 |   52 +++++++++++++++++++++++++++++++++++++---------------
- 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)
-     case 8: return "sha256";
-     case 10: return "sha512";
-     case 12: return "gosthash94";
--#ifndef NO_NETTLE_ECC
-     case 13: return "sha256";
-     case 14: return "sha384";
--#endif
-+
-     default: return NULL;
-     }
- }
-@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char
- }
-   
- static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
--			      unsigned char *digest, int algo)
-+			      unsigned char *digest, size_t digest_len, int algo)
- {
-   unsigned char *p;
-   size_t exp_len;
-   
-   static struct rsa_public_key *key = NULL;
-   static mpz_t sig_mpz;
-+
-+  (void)digest_len;
-   
-   if (key == NULL)
-     {
-@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len,
- }  
- 
- static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
--			      unsigned char *digest, int algo)
-+			      unsigned char *digest, size_t digest_len, int algo)
- {
-   unsigned char *p;
-   unsigned int t;
-@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len,
-   static struct dsa_public_key *key = NULL;
-   static struct dsa_signature *sig_struct;
-   
-+  (void)digest_len;
-+
-   if (key == NULL)
-     {
-       if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) || 
-@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
- } 
- #endif 
- 
--static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
--		  unsigned 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,
-+				    unsigned char *digest, size_t digest_len, int algo)
- {
--  (void)digest_len;
--
-+    
-+  /* Enure at runtime that we have support for this digest */
-+  if (!hash_find(algo_digest_name(algo)))
-+    return NULL;
-+  
-+  /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
-   switch (algo)
-     {
-     case 1: case 5: case 7: case 8: case 10:
--      return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
-+      return dnsmasq_rsa_verify;
-       
-     case 3: case 6: 
--      return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
-+      return dnsmasq_dsa_verify;
-  
- #ifndef NO_NETTLE_ECC   
-     case 13: case 14:
--      return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
-+      return dnsmasq_ecdsa_verify;
- #endif
-     }
-   
--  return 0;
-+  return NULL;
-+}
-+
-+static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
-+		  unsigned char *digest, size_t digest_len, int algo)
-+{
-+
-+  int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
-+	      unsigned char *digest, size_t digest_len, int algo);
-+  
-+  func = verify_func(algo);
-+  
-+  if (!func)
-+    return 0;
-+
-+  return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
- }
- 
- /* 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
- 	      if (check_date_range(sig_inception, sig_expiration) &&
- 		  labels <= name_labels &&
- 		  type_covered == type && 
--		  algo_digest_name(algo))
-+		  verify_func(algo))
- 		{
- 		  if (!expand_workspace(&sigs, &sig_sz, sigidx))
- 		    return 0; 
-@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
- 		      if (crecp->flags & F_DNSSECOK)
- 			return STAT_INSECURE; /* proved no DS here */
- 		    }
--		  else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
-+		  else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
- 		    return STAT_INSECURE; /* algo we can't use - insecure */
- 		  else
- 		    secure_ds = 1;
-@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
- 
- 	  do 
- 	    {
--	      if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
-+	      if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
- 		return STAT_INSECURE;
- 	    }
- 	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
--- 
-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     |    8 ++-
- src/dnsmasq.h  |    7 ++-
- src/dnssec.c   |    1 -
- src/forward.c  |  184 ++++++++++++++++++++++++++++++++++++++++----------------
- src/netlink.c  |    3 +-
- src/rfc1035.c  |   81 +++++++------------------
- src/rrfilter.c |    2 +-
- 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)
- }
- 
- 
--size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) 
-+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, 
-+		   int local_query, int do_bit, int have_pseudoheader) 
- {
-   char *name = daemon->namebuff;
-   unsigned char *p, *ansp;
-@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
-   header->ancount = htons(anscount);
-   header->nscount = htons(authcount);
-   header->arcount = htons(0);
-+
-+  /* Advertise our packet size limit in our reply */
-+  if (have_pseudoheader)
-+    return add_pseudoheader(header,  ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
-+
-   return ansp - (unsigned char *)header;
- }
-   
-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,
- 		      int no_cache, int secure, int *doctored);
- size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
- 		      struct in_addr local_addr, struct in_addr local_netmask, 
--		      time_t now, int *ad_reqd, int *do_bit);
-+		      time_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, 
- 			     struct 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, 
- 		  unsigned char *pheader, size_t hlen);
-+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-+			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
- size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
- size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
- #ifdef HAVE_DNSSEC
-@@ -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, 
--		   time_t now, union mysockaddr *peer_addr, int local_query);
-+		   time_t now, union mysockaddr *peer_addr, int local_query,
-+		   int do_bit, int have_pseudoheader);
- int in_zone(struct auth_zone *zone, char *name, char **cut);
- #endif
- 
-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)
-     case 12: return "gosthash94";
-     case 13: return "sha256";
-     case 14: return "sha384";
--
-     default: return NULL;
-     }
- }
-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,
-   void *hash = &crc;
- #endif
-  unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
-- unsigned char *pheader;
- 
-  (void)do_bit;
- 
-@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 	 there's no point retrying the query, retry the key query instead...... */
-       if (forward->blocking_query)
- 	{
--	  int fd;
-+	  int fd, is_sign;
-+	  unsigned char *pheader;
- 	  
- 	  forward->flags &= ~FREC_TEST_PKTSZ;
- 	  
-@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 	  blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
- 	  plen = forward->stash_len;
- 	  
--	  if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
--	    PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader);
-+	  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
-+	    PUTSHORT(SAFE_PKTSZ, pheader);
- 
- 	  if (forward->sentto->addr.sa.sa_family == AF_INET) 
- 	    log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
-@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-       forward->log_id = daemon->log_id;
-       
-       if (option_bool(OPT_ADD_MAC))
--	plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
--      
-+	{
-+	  size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
-+	  if (new != plen)
-+	    {
-+	      plen = new;
-+	      forward->flags |= FREC_ADDED_PHEADER;
-+	    }
-+	}
-+
-       if (option_bool(OPT_CLIENT_SUBNET))
- 	{
- 	  size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); 
- 	  if (new != plen)
- 	    {
- 	      plen = new;
--	      forward->flags |= FREC_HAS_SUBNET;
-+	      forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
- 	    }
- 	}
- 
- #ifdef HAVE_DNSSEC
-       if (option_bool(OPT_DNSSEC_VALID))
- 	{
--	  size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
-+	  size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
- 	 
-+	  if (new != plen)
-+	    forward->flags |= FREC_ADDED_PHEADER;
-+
-+	  plen = new;
-+	      
- 	  /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
- 	     this allows it to select auth servers when one is returning bad data. */
- 	  if (option_bool(OPT_DNSSEC_DEBUG))
- 	    header->hb4 |= HB4_CD;
- 
--	  if (new_plen != plen)
--	    forward->flags |= FREC_ADDED_PHEADER;
--
--	  plen = new_plen;
- 	}
- #endif
-       
-@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 		    }
- #endif
- 		}
--
--	      if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
--		PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader);
- 	      
-+#ifdef HAVE_DNSSEC
-+	      if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
-+		{
-+		  /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
-+		     packet size to 512. But that won't provide space for the RRSIGS in many cases.
-+		     The RRSIGS will be stripped out before the answer goes back, so the packet should
-+		     shrink again. So, if we added a do-bit, bump the udp packet size to the value
-+		     known to be OK for this server. Maybe check returned size after stripping and set
-+		     the truncated bit? */		  
-+		  unsigned char *pheader;
-+		  int is_sign;
-+		  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
-+		    PUTSHORT(start->edns_pktsz, pheader);
-+		}
-+#endif
-+
- 	      if (retry_send(sendto(fd, (char *)header, plen, 0,
- 				    &start->addr.sa,
- 				    sa_len(&start->addr))))
-@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     }
- #endif
-   
--  /* If upstream is advertising a larger UDP packet size
--     than we allow, trim it so that we don't get overlarge
--     requests for the client. We can't do this for signed packets. */
--
-   if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
-     {
--      unsigned short udpsz;
--      unsigned char *psave = sizep;
--      
--      GETSHORT(udpsz, sizep);
--
--      if (!is_sign && udpsz > daemon->edns_pktsz)
--	PUTSHORT(daemon->edns_pktsz, psave);
--      
-       if (check_subnet && !check_source(header, plen, pheader, query_source))
- 	{
- 	  my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
- 	  return 0;
- 	}
-       
--      if (added_pheader)
-+      if (!is_sign)
- 	{
--	  pheader = 0; 
--	  header->arcount = htons(0);
-+	  if (added_pheader)
-+	    {
-+	      /* client didn't send EDNS0, we added one, strip it off before returning answer. */
-+	      n = rrfilter(header, n, 0);
-+	      pheader = NULL;
-+	    }
-+	  else
-+	    {
-+	      /* If upstream is advertising a larger UDP packet size
-+		 than we allow, trim it so that we don't get overlarge
-+		 requests for the client. We can't do this for signed packets. */
-+	      unsigned short udpsz;
-+	      unsigned char *psave = sizep;
-+	      
-+	      GETSHORT(udpsz, sizep);
-+	      if (udpsz > daemon->edns_pktsz)
-+		PUTSHORT(daemon->edns_pktsz, psave);
-+	    }
- 	}
-     }
-   
-@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     }
- 
-   if (option_bool(OPT_DNSSEC_VALID))
--    header->hb4 &= ~HB4_AD;
--  
--  if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
--    header->hb4 |= HB4_AD;
--
--  /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
--  if (!do_bit)
--    n = rrfilter(header, n, 1);
-+    {
-+      header->hb4 &= ~HB4_AD;
-+      
-+      if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
-+	header->hb4 |= HB4_AD;
-+      
-+      /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
-+      if (!do_bit)
-+	n = rrfilter(header, n, 1);
-+    }
- #endif
- 
-   /* do this after extract_addresses. Ensure NODATA reply and remove
-@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now)
- 	  if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
- 	    {
- 	      header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
--	      header->hb4 &= ~(HB4_RA | HB4_RCODE);
--	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
-+	      header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
-+	      if (forward->flags |= FREC_CHECKING_DISABLED)
-+		header->hb4 |= HB4_CD;
-+	      if (forward->flags |= FREC_AD_QUESTION)
-+		header->hb4 |= HB4_AD;
-+	      if (forward->flags & FREC_DO_QUESTION)
-+		add_do_bit(header, nn,  (char *)pheader + plen);
-+	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
- 	      return;
- 	    }
- 	}
-@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now)
- {
-   struct dns_header *header = (struct dns_header *)daemon->packet;
-   union mysockaddr source_addr;
--  unsigned short type;
-+  unsigned char *pheader;
-+  unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
-   struct all_addr dst_addr;
-   struct in_addr netmask, dst_addr_4;
-   size_t m;
-   ssize_t n;
--  int if_index = 0, auth_dns = 0;
-+  int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
- #ifdef HAVE_AUTH
-   int local_auth = 0;
- #endif
-@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now)
- #endif
-     }
-   
-+  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
-+    { 
-+      unsigned short flags;
-+      
-+      have_pseudoheader = 1;
-+      GETSHORT(udp_size, pheader);
-+      pheader += 2; /* ext_rcode */
-+      GETSHORT(flags, pheader);
-+      
-+      if (flags & 0x8000)
-+	do_bit = 1;/* do bit */ 
-+	
-+      /* If the client provides an EDNS0 UDP size, use that to limit our reply.
-+	 (bounded by the maximum configured). If no EDNS0, then it
-+	 defaults to 512 */
-+      if (udp_size > daemon->edns_pktsz)
-+	udp_size = daemon->edns_pktsz;
-+    }
-+
- #ifdef HAVE_AUTH
-   if (auth_dns)
-     {
--      m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth);
-+      m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, 
-+		      local_auth, do_bit, have_pseudoheader);
-       if (m >= 1)
- 	{
- 	  send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
-@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now)
-   else
- #endif
-     {
--      int ad_reqd, do_bit;
--      m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, 
--			 dst_addr_4, netmask, now, &ad_reqd, &do_bit);
-+      int ad_reqd = do_bit;
-+       /* RFC 6840 5.7 */
-+      if (header->hb4 & HB4_AD)
-+	ad_reqd = 1;
-+
-+      m = answer_request(header, ((char *) header) + udp_size, (size_t)n, 
-+			 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
-       
-       if (m >= 1)
- 	{
-@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now,
- #ifdef HAVE_AUTH
-   int local_auth = 0;
- #endif
--  int checking_disabled, ad_question, do_bit, added_pheader = 0;
-+  int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
-   int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
-   size_t m;
-   unsigned short qtype;
-@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now,
-   union mysockaddr peer_addr;
-   socklen_t peer_len = sizeof(union mysockaddr);
-   int query_count = 0;
-+  unsigned char *pheader;
- 
-   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
-     return packet;
-@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now,
-       else
- 	dst_addr_4.s_addr = 0;
-       
-+      do_bit = 0;
-+
-+      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
-+	{ 
-+	  unsigned short flags;
-+	  
-+	  have_pseudoheader = 1;
-+	  pheader += 4; /* udp_size, ext_rcode */
-+	  GETSHORT(flags, pheader);
-+      
-+	  if (flags & 0x8000)
-+	    do_bit = 1;/* do bit */ 
-+	}
-+
- #ifdef HAVE_AUTH
-       if (auth_dns)
--	m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
-+	m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, 
-+			local_auth, do_bit, have_pseudoheader);
-       else
- #endif
- 	{
--	  /* m > 0 if answered from cache */
--	  m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
--			     dst_addr_4, netmask, now, &ad_question, &do_bit);
-+	   int ad_reqd = do_bit;
-+	   /* RFC 6840 5.7 */
-+	   if (header->hb4 & HB4_AD)
-+	     ad_reqd = 1;
-+	   
-+	   /* m > 0 if answered from cache */
-+	   m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
-+			      dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
- 	  
- 	  /* Do this by steam now we're not in the select() loop */
- 	  check_log_writer(1); 
-@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 			    }
- 			  
- #ifdef HAVE_DNSSEC
-+			  added_pheader = 0;			  
- 			  if (option_bool(OPT_DNSSEC_VALID))
- 			    {
- 			      size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
-@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 
- 		      m = process_reply(header, now, last_server, (unsigned int)m, 
- 					option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
--					ad_question, do_bit, added_pheader, check_subnet, &peer_addr); 
-+					ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); 
- 		      
- 		      break;
- 		    }
-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)())
- 		rta = RTA_NEXT(rta, len1);
- 	      }
- 
--	    if (inaddr && mac && callback_ok)
-+	    if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
-+		inaddr && mac && callback_ok)
- 	      if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
- 		callback_ok = 0;
- 	  }
-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 {
-   union mysockaddr *l3;
- };
-  
--static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
--			       int optno, unsigned char *opt, size_t optlen, int set_do)
-+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-+			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
- { 
-   unsigned char *lenp, *datap, *p;
-   int rdlen, is_sign;
-@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
- 	return plen;
-       *p++ = 0; /* empty name */
-       PUTSHORT(T_OPT, p);
--      PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
-+      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
-       PUTSHORT(0, p);    /* extended RCODE and version */
-       PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
-       lenp = p;
-@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
-   if (!match)
-     return 1; /* continue */
- 
--  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit,  EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
-+  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
-   
-   return 0; /* done */
- }	      
-@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
- {
-   struct macparm parm;
-      
--/* Must have an existing pseudoheader as the only ar-record, 
--   or have no ar-records. Must also not be signed */
--   
--  if (ntohs(header->arcount) > 1)
--    return plen;
--
-   parm.header = header;
-   parm.limit = (unsigned char *)limit;
-   parm.plen = plen;
-@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
-   struct subnet_opt opt;
-   
-   len = calc_subnet_opt(&opt, source);
--  return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
- }
- 
- #ifdef HAVE_DNSSEC
- size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
- {
--  return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
- }
- #endif
- 
-@@ -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,  
- 		      struct in_addr local_addr, struct in_addr local_netmask, 
--		      time_t now, int *ad_reqd, int *do_bit) 
-+		      time_t now, int ad_reqd, int do_bit, int have_pseudoheader) 
- {
-   char *name = daemon->namebuff;
--  unsigned char *p, *ansp, *pheader;
-+  unsigned char *p, *ansp;
-   unsigned int qtype, qclass;
-   struct all_addr addr;
-   int nameoffset;
-   unsigned short flag;
-   int q, ans, anscount = 0, addncount = 0;
--  int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
-+  int dryrun = 0;
-   struct crec *crecp;
-   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
-   struct mx_srv_record *rec;
-@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   if (header->hb4 & HB4_CD)
-     sec_data = 0;
-   
--  /* RFC 6840 5.7 */
--  *ad_reqd = header->hb4 & HB4_AD;
--  *do_bit = 0;
--
-   /* If there is an  additional data section then it will be overwritten by
-      partial replies, so we have to do a dry run to see if we can answer
-      the query. */
--
-   if (ntohs(header->arcount) != 0)
--    {
--      dryrun = 1;
--
--      /* If there's an additional section, there might be an EDNS(0) pseudoheader */
--      if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
--	{ 
--	  unsigned short flags;
--	  
--	  have_pseudoheader = 1;
--	  
--	  pheader += 4; /* udp size, ext_rcode */
--	  GETSHORT(flags, pheader);
--	  
--	  if ((sec_reqd = flags & 0x8000))
--	    {
--	      *do_bit = 1;/* do bit */ 
--	      *ad_reqd = 1;
--	    }
--	}
--    }
-+    dryrun = 1;
- 
-   for (rec = daemon->mxnames; rec; rec = rec->next)
-     rec->offset = 0;
-@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-       GETSHORT(qtype, p); 
-       GETSHORT(qclass, p);
- 
--      /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
--	 not set. */
--      if (qtype == T_ANY)
--	*do_bit = 1;
--
-       ans = 0; /* have we answered this question */
-       
-       if (qtype == T_TXT || qtype == T_ANY)
-@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 		     the zone is unsigned, which implies that we're doing
- 		     validation. */
- 		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
--		      !sec_reqd || 
-+		      !do_bit || 
- 		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
- 		    {
- 		      do 
-@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 		    }
- 
- 		  /* If the client asked for DNSSEC  don't use cached data. */
--		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
-+		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
- 		    do
- 		      { 
- 			/* 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,
- 			
- 			if (crecp->flags & F_NEG)
- 			  {
--			    /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
--			       is cached and the client wants DNSSEC, forward rather than answering from the cache */
--			    if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
--			      {
--				ans = 1;
--				auth = 0;
--				if (crecp->flags & F_NXDOMAIN)
--				  nxdomain = 1;
--				if (!dryrun)
--				  log_query(crecp->flags, name, NULL, NULL);
--			      }
-+			    ans = 1;
-+			    auth = 0;
-+			    if (crecp->flags & F_NXDOMAIN)
-+			      nxdomain = 1;
-+			    if (!dryrun)
-+			      log_query(crecp->flags, name, NULL, NULL);
- 			  }
- 			else 
- 			  {
-@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- 
-   len = ansp - (unsigned char *)header;
-   
-+  /* Advertise our packet size limit in our reply */
-   if (have_pseudoheader)
--    len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
-+    len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
-   
--  if (*ad_reqd && sec_data)
-+  if (ad_reqd && sec_data)
-     header->hb4 |= HB4_AD;
-   else
-     header->hb4 &= ~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)
-   for (p = rrs[0], i = 1; i < rr_found; i += 2)
-     {
-       unsigned char *start = rrs[i];
--      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
-+      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
-       
-       memmove(p, start, end-start);
-       p += end-start;
--- 
-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 |  128 +++++++++++++++++++++++++++++-----------------------------
- 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)
-     default: return NULL;
-     }
- }
--      
-+  
-+/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
-+static char *nsec3_digest_name(int digest)
-+{
-+  switch (digest)
-+    {
-+    case 1: return "sha1";
-+    default: return NULL;
-+    }
-+}
-+ 
- /* 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
-   static int rrset_sz = 0, sig_sz = 0; 
-   unsigned char *p;
-   int rrsetidx, sigidx, j, rdlen, res;
--  int name_labels = count_labels(name); /* For 4035 5.3.2 check */
-   int gotkey = 0;
- 
-   if (!(p = skip_questions(header, plen)))
-@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
-        j != 0; j--) 
-     {
-       unsigned char *pstart, *pdata;
--      int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
-+      int stype, sclass, type_covered;
- 
-       pstart = p;
-       
-@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
- 		return 0; /* bad packet */ 
- 	      
- 	      GETSHORT(type_covered, p);
--	      algo = *p++;
--	      labels = *p++;
--	      p += 4; /* orig_ttl */
--	      GETLONG(sig_expiration, p);
--	      GETLONG(sig_inception, p);
--	      p += 2; /* key_tag */
-+	      p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
- 	      
- 	      if (gotkey)
- 		{
-@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
- 		    }
- 		}
- 		  
--	      /* Don't count signatures for algos we don't support */
--	      if (check_date_range(sig_inception, sig_expiration) &&
--		  labels <= name_labels &&
--		  type_covered == type && 
--		  verify_func(algo))
-+	      
-+	      if (type_covered == type)
- 		{
- 		  if (!expand_workspace(&sigs, &sig_sz, sigidx))
- 		    return 0; 
-@@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- 			  char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
- {
-   unsigned char *p;
--  int rdlen, j, name_labels;
-+  int rdlen, j, name_labels, sig_expiration, sig_inception;
-   struct crec *crecp = NULL;
-   int algo, labels, orig_ttl, key_tag;
-   u16 *rr_desc = rrfilter_desc(type);
-@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
-       algo = *p++;
-       labels = *p++;
-       GETLONG(orig_ttl, p);
--      p += 8; /* sig_expiration, sig_inception already checked */
-+      GETLONG(sig_expiration, p);
-+      GETLONG(sig_inception, p);
-       GETSHORT(key_tag, p);
-       
-       if (!extract_name(header, plen, &p, keyname, 1, 0))
- 	return STAT_BOGUS;
- 
--      if (!(hash = hash_find(algo_digest_name(algo))) ||
-+      if (!check_date_range(sig_inception, sig_expiration) ||
-+	  labels > name_labels ||
-+	  !(hash = hash_find(algo_digest_name(algo))) ||
- 	  !hash_init(hash, &ctx, &digest))
- 	continue;
-       
-@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 		      else
- 			{
- 			  a.addr.keytag = keytag;
--			  log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
-+			  if (verify_func(algo))
-+			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
-+			  else
-+			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
- 			  
- 			  recp1->addr.key.keylen = rdlen - 4;
- 			  recp1->addr.key.keydata = key;
-@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
- 		  else
- 		    {
- 		      a.addr.keytag = keytag;
--		      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+		      if (hash_find(ds_digest_name(digest)) && verify_func(algo))
-+			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+		      else
-+			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
-+		      
- 		      crecp->addr.ds.digest = digest;
- 		      crecp->addr.ds.keydata = key;
- 		      crecp->addr.ds.algo = algo;
-@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-     *nons = 1;
-   
-   /* Look though the NSEC3 records to find the first one with 
--     an algorithm we support (currently only algo == 1).
-+     an algorithm we support.
- 
-      Take the algo, iterations, and salt of that record
-      as the ones we're going to use, and prune any 
-@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       p += 10; /* type, class, TTL, rdlen */
-       algo = *p++;
-       
--      if (algo == 1)
-+      if ((hash = hash_find(nsec3_digest_name(algo))))
- 	break; /* known algo */
-     }
- 
-@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       nsecs[i] = nsec3p;
-     }
- 
--  /* Algo is checked as 1 above */
--  if (!(hash = hash_find("sha1")))
--    return 0;
--
-   if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
-     return 0;
-   
-@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
-   
-   if (type_found == T_NSEC)
-     return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
--  else
-+  else if (type_found == T_NSEC3)
-     return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
-+  else
-+    return 0;
- }
- 
- /* 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)
- {
--  int secure_ds, name_start = strlen(name);
-+  int name_start = strlen(name);
-   struct crec *crecp;
-   char *p;
-   
-@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
-       
-       if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
- 	return STAT_NEED_DS;
-+      
-+       /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
-+	  F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
-+	  but that's because there's no NS record either, ie this isn't the start
-+	  of a zone. We only prove that the DNS tree below a node is unsigned when
-+	  we prove that we're at a zone cut AND there's no DS record. */
-+      if (crecp->flags & F_NEG)
-+	{
-+	  if (crecp->flags & F_DNSSECOK)
-+	    return STAT_INSECURE; /* proved no DS here */
-+	}
-       else
- 	{
--	  secure_ds = 0;
--	  
-+	  int gotone = 0;
-+
-+	  /* If all the DS records have digest and/or sig algos we don't support,
-+	     then the zone is insecure. Note that if an algo
-+	     appears in the DS, then RRSIGs for that algo MUST
-+	     exist for each RRset: 4035 para 2.2  So if we find
-+	     a DS here with digest and sig we can do, we're entitled
-+	     to assume we can validate the zone and if we can't later,
-+	     because an RRSIG is missing we return BOGUS.
-+	  */
- 	  do 
- 	    {
--	      if (crecp->uid == (unsigned int)class)
--		{
--		  /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
--		     F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
--		     but that's because there's no NS record either, ie this isn't the start
--		     of a zone. We only prove that the DNS tree below a node is unsigned when
--		     we prove that we're at a zone cut AND there's no DS record.
--		  */	  
--		  if (crecp->flags & F_NEG)
--		    {
--		      if (crecp->flags & F_DNSSECOK)
--			return STAT_INSECURE; /* proved no DS here */
--		    }
--		  else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
--		    return STAT_INSECURE; /* algo we can't use - insecure */
--		  else
--		    secure_ds = 1;
--		}
-+	      if (crecp->uid == (unsigned int)class &&
-+		  hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
-+		  verify_func(crecp->addr.ds.algo))
-+		gotone = 1;
- 	    }
- 	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
--	}
--
--      if (secure_ds)
--	{
--	  /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
--	     that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
--	     one we can use. However the DNSKEY RRset may contain more than one key and
--	     one of the other keys may use an algorithm we don't support. If that's 
--	     the case the zone is insecure for us. */
--	  
--	  if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
--	    return STAT_NEED_KEY;
- 
--	  do 
--	    {
--	      if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
--		return STAT_INSECURE;
--	    }
--	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
-+	  if (!gotone)
-+	    return STAT_INSECURE;
- 	}
- 
-       if (name_start == 0)
--- 
-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 |    4 ++--
- 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)
-       if (sb == b)
- 	return 1;
-       
--      ea = sa--;
--      eb = sb--;
-+      ea = --sa;
-+      eb = --sb;
-     }
- }
- 
--- 
-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 |    6 ++----
- 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)
- 	}
-       else
- 	{
--	  int gotone = 0;
--
- 	  /* If all the DS records have digest and/or sig algos we don't support,
- 	     then the zone is insecure. Note that if an algo
- 	     appears in the DS, then RRSIGs for that algo MUST
-@@ -1904,11 +1902,11 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
- 	      if (crecp->uid == (unsigned int)class &&
- 		  hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
- 		  verify_func(crecp->addr.ds.algo))
--		gotone = 1;
-+		break;
- 	    }
- 	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
- 
--	  if (!gotone)
-+	  if (!crecp)
- 	    return STAT_INSECURE;
- 	}
- 
--- 
-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 |    8 ++++++--
- 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
-   for (i = 0; i < nsec_count; i++)
-     {
-       unsigned char *nsec3p = nsecs[i];
--      int this_iter;
-+      int this_iter, flags;
- 
-       nsecs[i] = NULL; /* Speculative, will be restored if OK. */
-       
-@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
-       if (*p++ != algo)
- 	continue;
-  
--      p++; /* flags */
-+      flags = *p++; /* flags */
-       
-+      /* 5155 8.2 */
-+      if (flags != 0 && flags != 1)
-+	continue;
-+
-       GETSHORT(this_iter, p);
-       if (this_iter != iterations)
- 	continue;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/030-Split_EDNS0_stuff_into_its_own_source_file.patch b/src/patches/dnsmasq/030-Split_EDNS0_stuff_into_its_own_source_file.patch
deleted file mode 100644
index 0cef987..0000000
--- a/src/patches/dnsmasq/030-Split_EDNS0_stuff_into_its_own_source_file.patch
+++ /dev/null
@@ -1,777 +0,0 @@
-From 1d03016bbcb78962305cca20cbf7441423ff897d Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 21 Dec 2015 14:17:06 +0000
-Subject: [PATCH] Split EDNS0 stuff into its own source file.
-
----
- Makefile       |    2 +-
- bld/Android.mk |    2 +-
- src/dnsmasq.h  |   17 +--
- src/edns0.c    |  351 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/rfc1035.c  |  334 -----------------------------------------------------
- 5 files changed, 362 insertions(+), 344 deletions(-)
- create mode 100644 src/edns0.c
-
-diff --git a/Makefile b/Makefile
-index b664160..dfb0347 100644
---- a/Makefile
-+++ b/Makefile
-@@ -74,7 +74,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
-        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
-        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
-        domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
--       poll.o rrfilter.o
-+       poll.o rrfilter.o edns0.o
- 
- hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
-        dns-protocol.h radv-protocol.h ip6addr.h
-diff --git a/bld/Android.mk b/bld/Android.mk
-index 67b9c4b..87966d2 100644
---- a/bld/Android.mk
-+++ b/bld/Android.mk
-@@ -10,7 +10,7 @@ LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
- 		    dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
- 		    radv.c slaac.c auth.c ipset.c domain.c \
- 	            dnssec.c dnssec-openssl.c blockdata.c tables.c \
--		    loop.c inotify.c poll.c rrfilter.c
-+		    loop.c inotify.c poll.c rrfilter.c edns0.c
- 
- LOCAL_MODULE := dnsmasq
- 
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index abb34c5..a41c8cc 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1123,14 +1123,6 @@ int check_for_local_domain(char *name, time_t now);
- unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
- size_t resize_packet(struct dns_header *header, size_t plen, 
- 		  unsigned char *pheader, size_t hlen);
--size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
--			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
--size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
--size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
--#ifdef HAVE_DNSSEC
--size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
--#endif
--int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
- int add_resource_record(struct dns_header *header, char *limit, int *truncp,
- 			int nameoffset, unsigned char **pp, unsigned long ttl, 
- 			int *offset, unsigned short type, unsigned short class, char *format, ...);
-@@ -1521,3 +1513,12 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode);
- u16 *rrfilter_desc(int type);
- int expand_workspace(unsigned char ***wkspc, int *szp, int new);
- 
-+/* edns0.c */
-+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-+			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
-+size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
-+size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
-+#ifdef HAVE_DNSSEC
-+size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
-+#endif
-+int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
-diff --git a/src/edns0.c b/src/edns0.c
-new file mode 100644
-index 0000000..f348b01
---- /dev/null
-+++ b/src/edns0.c
-@@ -0,0 +1,351 @@
-+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; version 2 dated June, 1991, or
-+   (at your option) version 3 dated 29 June, 2007.
-+ 
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+     
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include "dnsmasq.h"
-+
-+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign)
-+{
-+  /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. 
-+     also return length of pseudoheader in *len and pointer to the UDP size in *p
-+     Finally, check to see if a packet is signed. If it is we cannot change a single bit before
-+     forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
-+  
-+  int i, arcount = ntohs(header->arcount);
-+  unsigned char *ansp = (unsigned char *)(header+1);
-+  unsigned short rdlen, type, class;
-+  unsigned char *ret = NULL;
-+
-+  if (is_sign)
-+    {
-+      *is_sign = 0;
-+
-+      if (OPCODE(header) == QUERY)
-+	{
-+	  for (i = ntohs(header->qdcount); i != 0; i--)
-+	    {
-+	      if (!(ansp = skip_name(ansp, header, plen, 4)))
-+		return NULL;
-+	      
-+	      GETSHORT(type, ansp); 
-+	      GETSHORT(class, ansp);
-+	      
-+	      if (class == C_IN && type == T_TKEY)
-+		*is_sign = 1;
-+	    }
-+	}
-+    }
-+  else
-+    {
-+      if (!(ansp = skip_questions(header, plen)))
-+	return NULL;
-+    }
-+    
-+  if (arcount == 0)
-+    return NULL;
-+  
-+  if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
-+    return NULL; 
-+  
-+  for (i = 0; i < arcount; i++)
-+    {
-+      unsigned char *save, *start = ansp;
-+      if (!(ansp = skip_name(ansp, header, plen, 10)))
-+	return NULL; 
-+
-+      GETSHORT(type, ansp);
-+      save = ansp;
-+      GETSHORT(class, ansp);
-+      ansp += 4; /* TTL */
-+      GETSHORT(rdlen, ansp);
-+      if (!ADD_RDLEN(header, ansp, plen, rdlen))
-+	return NULL;
-+      if (type == T_OPT)
-+	{
-+	  if (len)
-+	    *len = ansp - start;
-+	  if (p)
-+	    *p = save;
-+	  ret = start;
-+	}
-+      else if (is_sign && 
-+	       i == arcount - 1 && 
-+	       class == C_ANY && 
-+	       type == T_TSIG)
-+	*is_sign = 1;
-+    }
-+  
-+  return ret;
-+}
-+
-+struct macparm {
-+  unsigned char *limit;
-+  struct dns_header *header;
-+  size_t plen;
-+  union mysockaddr *l3;
-+};
-+ 
-+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-+			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
-+{ 
-+  unsigned char *lenp, *datap, *p;
-+  int rdlen, is_sign;
-+  
-+  if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
-+    {
-+      if (is_sign)
-+	return plen;
-+
-+      /* We are adding the pseudoheader */
-+      if (!(p = skip_questions(header, plen)) ||
-+	  !(p = skip_section(p, 
-+			     ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
-+			     header, plen)))
-+	return plen;
-+      *p++ = 0; /* empty name */
-+      PUTSHORT(T_OPT, p);
-+      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
-+      PUTSHORT(0, p);    /* extended RCODE and version */
-+      PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
-+      lenp = p;
-+      PUTSHORT(0, p);    /* RDLEN */
-+      rdlen = 0;
-+      if (((ssize_t)optlen) > (limit - (p + 4)))
-+	return plen; /* Too big */
-+      header->arcount = htons(ntohs(header->arcount) + 1);
-+      datap = p;
-+    }
-+  else
-+    {
-+      int i;
-+      unsigned short code, len, flags;
-+      
-+      /* Must be at the end, if exists */
-+      if (ntohs(header->arcount) != 1 ||
-+	  is_sign ||
-+	  (!(p = skip_name(p, header, plen, 10))))
-+	return plen;
-+      
-+      p += 6; /* skip UDP length and RCODE */
-+      GETSHORT(flags, p);
-+      if (set_do)
-+	{
-+	  p -=2;
-+	  PUTSHORT(flags | 0x8000, p);
-+	}
-+
-+      lenp = p;
-+      GETSHORT(rdlen, p);
-+      if (!CHECK_LEN(header, p, plen, rdlen))
-+	return plen; /* bad packet */
-+      datap = p;
-+
-+       /* no option to add */
-+      if (optno == 0)
-+	return plen;
-+      	  
-+      /* check if option already there */
-+      for (i = 0; i + 4 < rdlen; i += len + 4)
-+	{
-+	  GETSHORT(code, p);
-+	  GETSHORT(len, p);
-+	  if (code == optno)
-+	    return plen;
-+	  p += len;
-+	}
-+      
-+      if (((ssize_t)optlen) > (limit - (p + 4)))
-+	return plen; /* Too big */
-+    }
-+  
-+  if (optno != 0)
-+    {
-+      PUTSHORT(optno, p);
-+      PUTSHORT(optlen, p);
-+      memcpy(p, opt, optlen);
-+      p += optlen;  
-+    }
-+
-+  PUTSHORT(p - datap, lenp);
-+  return p - (unsigned char *)header;
-+  
-+}
-+
-+static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
-+{
-+  struct macparm *parm = parmv;
-+  int match = 0;
-+    
-+  if (family == parm->l3->sa.sa_family)
-+    {
-+      if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
-+	match = 1;
-+#ifdef HAVE_IPV6
-+      else
-+	if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
-+	  match = 1;
-+#endif
-+    }
-+ 
-+  if (!match)
-+    return 1; /* continue */
-+
-+  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
-+  
-+  return 0; /* done */
-+}	      
-+     
-+size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
-+{
-+  struct macparm parm;
-+     
-+  parm.header = header;
-+  parm.limit = (unsigned char *)limit;
-+  parm.plen = plen;
-+  parm.l3 = l3;
-+
-+  iface_enumerate(AF_UNSPEC, &parm, filter_mac);
-+  
-+  return parm.plen; 
-+}
-+
-+struct subnet_opt {
-+  u16 family;
-+  u8 source_netmask, scope_netmask;
-+#ifdef HAVE_IPV6 
-+  u8 addr[IN6ADDRSZ];
-+#else
-+  u8 addr[INADDRSZ];
-+#endif
-+};
-+
-+static void *get_addrp(union mysockaddr *addr, const short family) 
-+{
-+#ifdef HAVE_IPV6
-+  if (family == AF_INET6)
-+    return &addr->in6.sin6_addr;
-+#endif
-+
-+  return &addr->in.sin_addr;
-+}
-+
-+static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
-+{
-+  /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-+  
-+  int len;
-+  void *addrp;
-+  int sa_family = source->sa.sa_family;
-+
-+#ifdef HAVE_IPV6
-+  if (source->sa.sa_family == AF_INET6)
-+    {
-+      opt->source_netmask = daemon->add_subnet6->mask;
-+      if (daemon->add_subnet6->addr_used) 
-+	{
-+	  sa_family = daemon->add_subnet6->addr.sa.sa_family;
-+	  addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
-+	} 
-+      else 
-+	addrp = &source->in6.sin6_addr;
-+    }
-+  else
-+#endif
-+    {
-+      opt->source_netmask = daemon->add_subnet4->mask;
-+      if (daemon->add_subnet4->addr_used)
-+	{
-+	  sa_family = daemon->add_subnet4->addr.sa.sa_family;
-+	  addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
-+	} 
-+      else 
-+	addrp = &source->in.sin_addr;
-+    }
-+  
-+  opt->scope_netmask = 0;
-+  len = 0;
-+  
-+  if (opt->source_netmask != 0)
-+    {
-+#ifdef HAVE_IPV6
-+      opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
-+#else
-+      opt->family = htons(1);
-+#endif
-+      len = ((opt->source_netmask - 1) >> 3) + 1;
-+      memcpy(opt->addr, addrp, len);
-+      if (opt->source_netmask & 7)
-+	opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
-+    }
-+
-+  return len + 4;
-+}
-+ 
-+size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
-+{
-+  /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-+  
-+  int len;
-+  struct subnet_opt opt;
-+  
-+  len = calc_subnet_opt(&opt, source);
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
-+}
-+
-+#ifdef HAVE_DNSSEC
-+size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
-+{
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
-+}
-+#endif
-+
-+int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
-+{
-+  /* Section 9.2, Check that subnet option in reply matches. */
-+
-+
-+ int len, calc_len;
-+  struct subnet_opt opt;
-+  unsigned char *p;
-+  int code, i, rdlen;
-+  
-+   calc_len = calc_subnet_opt(&opt, peer);
-+   
-+   if (!(p = skip_name(pseudoheader, header, plen, 10)))
-+     return 1;
-+   
-+   p += 8; /* skip UDP length and RCODE */
-+   
-+   GETSHORT(rdlen, p);
-+   if (!CHECK_LEN(header, p, plen, rdlen))
-+     return 1; /* bad packet */
-+   
-+   /* check if option there */
-+   for (i = 0; i + 4 < rdlen; i += len + 4)
-+     {
-+       GETSHORT(code, p);
-+       GETSHORT(len, p);
-+       if (code == EDNS0_OPTION_CLIENT_SUBNET)
-+	 {
-+	   /* make sure this doesn't mismatch. */
-+	   opt.scope_netmask = p[3];
-+	   if (len != calc_len || memcmp(p, &opt, len) != 0)
-+	     return 0;
-+	 }
-+       p += len;
-+     }
-+   
-+   return 1;
-+}
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 18858a8..5d89287 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -408,340 +408,6 @@ size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *phea
-   return ansp - (unsigned char *)header;
- }
- 
--unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign)
--{
--  /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. 
--     also return length of pseudoheader in *len and pointer to the UDP size in *p
--     Finally, check to see if a packet is signed. If it is we cannot change a single bit before
--     forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
--  
--  int i, arcount = ntohs(header->arcount);
--  unsigned char *ansp = (unsigned char *)(header+1);
--  unsigned short rdlen, type, class;
--  unsigned char *ret = NULL;
--
--  if (is_sign)
--    {
--      *is_sign = 0;
--
--      if (OPCODE(header) == QUERY)
--	{
--	  for (i = ntohs(header->qdcount); i != 0; i--)
--	    {
--	      if (!(ansp = skip_name(ansp, header, plen, 4)))
--		return NULL;
--	      
--	      GETSHORT(type, ansp); 
--	      GETSHORT(class, ansp);
--	      
--	      if (class == C_IN && type == T_TKEY)
--		*is_sign = 1;
--	    }
--	}
--    }
--  else
--    {
--      if (!(ansp = skip_questions(header, plen)))
--	return NULL;
--    }
--    
--  if (arcount == 0)
--    return NULL;
--  
--  if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
--    return NULL; 
--  
--  for (i = 0; i < arcount; i++)
--    {
--      unsigned char *save, *start = ansp;
--      if (!(ansp = skip_name(ansp, header, plen, 10)))
--	return NULL; 
--
--      GETSHORT(type, ansp);
--      save = ansp;
--      GETSHORT(class, ansp);
--      ansp += 4; /* TTL */
--      GETSHORT(rdlen, ansp);
--      if (!ADD_RDLEN(header, ansp, plen, rdlen))
--	return NULL;
--      if (type == T_OPT)
--	{
--	  if (len)
--	    *len = ansp - start;
--	  if (p)
--	    *p = save;
--	  ret = start;
--	}
--      else if (is_sign && 
--	       i == arcount - 1 && 
--	       class == C_ANY && 
--	       type == T_TSIG)
--	*is_sign = 1;
--    }
--  
--  return ret;
--}
--
--struct macparm {
--  unsigned char *limit;
--  struct dns_header *header;
--  size_t plen;
--  union mysockaddr *l3;
--};
-- 
--size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
--			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
--{ 
--  unsigned char *lenp, *datap, *p;
--  int rdlen, is_sign;
--  
--  if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
--    {
--      if (is_sign)
--	return plen;
--
--      /* We are adding the pseudoheader */
--      if (!(p = skip_questions(header, plen)) ||
--	  !(p = skip_section(p, 
--			     ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
--			     header, plen)))
--	return plen;
--      *p++ = 0; /* empty name */
--      PUTSHORT(T_OPT, p);
--      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
--      PUTSHORT(0, p);    /* extended RCODE and version */
--      PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
--      lenp = p;
--      PUTSHORT(0, p);    /* RDLEN */
--      rdlen = 0;
--      if (((ssize_t)optlen) > (limit - (p + 4)))
--	return plen; /* Too big */
--      header->arcount = htons(ntohs(header->arcount) + 1);
--      datap = p;
--    }
--  else
--    {
--      int i;
--      unsigned short code, len, flags;
--      
--      /* Must be at the end, if exists */
--      if (ntohs(header->arcount) != 1 ||
--	  is_sign ||
--	  (!(p = skip_name(p, header, plen, 10))))
--	return plen;
--      
--      p += 6; /* skip UDP length and RCODE */
--      GETSHORT(flags, p);
--      if (set_do)
--	{
--	  p -=2;
--	  PUTSHORT(flags | 0x8000, p);
--	}
--
--      lenp = p;
--      GETSHORT(rdlen, p);
--      if (!CHECK_LEN(header, p, plen, rdlen))
--	return plen; /* bad packet */
--      datap = p;
--
--       /* no option to add */
--      if (optno == 0)
--	return plen;
--      	  
--      /* check if option already there */
--      for (i = 0; i + 4 < rdlen; i += len + 4)
--	{
--	  GETSHORT(code, p);
--	  GETSHORT(len, p);
--	  if (code == optno)
--	    return plen;
--	  p += len;
--	}
--      
--      if (((ssize_t)optlen) > (limit - (p + 4)))
--	return plen; /* Too big */
--    }
--  
--  if (optno != 0)
--    {
--      PUTSHORT(optno, p);
--      PUTSHORT(optlen, p);
--      memcpy(p, opt, optlen);
--      p += optlen;  
--    }
--
--  PUTSHORT(p - datap, lenp);
--  return p - (unsigned char *)header;
--  
--}
--
--static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
--{
--  struct macparm *parm = parmv;
--  int match = 0;
--    
--  if (family == parm->l3->sa.sa_family)
--    {
--      if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
--	match = 1;
--#ifdef HAVE_IPV6
--      else
--	if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
--	  match = 1;
--#endif
--    }
-- 
--  if (!match)
--    return 1; /* continue */
--
--  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
--  
--  return 0; /* done */
--}	      
--     
--size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
--{
--  struct macparm parm;
--     
--  parm.header = header;
--  parm.limit = (unsigned char *)limit;
--  parm.plen = plen;
--  parm.l3 = l3;
--
--  iface_enumerate(AF_UNSPEC, &parm, filter_mac);
--  
--  return parm.plen; 
--}
--
--struct subnet_opt {
--  u16 family;
--  u8 source_netmask, scope_netmask;
--#ifdef HAVE_IPV6 
--  u8 addr[IN6ADDRSZ];
--#else
--  u8 addr[INADDRSZ];
--#endif
--};
--
--static void *get_addrp(union mysockaddr *addr, const short family) 
--{
--#ifdef HAVE_IPV6
--  if (family == AF_INET6)
--    return &addr->in6.sin6_addr;
--#endif
--
--  return &addr->in.sin_addr;
--}
--
--static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
--{
--  /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
--  
--  int len;
--  void *addrp;
--  int sa_family = source->sa.sa_family;
--
--#ifdef HAVE_IPV6
--  if (source->sa.sa_family == AF_INET6)
--    {
--      opt->source_netmask = daemon->add_subnet6->mask;
--      if (daemon->add_subnet6->addr_used) 
--	{
--	  sa_family = daemon->add_subnet6->addr.sa.sa_family;
--	  addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
--	} 
--      else 
--	addrp = &source->in6.sin6_addr;
--    }
--  else
--#endif
--    {
--      opt->source_netmask = daemon->add_subnet4->mask;
--      if (daemon->add_subnet4->addr_used)
--	{
--	  sa_family = daemon->add_subnet4->addr.sa.sa_family;
--	  addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
--	} 
--      else 
--	addrp = &source->in.sin_addr;
--    }
--  
--  opt->scope_netmask = 0;
--  len = 0;
--  
--  if (opt->source_netmask != 0)
--    {
--#ifdef HAVE_IPV6
--      opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
--#else
--      opt->family = htons(1);
--#endif
--      len = ((opt->source_netmask - 1) >> 3) + 1;
--      memcpy(opt->addr, addrp, len);
--      if (opt->source_netmask & 7)
--	opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
--    }
--
--  return len + 4;
--}
-- 
--size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
--{
--  /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
--  
--  int len;
--  struct subnet_opt opt;
--  
--  len = calc_subnet_opt(&opt, source);
--  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
--}
--
--#ifdef HAVE_DNSSEC
--size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
--{
--  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
--}
--#endif
--
--int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
--{
--  /* Section 9.2, Check that subnet option in reply matches. */
--
--
-- int len, calc_len;
--  struct subnet_opt opt;
--  unsigned char *p;
--  int code, i, rdlen;
--  
--   calc_len = calc_subnet_opt(&opt, peer);
--   
--   if (!(p = skip_name(pseudoheader, header, plen, 10)))
--     return 1;
--   
--   p += 8; /* skip UDP length and RCODE */
--   
--   GETSHORT(rdlen, p);
--   if (!CHECK_LEN(header, p, plen, rdlen))
--     return 1; /* bad packet */
--   
--   /* check if option there */
--   for (i = 0; i + 4 < rdlen; i += len + 4)
--     {
--       GETSHORT(code, p);
--       GETSHORT(len, p);
--       if (code == EDNS0_OPTION_CLIENT_SUBNET)
--	 {
--	   /* make sure this doesn't mismatch. */
--	   opt.scope_netmask = p[3];
--	   if (len != calc_len || memcmp(p, &opt, len) != 0)
--	     return 0;
--	 }
--       p += len;
--     }
--   
--   return 1;
--}
--
- /* is addr in the non-globally-routed IP space? */ 
- int private_net(struct in_addr addr, int ban_localhost) 
- {
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch b/src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch
deleted file mode 100644
index 386ff69..0000000
--- a/src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch
+++ /dev/null
@@ -1,295 +0,0 @@
-From 5bb88f096363e66ac08e31761f850a1d5aa22244 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 21 Dec 2015 16:23:47 +0000
-Subject: [PATCH] Handle extending EDNS0 OPT RR.
-
----
- src/dnsmasq.h |    4 +-
- src/dnssec.c  |    2 +-
- src/edns0.c   |  113 +++++++++++++++++++++++++++++++++++----------------------
- src/forward.c |   16 ++++----
- 4 files changed, 80 insertions(+), 55 deletions(-)
-
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index a41c8cc..9828819 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1117,8 +1117,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
- int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
- 			     struct bogus_addr *addr, time_t now);
- int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
--unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
--				 size_t *len, unsigned char **p, int *is_sign);
- int check_for_local_domain(char *name, time_t now);
- unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
- size_t resize_packet(struct dns_header *header, size_t plen, 
-@@ -1514,6 +1512,8 @@ u16 *rrfilter_desc(int type);
- int expand_workspace(unsigned char ***wkspc, int *szp, int new);
- 
- /* edns0.c */
-+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
-+				   size_t *len, unsigned char **p, int *is_sign, int *is_last);
- size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
- 			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
- size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 486e422..e0b7f39 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -2206,7 +2206,7 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
- 
-   ret = add_do_bit(header, p - (unsigned char *)header, end);
- 
--  if (find_pseudoheader(header, ret, NULL, &p, NULL))
-+  if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
-     PUTSHORT(edns_pktsz, p);
- 
-   return ret;
-diff --git a/src/edns0.c b/src/edns0.c
-index f348b01..d1a11e7 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -16,12 +16,12 @@
- 
- #include "dnsmasq.h"
- 
--unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign)
-+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign, int *is_last)
- {
-   /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. 
-      also return length of pseudoheader in *len and pointer to the UDP size in *p
-      Finally, check to see if a packet is signed. If it is we cannot change a single bit before
--     forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
-+     forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
-   
-   int i, arcount = ntohs(header->arcount);
-   unsigned char *ansp = (unsigned char *)(header+1);
-@@ -76,8 +76,13 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
- 	{
- 	  if (len)
- 	    *len = ansp - start;
-+
- 	  if (p)
- 	    *p = save;
-+	  
-+	  if (is_last)
-+	    *is_last = (i == arcount-1);
-+
- 	  ret = start;
- 	}
-       else if (is_sign && 
-@@ -100,50 +105,31 @@ struct macparm {
- size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
- 			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
- { 
--  unsigned char *lenp, *datap, *p;
--  int rdlen, is_sign;
-+  unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
-+  int rdlen = 0, is_sign, is_last;
-+  unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
-+
-+  p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
-   
--  if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
--    {
--      if (is_sign)
--	return plen;
-+  if (is_sign)
-+    return plen;
- 
--      /* We are adding the pseudoheader */
--      if (!(p = skip_questions(header, plen)) ||
--	  !(p = skip_section(p, 
--			     ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
--			     header, plen)))
--	return plen;
--      *p++ = 0; /* empty name */
--      PUTSHORT(T_OPT, p);
--      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
--      PUTSHORT(0, p);    /* extended RCODE and version */
--      PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
--      lenp = p;
--      PUTSHORT(0, p);    /* RDLEN */
--      rdlen = 0;
--      if (((ssize_t)optlen) > (limit - (p + 4)))
--	return plen; /* Too big */
--      header->arcount = htons(ntohs(header->arcount) + 1);
--      datap = p;
--    }
--  else
-+  if (p)
-     {
-+      /* Existing header */
-       int i;
--      unsigned short code, len, flags;
--      
--      /* Must be at the end, if exists */
--      if (ntohs(header->arcount) != 1 ||
--	  is_sign ||
--	  (!(p = skip_name(p, header, plen, 10))))
--	return plen;
--      
--      p += 6; /* skip UDP length and RCODE */
-+      unsigned short code, len;
-+
-+      p = udp_len;
-+      GETSHORT(udp_sz, p);
-+      GETSHORT(rcode, p);
-       GETSHORT(flags, p);
-+
-       if (set_do)
- 	{
- 	  p -=2;
--	  PUTSHORT(flags | 0x8000, p);
-+	  flags |= 0x8000;
-+	  PUTSHORT(flags, p);
- 	}
- 
-       lenp = p;
-@@ -165,22 +151,61 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
- 	    return plen;
- 	  p += len;
- 	}
--      
--      if (((ssize_t)optlen) > (limit - (p + 4)))
--	return plen; /* Too big */
-+
-+      /* If we're going to extend the RR, it has to be the last RR in the packet */
-+      if (!is_last)
-+	{
-+	  /* First, take a copy of the options. */
-+	  if (rdlen != 0 && (buff = whine_malloc(rdlen)))
-+	    memcpy(buff, datap, rdlen);	      
-+	  
-+	  /* now, delete OPT RR */
-+	  plen = rrfilter(header, plen, 0);
-+	  
-+	  /* Now, force addition of a new one */
-+	  p = NULL;	  
-+	}
-+    }
-+  
-+  if (!p)
-+    {
-+      /* We are (re)adding the pseudoheader */
-+      if (!(p = skip_questions(header, plen)) ||
-+	  !(p = skip_section(p, 
-+			     ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
-+			     header, plen)))
-+	return plen;
-+      *p++ = 0; /* empty name */
-+      PUTSHORT(T_OPT, p);
-+      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
-+      PUTSHORT(rcode, p);    /* extended RCODE and version */
-+      PUTSHORT(flags, p); /* DO flag */
-+      lenp = p;
-+      PUTSHORT(rdlen, p);    /* RDLEN */
-+      datap = p;
-+      /* Copy back any options */
-+      if (buff)
-+	{
-+	  memcpy(p, buff, rdlen);
-+	  free(buff);
-+	  p += rdlen;
-+	}
-+      header->arcount = htons(ntohs(header->arcount) + 1);
-     }
-   
-+  if (((ssize_t)optlen) > (limit - (p + 4)))
-+    return plen; /* Too big */
-+  
-+  /* Add new option */
-   if (optno != 0)
-     {
-       PUTSHORT(optno, p);
-       PUTSHORT(optlen, p);
-       memcpy(p, opt, optlen);
-       p += optlen;  
-+      PUTSHORT(p - datap, lenp);
-     }
--
--  PUTSHORT(p - datap, lenp);
-   return p - (unsigned char *)header;
--  
- }
- 
- static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
-diff --git a/src/forward.c b/src/forward.c
-index 041353c..2ca3c86 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -276,7 +276,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 	  blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
- 	  plen = forward->stash_len;
- 	  
--	  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
-+	  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
- 	    PUTSHORT(SAFE_PKTSZ, pheader);
- 
- 	  if (forward->sentto->addr.sa.sa_family == AF_INET) 
-@@ -479,7 +479,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 		}
- 	      
- #ifdef HAVE_DNSSEC
--	      if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
-+	      if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
- 		{
- 		  /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
- 		     packet size to 512. But that won't provide space for the RRSIGS in many cases.
-@@ -489,7 +489,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 		     the truncated bit? */		  
- 		  unsigned char *pheader;
- 		  int is_sign;
--		  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
-+		  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
- 		    PUTSHORT(start->edns_pktsz, pheader);
- 		}
- #endif
-@@ -584,7 +584,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     }
- #endif
-   
--  if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
-+  if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
-     {
-       if (check_subnet && !check_source(header, plen, pheader, query_source))
- 	{
-@@ -779,7 +779,7 @@ void reply_query(int fd, int family, time_t now)
-       int is_sign;
-       
-       /* recreate query from reply */
--      pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
-+      pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
-       if (!is_sign)
- 	{
- 	  header->ancount = htons(0);
-@@ -1313,7 +1313,7 @@ void receive_query(struct listener *listen, time_t now)
- #endif
-     }
-   
--  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
-+  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
-     { 
-       unsigned short flags;
-       
-@@ -1569,7 +1569,7 @@ unsigned char *tcp_request(int confd, time_t now,
-       
-       do_bit = 0;
- 
--      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
-+      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
- 	{ 
- 	  unsigned short flags;
- 	  
-@@ -1578,7 +1578,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 	  GETSHORT(flags, pheader);
-       
- 	  if (flags & 0x8000)
--	    do_bit = 1;/* do bit */ 
-+	    do_bit = 1; /* do bit */ 
- 	}
- 
- #ifdef HAVE_AUTH
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting.patch b/src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting.patch
deleted file mode 100644
index df90a4d..0000000
--- a/src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_that_the_client_isnt_expecting.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From 5aa5f0ff2f8227ed743feb089dee421f1ca69943 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 21 Dec 2015 17:20:35 +0000
-Subject: [PATCH] Truncate DNS replies >512 bytes that the client isn't
- expecting.
-
----
- src/edns0.c   |    5 ++---
- src/forward.c |   17 +++++++++++++++--
- 2 files changed, 17 insertions(+), 5 deletions(-)
-
-diff --git a/src/edns0.c b/src/edns0.c
-index d1a11e7..e137992 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -339,9 +339,8 @@ size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
- int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
- {
-   /* Section 9.2, Check that subnet option in reply matches. */
--
--
-- int len, calc_len;
-+  
-+  int len, calc_len;
-   struct subnet_opt opt;
-   unsigned char *p;
-   int code, i, rdlen;
-diff --git a/src/forward.c b/src/forward.c
-index 2ca3c86..e1766b9 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -485,8 +485,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 		     packet size to 512. But that won't provide space for the RRSIGS in many cases.
- 		     The RRSIGS will be stripped out before the answer goes back, so the packet should
- 		     shrink again. So, if we added a do-bit, bump the udp packet size to the value
--		     known to be OK for this server. Maybe check returned size after stripping and set
--		     the truncated bit? */		  
-+		     known to be OK for this server. We check returned size after stripping and set
-+		     the truncated bit if it's still too big. */		  
- 		  unsigned char *pheader;
- 		  int is_sign;
- 		  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
-@@ -1028,6 +1028,19 @@ void reply_query(int fd, int family, time_t now)
- 	{
- 	  header->id = htons(forward->orig_id);
- 	  header->hb4 |= HB4_RA; /* recursion if available */
-+#ifdef HAVE_DNSSEC
-+	  /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
-+	     greater than the no-EDNS0-implied 512 to have if space for the RRSIGS. If, having stripped them and the EDNS0
-+             header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
-+	  if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
-+	    {
-+	      header->ancount = htons(0);
-+	      header->nscount = htons(0);
-+	      header->arcount = htons(0);
-+	      header->hb3 |= HB3_TC;
-+	      nn = resize_packet(header, nn, NULL, 0);
-+	    }
-+#endif
- 	  send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, 
- 		    &forward->source, &forward->dest, forward->iface);
- 	}
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitted.patch b/src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitted.patch
deleted file mode 100644
index eed613b..0000000
--- a/src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitted.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From efef497b890231ba9232d02e7bfaf8273f044622 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 21 Dec 2015 17:30:44 +0000
-Subject: [PATCH] Fix build failure when DNSSEC code omitted.
-
----
- src/dnsmasq.h |    2 --
- src/edns0.c   |   12 +++++-------
- 2 files changed, 5 insertions(+), 9 deletions(-)
-
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 9828819..1286807 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1518,7 +1518,5 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
- 			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
- size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
- size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
--#ifdef HAVE_DNSSEC
- size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
--#endif
- int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
-diff --git a/src/edns0.c b/src/edns0.c
-index e137992..f82ba1b 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -208,6 +208,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
-   return p - (unsigned char *)header;
- }
- 
-+size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
-+{
-+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
-+}
-+
- static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
- {
-   struct macparm *parm = parmv;
-@@ -329,13 +334,6 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
-   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
- }
- 
--#ifdef HAVE_DNSSEC
--size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
--{
--  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
--}
--#endif
--
- int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
- {
-   /* Section 9.2, Check that subnet option in reply matches. */
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch b/src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch
deleted file mode 100644
index 5742d4b..0000000
--- a/src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch
+++ /dev/null
@@ -1,81 +0,0 @@
-From 15379ea1f252d1f53c5d93ae970b22dedb233642 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 21 Dec 2015 18:31:55 +0000
-Subject: [PATCH] Log signature algo with DNSKEY and DS, also digest with DS.
-
----
- src/cache.c   |    2 +-
- src/dnsmasq.h |    6 ++++--
- src/dnssec.c  |   15 +++++++++------
- 3 files changed, 14 insertions(+), 9 deletions(-)
-
-diff --git a/src/cache.c b/src/cache.c
-index 51ba7cc..4da380a 100644
---- a/src/cache.c
-+++ b/src/cache.c
-@@ -1580,7 +1580,7 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
-   if (addr)
-     {
-       if (flags & F_KEYTAG)
--	sprintf(daemon->addrbuff, arg, addr->addr.keytag);
-+	sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
-       else
- 	{
- #ifdef HAVE_IPV6
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 1286807..4503a2d 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -256,8 +256,10 @@ struct all_addr {
-     struct in6_addr addr6;
- #endif
-     /* for log_query */
--    unsigned int keytag;
--    /* for cache_insert if RRSIG, DNSKEY, DS */
-+    struct {
-+      unsigned short keytag, algo, digest;
-+    } log; 
-+    /* for cache_insert of DNSKEY, DS */
-     struct {
-       unsigned short class, type;
-     } dnssec;      
-diff --git a/src/dnssec.c b/src/dnssec.c
-index e0b7f39..ed2d3fe 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1115,11 +1115,12 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- 			}
- 		      else
- 			{
--			  a.addr.keytag = keytag;
-+			  a.addr.log.keytag = keytag;
-+			  a.addr.log.algo = algo;
- 			  if (verify_func(algo))
--			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
-+			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
- 			  else
--			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
-+			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
- 			  
- 			  recp1->addr.key.keylen = rdlen - 4;
- 			  recp1->addr.key.keydata = key;
-@@ -1241,11 +1242,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
- 		    }
- 		  else
- 		    {
--		      a.addr.keytag = keytag;
-+		      a.addr.log.keytag = keytag;
-+		      a.addr.log.algo = algo;
-+		      a.addr.log.digest = digest;
- 		      if (hash_find(ds_digest_name(digest)) && verify_func(algo))
--			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
-+			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
- 		      else
--			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
-+			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
- 		      
- 		      crecp->addr.ds.digest = digest;
- 		      crecp->addr.ds.keydata = key;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch b/src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch
deleted file mode 100644
index 5c8ebd7..0000000
--- a/src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch
+++ /dev/null
@@ -1,138 +0,0 @@
-From d3a8b39c7df2f0debf3b5f274a1c37a9e261f94e Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Wed, 23 Dec 2015 12:27:37 +0000
-Subject: [PATCH] More EDNS0 packet-size tweaks.
-
----
- src/dnsmasq.c |    7 +++++--
- src/dnsmasq.h |    8 +-------
- src/forward.c |   22 +++++++++++++++-------
- 3 files changed, 21 insertions(+), 16 deletions(-)
-
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 81254f6..45761cc 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -91,8 +91,11 @@ int main (int argc, char **argv)
-   if (daemon->edns_pktsz < PACKETSZ)
-     daemon->edns_pktsz = PACKETSZ;
- 
--  daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ? 
--    daemon->edns_pktsz : DNSMASQ_PACKETSZ;
-+  /* Min buffer size: we check after adding each record, so there must be 
-+     memory for the largest packet, and the largest record so the
-+     min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
-+     This might be increased is EDNS packet size if greater than the minimum. */ 
-+  daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
-   daemon->packet = safe_malloc(daemon->packet_buff_sz);
-   
-   daemon->addrbuff = safe_malloc(ADDRSTRLEN);
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 4503a2d..1c94f2a 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -179,13 +179,6 @@ struct event_desc {
- #define EC_MISC        5
- #define EC_INIT_OFFSET 10
- 
--/* Min buffer size: we check after adding each record, so there must be 
--   memory for the largest packet, and the largest record so the
--   min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
--   This might be increased is EDNS packet size if greater than the minimum.
--*/
--#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
--
- /* Trust the compiler dead-code eliminator.... */
- #define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
- 
-@@ -594,6 +587,7 @@ struct hostsfile {
- #define FREC_DO_QUESTION       64
- #define FREC_ADDED_PHEADER    128
- #define FREC_TEST_PKTSZ       256
-+#define FREC_HAS_EXTRADATA    512        
- 
- #ifdef HAVE_DNSSEC
- #define HASH_SIZE 20 /* SHA-1 digest size */
-diff --git a/src/forward.c b/src/forward.c
-index e1766b9..c0e4d9a 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -389,13 +389,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-     {
-       struct server *firstsentto = start;
-       int forwarded = 0;
--      
-+      size_t edns0_len;
-+
-       /* If a query is retried, use the log_id for the retry when logging the answer. */
-       forward->log_id = daemon->log_id;
-       
-       if (option_bool(OPT_ADD_MAC))
- 	{
--	  size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
-+	  size_t new = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
- 	  if (new != plen)
- 	    {
- 	      plen = new;
-@@ -405,7 +406,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 
-       if (option_bool(OPT_CLIENT_SUBNET))
- 	{
--	  size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); 
-+	  size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source); 
- 	  if (new != plen)
- 	    {
- 	      plen = new;
-@@ -416,7 +417,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- #ifdef HAVE_DNSSEC
-       if (option_bool(OPT_DNSSEC_VALID))
- 	{
--	  size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
-+	  size_t new = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
- 	 
- 	  if (new != plen)
- 	    forward->flags |= FREC_ADDED_PHEADER;
-@@ -430,6 +431,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 
- 	}
- #endif
-+
-+      /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
-+      if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11)
-+	forward->flags |= FREC_HAS_EXTRADATA;
-       
-       while (1)
- 	{ 
-@@ -769,9 +774,12 @@ void reply_query(int fd, int family, time_t now)
-       check_for_ignored_address(header, n, daemon->ignore_addr))
-     return;
- 
-+  /* Note: if we send extra options in the EDNS0 header, we can't recreate
-+     the query from the reply. */
-   if (RCODE(header) == REFUSED &&
-       !option_bool(OPT_ORDER) &&
--      forward->forwardall == 0)
-+      forward->forwardall == 0 &&
-+      !(forward->flags & FREC_HAS_EXTRADATA))
-     /* for broken servers, attempt to send to another one. */
-     {
-       unsigned char *pheader;
-@@ -919,13 +927,13 @@ void reply_query(int fd, int family, time_t now)
- 		      if (status == STAT_NEED_KEY)
- 			{
- 			  new->flags |= FREC_DNSKEY_QUERY; 
--			  nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
-+			  nn = dnssec_generate_query(header, ((char *) header) + server->edns_pktsz,
- 						     daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
- 			}
- 		      else 
- 			{
- 			  new->flags |= FREC_DS_QUERY;
--			  nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
-+			  nn = dnssec_generate_query(header,((char *) header) + server->edns_pktsz,
- 						     daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
- 			}
- 		      if ((hash = hash_questions(header, nn, daemon->namebuff)))
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch b/src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch
deleted file mode 100644
index ec70419..0000000
--- a/src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.patch
+++ /dev/null
@@ -1,414 +0,0 @@
-From 11867dc28c7bd7c8a509ee7c8c7438cd2bcc1770 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Wed, 23 Dec 2015 16:15:58 +0000
-Subject: [PATCH] Cache access to the kernel's ARP table.
-
----
- Makefile       |    2 +-
- bld/Android.mk |    2 +-
- src/arp.c      |  201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/dhcp6.c    |   54 ++++-----------
- src/dnsmasq.h  |    4 ++
- src/edns0.c    |   37 ++---------
- 6 files changed, 223 insertions(+), 77 deletions(-)
- create mode 100644 src/arp.c
-
-diff --git a/Makefile b/Makefile
-index dfb0347..41e368f 100644
---- a/Makefile
-+++ b/Makefile
-@@ -74,7 +74,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
-        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
-        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
-        domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
--       poll.o rrfilter.o edns0.o
-+       poll.o rrfilter.o edns0.o arp.o
- 
- hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
-        dns-protocol.h radv-protocol.h ip6addr.h
-diff --git a/bld/Android.mk b/bld/Android.mk
-index 87966d2..eafef35 100644
---- a/bld/Android.mk
-+++ b/bld/Android.mk
-@@ -10,7 +10,7 @@ LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
- 		    dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
- 		    radv.c slaac.c auth.c ipset.c domain.c \
- 	            dnssec.c dnssec-openssl.c blockdata.c tables.c \
--		    loop.c inotify.c poll.c rrfilter.c edns0.c
-+		    loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
- 
- LOCAL_MODULE := dnsmasq
- 
-diff --git a/src/arp.c b/src/arp.c
-new file mode 100644
-index 0000000..b624dac
---- /dev/null
-+++ b/src/arp.c
-@@ -0,0 +1,201 @@
-+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; version 2 dated June, 1991, or
-+   (at your option) version 3 dated 29 June, 2007.
-+ 
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+     
-+   You should have received a copy of the GNU General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include "dnsmasq.h"
-+
-+#define ARP_FREE  0
-+#define ARP_FOUND 1
-+#define ARP_NEW   2
-+#define ARP_EMPTY 3
-+
-+struct arp_record {
-+  short hwlen, status;
-+  int family;
-+  unsigned char hwaddr[DHCP_CHADDR_MAX]; 
-+  struct all_addr addr;
-+  struct arp_record *next;
-+};
-+
-+static struct arp_record *arps = NULL, *old = NULL;
-+
-+static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
-+{
-+  int match = 0;
-+  struct arp_record *arp;
-+
-+  if (maclen > DHCP_CHADDR_MAX)
-+    return 1;
-+
-+  /* Look for existing entry */
-+  for (arp = arps; arp; arp = arp->next)
-+    {
-+      if (family != arp->family || arp->status == ARP_NEW)
-+	continue;
-+      
-+      if (family == AF_INET)
-+	{
-+	  if (arp->addr.addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
-+	    continue;
-+	}
-+#ifdef HAVE_IPV6
-+      else
-+	{
-+	  if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct in6_addr *)addrp))
-+	    continue;
-+	}
-+#endif
-+
-+      if (arp->status != ARP_EMPTY && arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
-+	arp->status = ARP_FOUND;
-+      else
-+	{
-+	  /* existing address, MAC changed or arrived new. */
-+	  arp->status = ARP_NEW;
-+	  arp->hwlen = maclen;
-+	  arp->family = family;
-+	  memcpy(arp->hwaddr, mac, maclen);
-+	}
-+      
-+      break;
-+    }
-+
-+  if (!arp)
-+    {
-+      /* New entry */
-+      if (old)
-+	{
-+	  arp = old;
-+	  old = old->next;
-+	}
-+      else if (!(arp = whine_malloc(sizeof(struct arp_record))))
-+	return 1;
-+      
-+      arp->next = arps;
-+      arps = arp;
-+      arp->status = ARP_NEW;
-+      arp->hwlen = maclen;
-+      arp->family = family;
-+      memcpy(arp->hwaddr, mac, maclen);
-+      if (family == AF_INET)
-+	arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
-+#ifdef HAVE_IPV6
-+      else
-+	memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ);
-+#endif
-+    }
-+  
-+  return 1;
-+}
-+
-+/* If in lazy mode, we cache absence of ARP entries. */
-+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
-+{
-+  struct arp_record *arp, **up;
-+  int updated = 0;
-+
-+ again:
-+  
-+  for (arp = arps; arp; arp = arp->next)
-+    {
-+      if (addr->sa.sa_family == arp->family)
-+	{
-+	  if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
-+	    continue;
-+	}
-+#ifdef HAVE_IPV6
-+      else
-+	{
-+	  if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
-+	    continue;
-+	}
-+#endif
-+      
-+      /* Only accept poitive entries unless in lazy mode. */
-+      if (arp->status != ARP_EMPTY || lazy || updated)
-+	{
-+	  if (mac && arp->hwlen != 0)
-+	    memcpy(mac, arp->hwaddr, arp->hwlen);
-+	  return arp->hwlen;
-+	}
-+    }
-+
-+  /* Not found, try the kernel */
-+  if (!updated)
-+     {
-+       updated = 1;
-+       
-+       /* Mark all non-negative entries */
-+       for (arp = arps, up = &arps; arp; arp = arp->next)
-+	 if (arp->status != ARP_EMPTY)
-+	   arp->status = ARP_FREE;
-+       
-+       iface_enumerate(AF_UNSPEC, NULL, filter_mac);
-+       
-+       /* Remove all unconfirmed entries to old list, announce new ones. */
-+       for (arp = arps, up = &arps; arp; arp = arp->next)
-+	 if (arp->status == ARP_FREE)
-+	   {
-+	     *up = arp->next;
-+	     arp->next = old;
-+	     old = arp;
-+	   }
-+	 else
-+	   {
-+	     up = &arp->next;
-+	     if (arp->status == ARP_NEW)
-+	       {
-+		 char a[ADDRSTRLEN], m[ADDRSTRLEN];
-+		 union mysockaddr pa;
-+		 pa.sa.sa_family = arp->family;
-+		 pa.in.sin_addr.s_addr = arp->addr.addr.addr4.s_addr;
-+		 prettyprint_addr(&pa, a);
-+		 print_mac(m, arp->hwaddr, arp->hwlen);
-+		 my_syslog(LOG_INFO, _("new arp: %s %s"), a, m);
-+	       }
-+	   }
-+
-+       goto again;
-+     }
-+
-+  /* record failure, so we don't consult the kernel each time
-+     we're asked for this address */
-+  if (old)
-+    {
-+      arp = old;
-+      old = old->next;
-+    }
-+  else
-+    arp = whine_malloc(sizeof(struct arp_record));
-+  
-+  if (arp)
-+    {      
-+      arp->next = arps;
-+      arps = arp;
-+      arp->status = ARP_EMPTY;
-+      arp->family = addr->sa.sa_family;
-+      
-+      if (addr->sa.sa_family == AF_INET)
-+	arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
-+#ifdef HAVE_IPV6
-+      else
-+	memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
-+#endif
-+    }
-+	  
-+   return 0;
-+}
-+
-+
-diff --git a/src/dhcp6.c b/src/dhcp6.c
-index 8286ff4..7b1a7c7 100644
---- a/src/dhcp6.c
-+++ b/src/dhcp6.c
-@@ -27,17 +27,10 @@ struct iface_param {
-   int ind, addr_match;
- };
- 
--struct mac_param {
--  struct in6_addr *target;
--  unsigned char *mac;
--  unsigned int maclen;
--};
--
- 
- static int complete_context6(struct in6_addr *local,  int prefix,
- 			     int scope, int if_index, int flags, 
- 			     unsigned int preferred, unsigned int valid, void *vparam);
--static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
- static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); 
- 
- void dhcp6_init(void)
-@@ -264,9 +257,8 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
-      find the sender. Repeat a few times in case of packet loss. */
-   
-   struct neigh_packet neigh;
--  struct sockaddr_in6 addr;
--  struct mac_param mac_param;
--  int i;
-+  union mysockaddr addr;
-+  int i, maclen;
- 
-   neigh.type = ND_NEIGHBOR_SOLICIT;
-   neigh.code = 0;
-@@ -277,55 +269,31 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
-    
-   memset(&addr, 0, sizeof(addr));
- #ifdef HAVE_SOCKADDR_SA_LEN
--  addr.sin6_len = sizeof(struct sockaddr_in6);
-+  addr.in6.sin6_len = sizeof(struct sockaddr_in6);
- #endif
--  addr.sin6_family = AF_INET6;
--  addr.sin6_port = htons(IPPROTO_ICMPV6);
--  addr.sin6_addr = *client;
--  addr.sin6_scope_id = iface;
--  
--  mac_param.target = client;
--  mac_param.maclen = 0;
--  mac_param.mac = mac;
-+  addr.in6.sin6_family = AF_INET6;
-+  addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
-+  addr.in6.sin6_addr = *client;
-+  addr.in6.sin6_scope_id = iface;
-   
-   for (i = 0; i < 5; i++)
-     {
-       struct timespec ts;
-       
--      iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
--      
--      if (mac_param.maclen != 0)
-+      if ((maclen = find_mac(&addr, mac, 0)) != 0)
- 	break;
--      
--      sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
-+	  
-+      sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
-       
-       ts.tv_sec = 0;
-       ts.tv_nsec = 100000000; /* 100ms */
-       nanosleep(&ts, NULL);
-     }
- 
--  *maclenp = mac_param.maclen;
-+  *maclenp = maclen;
-   *mactypep = ARPHRD_ETHER;
- }
-     
--static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
--{
--  struct mac_param *parm = parmv;
--  
--  if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
--    {
--      if (maclen <= DHCP_CHADDR_MAX)
--	{
--	  parm->maclen = maclen;
--	  memcpy(parm->mac, mac, maclen);
--	}
--      
--      return 0; /* found, abort */
--    }
--  
--  return 1;
--}
--
- static int complete_context6(struct in6_addr *local,  int prefix,
- 			     int scope, int if_index, int flags, unsigned int preferred, 
- 			     unsigned int valid, void *vparam)
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 1c94f2a..4459594 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1516,3 +1516,7 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
- size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
- size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
- int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
-+
-+/* arp.c */
-+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy);
-+
-diff --git a/src/edns0.c b/src/edns0.c
-index f82ba1b..9d8c0b9 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -213,42 +213,15 @@ size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
-   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
- }
- 
--static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
--{
--  struct macparm *parm = parmv;
--  int match = 0;
--    
--  if (family == parm->l3->sa.sa_family)
--    {
--      if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
--	match = 1;
--#ifdef HAVE_IPV6
--      else
--	if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
--	  match = 1;
--#endif
--    }
-- 
--  if (!match)
--    return 1; /* continue */
--
--  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
--  
--  return 0; /* done */
--}	      
--     
- size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
- {
--  struct macparm parm;
--     
--  parm.header = header;
--  parm.limit = (unsigned char *)limit;
--  parm.plen = plen;
--  parm.l3 = l3;
-+  int maclen;
-+  unsigned char mac[DHCP_CHADDR_MAX];
- 
--  iface_enumerate(AF_UNSPEC, &parm, filter_mac);
-+  if ((maclen = find_mac(l3, mac, 1)) != 0)
-+    plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0); 
-   
--  return parm.plen; 
-+  return plen; 
- }
- 
- struct subnet_opt {
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/037-First_complete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch b/src/patches/dnsmasq/037-First_complete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch
deleted file mode 100644
index c89984a..0000000
--- a/src/patches/dnsmasq/037-First_complete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch
+++ /dev/null
@@ -1,976 +0,0 @@
-From 33702ab1f829789183cbaf6b1c39eee7ff15d744 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 28 Dec 2015 23:17:15 +0000
-Subject: [PATCH] First complete version of DNS-client-id EDNS0 and ARP
- tracking code.
-
----
- src/arp.c          |  148 +++++++++++++++++++++++++++++++---------------------
- src/config.h       |    2 +-
- src/dhcp6.c        |    6 +--
- src/dns-protocol.h |    2 +
- src/dnsmasq.c      |   23 ++++----
- src/dnsmasq.h      |   25 +++++----
- src/dnssec.c       |    2 +-
- src/edns0.c        |   72 ++++++++++++++++++++-----
- src/forward.c      |  107 ++++++++++++++++++-------------------
- src/helper.c       |   66 ++++++++++++++++++++---
- src/option.c       |    9 ++++
- src/rfc3315.c      |    7 +--
- 12 files changed, 308 insertions(+), 161 deletions(-)
-
-diff --git a/src/arp.c b/src/arp.c
-index b624dac..f41cdec 100644
---- a/src/arp.c
-+++ b/src/arp.c
-@@ -16,26 +16,31 @@
- 
- #include "dnsmasq.h"
- 
--#define ARP_FREE  0
--#define ARP_FOUND 1
--#define ARP_NEW   2
--#define ARP_EMPTY 3
-+/* Time between forced re-loads from kernel. */
-+#define INTERVAL 90
-+
-+#define ARP_MARK  0
-+#define ARP_FOUND 1  /* Confirmed */
-+#define ARP_NEW   2  /* Newly created */
-+#define ARP_EMPTY 3  /* No MAC addr */
- 
- struct arp_record {
--  short hwlen, status;
-+  unsigned short hwlen, status;
-   int family;
-   unsigned char hwaddr[DHCP_CHADDR_MAX]; 
-   struct all_addr addr;
-   struct arp_record *next;
- };
- 
--static struct arp_record *arps = NULL, *old = NULL;
-+static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
-+static time_t last = 0;
- 
- static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
- {
--  int match = 0;
-   struct arp_record *arp;
- 
-+  (void)parmv;
-+
-   if (maclen > DHCP_CHADDR_MAX)
-     return 1;
- 
-@@ -58,16 +63,18 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
- 	}
- #endif
- 
--      if (arp->status != ARP_EMPTY && arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
--	arp->status = ARP_FOUND;
--      else
-+      if (arp->status == ARP_EMPTY)
- 	{
--	  /* existing address, MAC changed or arrived new. */
-+	  /* existing address, was negative. */
- 	  arp->status = ARP_NEW;
- 	  arp->hwlen = maclen;
--	  arp->family = family;
- 	  memcpy(arp->hwaddr, mac, maclen);
- 	}
-+      else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
-+	/* Existing entry matches - confirm. */
-+	arp->status = ARP_FOUND;
-+      else
-+	continue;
-       
-       break;
-     }
-@@ -75,10 +82,10 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
-   if (!arp)
-     {
-       /* New entry */
--      if (old)
-+      if (freelist)
- 	{
--	  arp = old;
--	  old = old->next;
-+	  arp = freelist;
-+	  freelist = freelist->next;
- 	}
-       else if (!(arp = whine_malloc(sizeof(struct arp_record))))
- 	return 1;
-@@ -101,81 +108,72 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
- }
- 
- /* If in lazy mode, we cache absence of ARP entries. */
--int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
-+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
- {
-   struct arp_record *arp, **up;
-   int updated = 0;
- 
-  again:
-   
--  for (arp = arps; arp; arp = arp->next)
--    {
--      if (addr->sa.sa_family == arp->family)
--	{
--	  if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
--	    continue;
--	}
-+  /* If the database is less then INTERVAL old, look in there */
-+  if (difftime(now, last) < INTERVAL)
-+    for (arp = arps; arp; arp = arp->next)
-+      {
-+	if (addr->sa.sa_family == arp->family)
-+	  {
-+	    if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
-+	      continue;
-+	  }
- #ifdef HAVE_IPV6
--      else
--	{
--	  if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
--	    continue;
--	}
-+	else
-+	  {
-+	    if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
-+	      continue;
-+	  }
- #endif
--      
--      /* Only accept poitive entries unless in lazy mode. */
--      if (arp->status != ARP_EMPTY || lazy || updated)
--	{
--	  if (mac && arp->hwlen != 0)
--	    memcpy(mac, arp->hwaddr, arp->hwlen);
--	  return arp->hwlen;
--	}
--    }
--
-+	
-+	/* Only accept poitive entries unless in lazy mode. */
-+	if (arp->status != ARP_EMPTY || lazy || updated)
-+	  {
-+	    if (mac && arp->hwlen != 0)
-+	      memcpy(mac, arp->hwaddr, arp->hwlen);
-+	    return arp->hwlen;
-+	  }
-+      }
-+  
-   /* Not found, try the kernel */
-   if (!updated)
-      {
-        updated = 1;
--       
-+       last = now;
-+
-        /* Mark all non-negative entries */
-        for (arp = arps, up = &arps; arp; arp = arp->next)
- 	 if (arp->status != ARP_EMPTY)
--	   arp->status = ARP_FREE;
-+	   arp->status = ARP_MARK;
-        
-        iface_enumerate(AF_UNSPEC, NULL, filter_mac);
-        
--       /* Remove all unconfirmed entries to old list, announce new ones. */
-+       /* Remove all unconfirmed entries to old list. */
-        for (arp = arps, up = &arps; arp; arp = arp->next)
--	 if (arp->status == ARP_FREE)
-+	 if (arp->status == ARP_MARK)
- 	   {
- 	     *up = arp->next;
- 	     arp->next = old;
- 	     old = arp;
- 	   }
- 	 else
--	   {
--	     up = &arp->next;
--	     if (arp->status == ARP_NEW)
--	       {
--		 char a[ADDRSTRLEN], m[ADDRSTRLEN];
--		 union mysockaddr pa;
--		 pa.sa.sa_family = arp->family;
--		 pa.in.sin_addr.s_addr = arp->addr.addr.addr4.s_addr;
--		 prettyprint_addr(&pa, a);
--		 print_mac(m, arp->hwaddr, arp->hwlen);
--		 my_syslog(LOG_INFO, _("new arp: %s %s"), a, m);
--	       }
--	   }
--
-+	   up = &arp->next;
-+	   
-        goto again;
-      }
- 
-   /* record failure, so we don't consult the kernel each time
-      we're asked for this address */
--  if (old)
-+  if (freelist)
-     {
--      arp = old;
--      old = old->next;
-+      arp = freelist;
-+      freelist = freelist->next;
-     }
-   else
-     arp = whine_malloc(sizeof(struct arp_record));
-@@ -198,4 +196,36 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
-    return 0;
- }
- 
-+int do_arp_script_run(void)
-+{
-+  struct arp_record *arp;
-+  
-+  /* Notify any which went, then move to free list */
-+  if (old)
-+    {
-+#ifdef HAVE_SCRIPT
-+      if (option_bool(OPT_DNS_CLIENT))
-+	queue_arp(ACTION_ARP_OLD, old->hwaddr, old->hwlen, old->family, &old->addr);
-+#endif
-+      arp = old;
-+      old = arp->next;
-+      arp->next = freelist;
-+      freelist = arp;
-+      return 1;
-+    }
-+
-+  for (arp = arps; arp; arp = arp->next)
-+    if (arp->status == ARP_NEW)
-+      {
-+#ifdef HAVE_SCRIPT
-+	if (option_bool(OPT_DNS_CLIENT))
-+	  queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
-+#endif
-+	arp->status = ARP_FOUND;
-+	return 1;
-+      }
-+
-+  return 0;
-+}
-+
- 
-diff --git a/src/config.h b/src/config.h
-index f75fe9d..309be6b 100644
---- a/src/config.h
-+++ b/src/config.h
-@@ -337,7 +337,7 @@ HAVE_SOCKADDR_SA_LEN
- #define HAVE_DHCP
- #endif
- 
--#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
-+#if defined(NO_SCRIPT) || defined(NO_FORK)
- #undef HAVE_SCRIPT
- #undef HAVE_LUASCRIPT
- #endif
-diff --git a/src/dhcp6.c b/src/dhcp6.c
-index 7b1a7c7..0e2e171 100644
---- a/src/dhcp6.c
-+++ b/src/dhcp6.c
-@@ -220,7 +220,7 @@ void dhcp6_packet(time_t now)
- 	  inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
- 	  
- 	  if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
--	    relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
-+	    relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
- 	  return;
- 	}
-       
-@@ -250,7 +250,7 @@ void dhcp6_packet(time_t now)
-     }
- }
- 
--void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
-+void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
- {
-   /* Recieving a packet from a host does not populate the neighbour
-      cache, so we send a neighbour discovery request if we can't 
-@@ -280,7 +280,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
-     {
-       struct timespec ts;
-       
--      if ((maclen = find_mac(&addr, mac, 0)) != 0)
-+      if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
- 	break;
- 	  
-       sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
-diff --git a/src/dns-protocol.h b/src/dns-protocol.h
-index 6cf5158..addfa9e 100644
---- a/src/dns-protocol.h
-+++ b/src/dns-protocol.h
-@@ -77,6 +77,8 @@
- 
- #define EDNS0_OPTION_MAC            65001 /* dyndns.org temporary assignment */
- #define EDNS0_OPTION_CLIENT_SUBNET  8     /* IANA */
-+#define EDNS0_OPTION_NOMDEVICEID    65073 /* Nominum temporary assignment */
-+#define EDNS0_OPTION_NOMCPEID       65074 /* Nominum temporary assignment */
- 
- struct dns_header {
-   u16 id;
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 45761cc..229693f 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -245,8 +245,11 @@ int main (int argc, char **argv)
-   /* Note that order matters here, we must call lease_init before
-      creating any file descriptors which shouldn't be leaked
-      to the lease-script init process. We need to call common_init
--     before lease_init to allocate buffers it uses.*/
--  if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
-+     before lease_init to allocate buffers it uses.
-+     The script subsystrm relies on DHCP buffers, hence the last two
-+     conditions below. */  
-+  if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || 
-+      daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_ADD_MAC))
-     {
-       dhcp_common_init();
-       if (daemon->dhcp || daemon->doing_dhcp6)
-@@ -553,8 +556,9 @@ int main (int argc, char **argv)
-    /* if we are to run scripts, we need to fork a helper before dropping root. */
-   daemon->helperfd = -1;
- #ifdef HAVE_SCRIPT 
--  if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
--    daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
-+  if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_ADD_MAC)) && 
-+      (daemon->lease_change_command || daemon->luascript))
-+      daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
- #endif
- 
-   if (!option_bool(OPT_DEBUG) && getuid() == 0)   
-@@ -914,9 +918,9 @@ int main (int argc, char **argv)
-       
-       poll_listen(piperead, POLLIN);
- 
--#ifdef HAVE_DHCP
--#  ifdef HAVE_SCRIPT
--      while (helper_buf_empty() && do_script_run(now));
-+#ifdef HAVE_SCRIPT
-+      while (helper_buf_empty() && do_script_run(now)); 
-+      while (helper_buf_empty() && do_arp_script_run());
- 
- #    ifdef HAVE_TFTP
-       while (helper_buf_empty() && do_tftp_script_run());
-@@ -924,16 +928,17 @@ int main (int argc, char **argv)
- 
-       if (!helper_buf_empty())
- 	poll_listen(daemon->helperfd, POLLOUT);
--#  else
-+#else
-       /* need this for other side-effects */
-       while (do_script_run(now));
-+      while (do_arp_script_run(now));
- 
- #    ifdef HAVE_TFTP 
-       while (do_tftp_script_run());
- #    endif
- 
--#  endif
- #endif
-+
-    
-       /* must do this just before select(), when we know no
- 	 more calls to my_syslog() can occur */
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 4459594..fec0f8d 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -235,7 +235,8 @@ struct event_desc {
- #define OPT_LOOP_DETECT    50
- #define OPT_EXTRALOG       51
- #define OPT_TFTP_NO_FAIL   52
--#define OPT_LAST           53
-+#define OPT_DNS_CLIENT     53
-+#define OPT_LAST           54
- 
- /* extra flags for my_syslog, we use a couple of facilities since they are known 
-    not to occupy the same bits as priorities, no matter how syslog.h is set up. */
-@@ -633,6 +634,8 @@ struct frec {
- #define ACTION_OLD           3
- #define ACTION_ADD           4
- #define ACTION_TFTP          5
-+#define ACTION_ARP           6
-+#define ACTION_ARP_OLD       7
- 
- #define LEASE_NEW            1  /* newly created */
- #define LEASE_CHANGED        2  /* modified */
-@@ -948,6 +951,7 @@ extern struct daemon {
-   int cachesize, ftabsize;
-   int port, query_port, min_port;
-   unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
-+  char *dns_client_id;
-   struct hostsfile *addn_hosts;
-   struct dhcp_context *dhcp, *dhcp6;
-   struct ra_interface *ra_interfaces;
-@@ -1135,7 +1139,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
- #endif
- 
- /* dnssec.c */
--size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
-+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
- int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
- int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
- int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
-@@ -1372,6 +1376,8 @@ void queue_script(int action, struct dhcp_lease *lease,
- #ifdef HAVE_TFTP
- void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
- #endif
-+void queue_arp(int action, unsigned char *mac, int maclen,
-+	       int family, struct all_addr *addr);
- int helper_buf_empty(void);
- #endif
- 
-@@ -1408,7 +1414,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
- void make_duid(time_t now);
- void dhcp_construct_contexts(time_t now);
- void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, 
--		    unsigned int *maclenp, unsigned int *mactypep);
-+		    unsigned int *maclenp, unsigned int *mactypep, time_t now);
- #endif
-   
- /* rfc3315.c */
-@@ -1416,7 +1422,8 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
- unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,  
- 			   struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
- 			   size_t sz, struct in6_addr *client_addr, time_t now);
--void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
-+void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, 
-+		     u32 scope_id, time_t now);
- 
- unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
- #endif
-@@ -1512,11 +1519,11 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
- 				   size_t *len, unsigned char **p, int *is_sign, int *is_last);
- size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
- 			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
--size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
--size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
--size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
-+size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
-+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, 
-+			union mysockaddr *source, time_t now, int *check_subnet);
- int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
- 
- /* arp.c */
--int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy);
--
-+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
-+int do_arp_script_run(void);
-diff --git a/src/dnssec.c b/src/dnssec.c
-index ed2d3fe..918a2dc 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -2173,7 +2173,7 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
-     }
- }
- 
--size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, 
-+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, 
- 			     int type, union mysockaddr *addr, int edns_pktsz)
- {
-   unsigned char *p;
-diff --git a/src/edns0.c b/src/edns0.c
-index 9d8c0b9..12e0210 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -94,13 +94,6 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
-   
-   return ret;
- }
--
--struct macparm {
--  unsigned char *limit;
--  struct dns_header *header;
--  size_t plen;
--  union mysockaddr *l3;
--};
-  
- size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
- 			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
-@@ -208,19 +201,54 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
-   return p - (unsigned char *)header;
- }
- 
--size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
-+size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
- {
-   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
- }
- 
--size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
-+static unsigned char char64(unsigned char c)
-+{
-+  return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
-+}
-+
-+static void encoder(unsigned char *in, char *out)
-+{
-+  out[0] = char64(in[0]>>2);
-+  out[1] = char64((in[0]<<4) | (in[1]>>4));
-+  out[2] = char64((in[1]<<2) | (in[2]>>6));
-+  out[3] = char64(in[2]);
-+}
-+
-+static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
- {
-   int maclen;
-   unsigned char mac[DHCP_CHADDR_MAX];
-+  char encode[8]; /* handle 6 byte MACs */
-+
-+  if ((maclen = find_mac(l3, mac, 1, now)) == 6)
-+    {
-+      encoder(mac, encode);
-+      encoder(mac+3, encode+4);
-+      
-+      plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, 8, 0); 
-+    }
-+
-+  if (daemon->dns_client_id)
-+    plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, 
-+			    (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0);
-+
-+  return plen; 
-+}
-+
- 
--  if ((maclen = find_mac(l3, mac, 1)) != 0)
-+static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
-+{
-+  int maclen;
-+  unsigned char mac[DHCP_CHADDR_MAX];
-+
-+  if ((maclen = find_mac(l3, mac, 1, now)) != 0)
-     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0); 
--  
-+    
-   return plen; 
- }
- 
-@@ -296,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
-   return len + 4;
- }
-  
--size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
-+static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
- {
-   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-   
-@@ -344,3 +372,23 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
-    
-    return 1;
- }
-+
-+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, 
-+			union mysockaddr *source, time_t now, int *check_subnet)    
-+{
-+  *check_subnet = 0;
-+
-+  if (option_bool(OPT_ADD_MAC))
-+    plen  = add_mac(header, plen, limit, source, now);
-+  
-+  if (option_bool(OPT_DNS_CLIENT))
-+    plen = add_dns_client(header, plen, limit, source, now);
-+  
-+  if (option_bool(OPT_CLIENT_SUBNET))
-+    {
-+      plen = add_source_addr(header, plen, limit, source); 
-+      *check_subnet = 1;
-+    }
-+	  
-+  return plen;
-+}
-diff --git a/src/forward.c b/src/forward.c
-index c0e4d9a..911f46e 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -388,36 +388,27 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-   if (!flags && forward)
-     {
-       struct server *firstsentto = start;
--      int forwarded = 0;
-+      int subnet, forwarded = 0;
-       size_t edns0_len;
- 
-       /* If a query is retried, use the log_id for the retry when logging the answer. */
-       forward->log_id = daemon->log_id;
-       
--      if (option_bool(OPT_ADD_MAC))
--	{
--	  size_t new = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
--	  if (new != plen)
--	    {
--	      plen = new;
--	      forward->flags |= FREC_ADDED_PHEADER;
--	    }
--	}
--
--      if (option_bool(OPT_CLIENT_SUBNET))
-+      edns0_len  = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
-+      
-+      if (edns0_len != plen)
- 	{
--	  size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source); 
--	  if (new != plen)
--	    {
--	      plen = new;
--	      forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
--	    }
-+	  plen = edns0_len;
-+	  forward->flags |= FREC_ADDED_PHEADER;
-+	  
-+	  if (subnet)
-+	    forward->flags |= FREC_HAS_SUBNET;
- 	}
--
-+      
- #ifdef HAVE_DNSSEC
-       if (option_bool(OPT_DNSSEC_VALID))
- 	{
--	  size_t new = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
-+	  size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
- 	 
- 	  if (new != plen)
- 	    forward->flags |= FREC_ADDED_PHEADER;
-@@ -607,15 +598,30 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
- 	    }
- 	  else
- 	    {
-+	      unsigned short udpsz;
-+
- 	      /* If upstream is advertising a larger UDP packet size
- 		 than we allow, trim it so that we don't get overlarge
- 		 requests for the client. We can't do this for signed packets. */
--	      unsigned short udpsz;
--	      unsigned char *psave = sizep;
--	      
- 	      GETSHORT(udpsz, sizep);
- 	      if (udpsz > daemon->edns_pktsz)
--		PUTSHORT(daemon->edns_pktsz, psave);
-+		{
-+		  sizep -= 2;
-+		  PUTSHORT(daemon->edns_pktsz, sizep);
-+		}
-+
-+#ifdef HAVE_DNSSEC
-+	      /* If the client didn't set the do bit, but we did, reset it. */
-+	      if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
-+		{
-+		  unsigned short flags;
-+		  sizep += 2; /* skip RCODE */
-+		  GETSHORT(flags, sizep);
-+		  flags &= ~0x8000;
-+		  sizep -= 2;
-+		  PUTSHORT(flags, sizep);
-+		}
-+#endif
- 	    }
- 	}
-     }
-@@ -674,14 +680,11 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     }
-   
- #ifdef HAVE_DNSSEC
--  if (bogusanswer && !(header->hb4 & HB4_CD)) 
-+  if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
-     {
--      if (!option_bool(OPT_DNSSEC_DEBUG))
--	{
--	  /* Bogus reply, turn into SERVFAIL */
--	  SET_RCODE(header, SERVFAIL);
--	  munged = 1;
--	}
-+      /* Bogus reply, turn into SERVFAIL */
-+      SET_RCODE(header, SERVFAIL);
-+      munged = 1;
-     }
- 
-   if (option_bool(OPT_DNSSEC_VALID))
-@@ -802,7 +805,7 @@ void reply_query(int fd, int family, time_t now)
- 	      if (forward->flags |= FREC_AD_QUESTION)
- 		header->hb4 |= HB4_AD;
- 	      if (forward->flags & FREC_DO_QUESTION)
--		add_do_bit(header, nn,  (char *)pheader + plen);
-+		add_do_bit(header, nn,  (unsigned char *)pheader + plen);
- 	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
- 	      return;
- 	    }
-@@ -927,13 +930,13 @@ void reply_query(int fd, int family, time_t now)
- 		      if (status == STAT_NEED_KEY)
- 			{
- 			  new->flags |= FREC_DNSKEY_QUERY; 
--			  nn = dnssec_generate_query(header, ((char *) header) + server->edns_pktsz,
-+			  nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
- 						     daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
- 			}
- 		      else 
- 			{
- 			  new->flags |= FREC_DS_QUERY;
--			  nn = dnssec_generate_query(header,((char *) header) + server->edns_pktsz,
-+			  nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
- 						     daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
- 			}
- 		      if ((hash = hash_questions(header, nn, daemon->namebuff)))
-@@ -1434,7 +1437,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
- 	  break;
- 	}
- 	 
--      m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class, 
-+      m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 
- 				new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
-       
-       *length = htons(m);
-@@ -1548,8 +1551,6 @@ unsigned char *tcp_request(int confd, time_t now,
-       daemon->log_display_id = ++daemon->log_id;
-       daemon->log_source_addr = &peer_addr;
-       
--      check_subnet = 0;
--
-       /* save state of "cd" flag in query */
-       if ((checking_disabled = header->hb4 & HB4_CD))
- 	no_cache_dnssec = 1;
-@@ -1627,20 +1628,14 @@ unsigned char *tcp_request(int confd, time_t now,
- 	      struct all_addr *addrp = NULL;
- 	      int type = 0;
- 	      char *domain = NULL;
--	      
--	      if (option_bool(OPT_ADD_MAC))
--		size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
--	      	
--	      if (option_bool(OPT_CLIENT_SUBNET))
-+	      size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
-+
-+	      if (size != new_size)
- 		{
--		  size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr);
--		  if (size != new)
--		    {
--		      size = new;
--		      check_subnet = 1;
--		    }
-+		  added_pheader = 1;
-+		  size = new_size;
- 		}
--
-+	      
- 	      if (gotname)
- 		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
- 	      
-@@ -1715,20 +1710,20 @@ unsigned char *tcp_request(int confd, time_t now,
- 			    }
- 			  
- #ifdef HAVE_DNSSEC
--			  added_pheader = 0;			  
- 			  if (option_bool(OPT_DNSSEC_VALID))
- 			    {
--			      size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
-+			      new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
-+			      
-+			      if (size != new_size)
-+				{
-+				  added_pheader = 1;
-+				  size = new_size;
-+				}
- 			      
- 			      /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
- 				 this allows it to select auth servers when one is returning bad data. */
- 			      if (option_bool(OPT_DNSSEC_DEBUG))
- 				header->hb4 |= HB4_CD;
--			      
--			      if (size != new_size)
--				added_pheader = 1;
--			      
--			      size = new_size;
- 			    }
- #endif
- 			}
-diff --git a/src/helper.c b/src/helper.c
-index 1fee72d..517cfd9 100644
---- a/src/helper.c
-+++ b/src/helper.c
-@@ -219,7 +219,18 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
- 	  action_str = "tftp";
- 	  is6 = (data.flags != AF_INET);
- 	}
--      else
-+      else if (data.action == ACTION_ARP)
-+	{
-+	  action_str = "arp";
-+	  is6 = (data.flags != AF_INET);
-+	}
-+       else if (data.action == ACTION_ARP_OLD)
-+	{
-+	  action_str = "arp-old";
-+	  is6 = (data.flags != AF_INET);
-+	  data.action = ACTION_ARP;
-+	}
-+       else 
- 	continue;
- 
-       	
-@@ -321,6 +332,22 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
- 		  lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
- 		}
- 	    }
-+	  else if (data.action == ACTION_ARP)
-+	    {
-+	      lua_getglobal(lua, "arp"); 
-+	      if (lua_type(lua, -1) != LUA_TFUNCTION)
-+		lua_pop(lua, 1); /* arp function optional */
-+	      else
-+		{
-+		  lua_pushstring(lua, action_str); /* arg1 - action */
-+		  lua_newtable(lua);               /* arg2 - data table */
-+		  lua_pushstring(lua, daemon->addrbuff);
-+		  lua_setfield(lua, -2, "client_address");
-+		  lua_pushstring(lua, daemon->dhcp_buff);
-+		  lua_setfield(lua, -2, "mac_address");
-+		  lua_call(lua, 2, 0);	/* pass 2 values, expect 0 */
-+		}
-+	    }
- 	  else
- 	    {
- 	      lua_getglobal(lua, "lease");     /* function to call */
-@@ -478,7 +505,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
- 	  continue;
- 	}
-       
--      if (data.action != ACTION_TFTP)
-+      if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
- 	{
- #ifdef HAVE_DHCP6
- 	  my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
-@@ -550,10 +577,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
- 	  my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
- 	  if (data.action == ACTION_OLD_HOSTNAME)
- 	    hostname = NULL;
--	}
--
--      my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
--      
-+	  
-+	  my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
-+    }
-       /* we need to have the event_fd around if exec fails */
-       if ((i = fcntl(event_fd, F_GETFD)) != -1)
- 	fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
-@@ -563,8 +589,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
-       if (err == 0)
- 	{
- 	  execl(daemon->lease_change_command, 
--		p ? p+1 : daemon->lease_change_command,
--		action_str, is6 ? daemon->packet : daemon->dhcp_buff, 
-+		p ? p+1 : daemon->lease_change_command, action_str, 
-+		(is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff, 
- 		daemon->addrbuff, hostname, (char*)NULL);
- 	  err = errno;
- 	}
-@@ -760,6 +786,30 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
- }
- #endif
- 
-+void queue_arp(int action, unsigned char *mac, int maclen, int family, struct all_addr *addr)
-+{
-+  /* no script */
-+  if (daemon->helperfd == -1)
-+    return;
-+  
-+  buff_alloc(sizeof(struct script_data));
-+  memset(buf, 0, sizeof(struct script_data));
-+
-+  buf->action = action;
-+  buf->hwaddr_len = maclen;
-+  buf->hwaddr_type =  ARPHRD_ETHER; 
-+  if ((buf->flags = family) == AF_INET)
-+    buf->addr = addr->addr.addr4;
-+#ifdef HAVE_IPV6
-+  else
-+    buf->addr6 = addr->addr.addr6;
-+#endif
-+  
-+  memcpy(buf->hwaddr, mac, maclen);
-+  
-+  bytes_in_buf = sizeof(struct script_data);
-+}
-+
- int helper_buf_empty(void)
- {
-   return bytes_in_buf == 0;
-diff --git a/src/option.c b/src/option.c
-index 71beb98..f359bc5 100644
---- a/src/option.c
-+++ b/src/option.c
-@@ -154,6 +154,7 @@ struct myoption {
- #define LOPT_HOST_INOTIFY  342
- #define LOPT_DNSSEC_STAMP  343
- #define LOPT_TFTP_NO_FAIL  344
-+#define LOPT_DNS_CLIENT_ID 355
- 
- #ifdef HAVE_GETOPT_LONG
- static const struct option opts[] =  
-@@ -281,6 +282,7 @@ static const struct myoption opts[] =
-     { "rebind-localhost-ok", 0, 0,  LOPT_LOC_REBND },
-     { "add-mac", 0, 0, LOPT_ADD_MAC },
-     { "add-subnet", 2, 0, LOPT_ADD_SBNET },
-+    { "add-dns-client", 2, 0 , LOPT_DNS_CLIENT_ID },
-     { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
-     { "dhcp-sequential-ip", 0, 0,  LOPT_INCR_ADDR },
-     { "conntrack", 0, 0, LOPT_CONNTRACK },
-@@ -446,6 +448,7 @@ static struct {
-   { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
-   { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
-   { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
-+  { LOPT_DNS_CLIENT_ID, ARG_ONE, "<proxyname>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
-   { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
-   { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
-   { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
-@@ -2150,6 +2153,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
- 	}
-       break;
-       
-+    case LOPT_DNS_CLIENT_ID: /* --add-dns-client */
-+       set_option_bool(OPT_DNS_CLIENT);
-+       if (arg)
-+	daemon->dns_client_id = opt_string_alloc(arg);
-+      break;
-+
-     case 'u':  /* --user */
-       daemon->username = opt_string_alloc(arg);
-       break;
-diff --git a/src/rfc3315.c b/src/rfc3315.c
-index 3ed8623..31bb41b 100644
---- a/src/rfc3315.c
-+++ b/src/rfc3315.c
-@@ -130,7 +130,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
-       MAC address from the local ND cache. */
-       
-       if (!state->link_address)
--	get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
-+	get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
-       else
- 	{
- 	  struct dhcp_context *c;
-@@ -2054,7 +2054,8 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
-   return ret;
- } 
- 
--void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
-+void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, 
-+		     struct in6_addr *peer_address, u32 scope_id, time_t now)
- {
-   /* ->local is same value for all relays on ->current chain */
-   
-@@ -2068,7 +2069,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer
-   unsigned char mac[DHCP_CHADDR_MAX];
- 
-   inet_pton(AF_INET6, ALL_SERVERS, &multicast);
--  get_client_mac(peer_address, scope_id, mac, &maclen, &mactype);
-+  get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
- 
-   /* source address == relay address */
-   from.addr.addr6 = relay->local.addr.addr6;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.patch b/src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.patch
deleted file mode 100644
index 2c25d30..0000000
--- a/src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 8e39c34077cdad5b8e7cc799443bf8d1f22a1e80 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Thu, 31 Dec 2015 16:18:11 +0000
-Subject: [PATCH] Correct logic for when to start helper.
-
----
- src/dnsmasq.c |    2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 229693f..009d357 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -556,7 +556,7 @@ int main (int argc, char **argv)
-    /* if we are to run scripts, we need to fork a helper before dropping root. */
-   daemon->helperfd = -1;
- #ifdef HAVE_SCRIPT 
--  if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_ADD_MAC)) && 
-+  if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_DNS_CLIENT)) && 
-       (daemon->lease_change_command || daemon->luascript))
-       daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
- #endif
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/039-Trivial_code_tweak.patch b/src/patches/dnsmasq/039-Trivial_code_tweak.patch
deleted file mode 100644
index ce0d23b..0000000
--- a/src/patches/dnsmasq/039-Trivial_code_tweak.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From ec0628c4b2a06e1fc21216091bb040d61a43b271 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Thu, 31 Dec 2015 20:55:39 +0000
-Subject: [PATCH] Trivial code tweak.
-
----
- src/dnssec.c |    8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 918a2dc..0e5cbe8 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1599,12 +1599,12 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
- 		if (!CHECK_LEN(header, p, plen, rdlen))
- 		  return 0;
- 		
--		/* If we can prove that there's no NS record, return that information. */
--		if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
--		  *nons = 0;
--		
- 		if (rdlen >= 2 && p[0] == 0)
- 		  {
-+		    /* If we can prove that there's no NS record, return that information. */
-+		    if (nons && (p[2] & (0x80 >> T_NS)) != 0)
-+		      *nons = 0;
-+		
- 		    /* A CNAME answer would also be valid, so if there's a CNAME is should 
- 		       have been returned. */
- 		    if ((p[2] & (0x80 >> T_CNAME)) != 0)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_broke_DNSSEC_sig_timestamps_when_far_in_the_future.patch b/src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_broke_DNSSEC_sig_timestamps_when_far_in_the_future.patch
deleted file mode 100644
index b7458ff..0000000
--- a/src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_broke_DNSSEC_sig_timestamps_when_far_in_the_future.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From cc7cb0b89326b7c2ecdd4848002d10a4cbed894d Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 4 Jan 2016 16:04:51 +0000
-Subject: [PATCH] Fix datatype-sixe botch which broke DNSSEC sig timestamps
- when far in the future.
-
----
- src/dnssec.c |   10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 0e5cbe8..5a1190d 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -436,7 +436,7 @@ static int count_labels(char *name)
- }
- 
- /* Implement RFC1982 wrapped compare for 32-bit numbers */
--static int serial_compare_32(unsigned long s1, unsigned long s2)
-+static int serial_compare_32(u32 s1, u32 s2)
- {
-   if (s1 == s2)
-     return SERIAL_EQ;
-@@ -503,7 +503,7 @@ int setup_timestamp(void)
- }
- 
- /* Check whether today/now is between date_start and date_end */
--static int check_date_range(unsigned long date_start, unsigned long date_end)
-+static int check_date_range(u32 date_start, u32 date_end)
- {
-   unsigned long curtime = time(0);
-  
-@@ -796,11 +796,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- 			  char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
- {
-   unsigned char *p;
--  int rdlen, j, name_labels, sig_expiration, sig_inception;
-+  int rdlen, j, name_labels, algo, labels, orig_ttl, key_tag;
-   struct crec *crecp = NULL;
--  int algo, labels, orig_ttl, key_tag;
-   u16 *rr_desc = rrfilter_desc(type);
-- 
-+  u32 sig_expiration, sig_inception
-+;
-   if (wildcard_out)
-     *wildcard_out = NULL;
-   
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/041-Fix_botch_in_new_arp-cache_linked-list_code_resulting_in_100percent_CPU_spin.patch b/src/patches/dnsmasq/041-Fix_botch_in_new_arp-cache_linked-list_code_resulting_in_100percent_CPU_spin.patch
deleted file mode 100644
index c418124..0000000
--- a/src/patches/dnsmasq/041-Fix_botch_in_new_arp-cache_linked-list_code_resulting_in_100percent_CPU_spin.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From d917275e481add809cd5c40650f339ae994ee35f Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 4 Jan 2016 17:17:41 +0000
-Subject: [PATCH] Fix botch in new arp-cache linked-list code resulting in
- 100% CPU spin.
-
----
- src/arp.c |   24 ++++++++++++++----------
- 1 file changed, 14 insertions(+), 10 deletions(-)
-
-diff --git a/src/arp.c b/src/arp.c
-index f41cdec..d17eedb 100644
---- a/src/arp.c
-+++ b/src/arp.c
-@@ -110,7 +110,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
- /* If in lazy mode, we cache absence of ARP entries. */
- int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
- {
--  struct arp_record *arp, **up;
-+  struct arp_record *arp, *tmp, **up;
-   int updated = 0;
- 
-  again:
-@@ -155,16 +155,20 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
-        iface_enumerate(AF_UNSPEC, NULL, filter_mac);
-        
-        /* Remove all unconfirmed entries to old list. */
--       for (arp = arps, up = &arps; arp; arp = arp->next)
--	 if (arp->status == ARP_MARK)
--	   {
--	     *up = arp->next;
--	     arp->next = old;
--	     old = arp;
--	   }
--	 else
--	   up = &arp->next;
-+       for (arp = arps, up = &arps; arp; arp = tmp)
-+	 {
-+	   tmp = arp->next;
- 	   
-+	   if (arp->status == ARP_MARK)
-+	     {
-+	       *up = arp->next;
-+	       arp->next = old;
-+	       old = arp;
-+	     }
-+	   else
-+	     up = &arp->next;
-+	 }
-+
-        goto again;
-      }
- 
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/042-Handle_building_with_script_support_enabled_and_DHCP_disabled.patch b/src/patches/dnsmasq/042-Handle_building_with_script_support_enabled_and_DHCP_disabled.patch
deleted file mode 100644
index a6255a5..0000000
--- a/src/patches/dnsmasq/042-Handle_building_with_script_support_enabled_and_DHCP_disabled.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 53a9173fc0b36d9427adb4ee9ac44df425717e84 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Wed, 6 Jan 2016 17:59:13 +0000
-Subject: [PATCH] Handle building with script support enabled and DHCP
- disabled.
-
----
- src/dnsmasq.c |    8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 4ab56f1..5cbfdbd 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -919,7 +919,10 @@ int main (int argc, char **argv)
-       poll_listen(piperead, POLLIN);
- 
- #ifdef HAVE_SCRIPT
-+#    ifdef HAVE_DHCP
-       while (helper_buf_empty() && do_script_run(now)); 
-+#    endif
-+
-       while (helper_buf_empty() && do_arp_script_run());
- 
- #    ifdef HAVE_TFTP
-@@ -930,7 +933,10 @@ int main (int argc, char **argv)
- 	poll_listen(daemon->helperfd, POLLOUT);
- #else
-       /* need this for other side-effects */
-+#    ifdef HAVE_DHCP
-       while (do_script_run(now));
-+#    endif
-+
-       while (do_arp_script_run(now));
- 
- #    ifdef HAVE_TFTP 
-@@ -1312,7 +1318,7 @@ static void async_event(int pipe, time_t now)
- 	  if (daemon->tcp_pids[i] != 0)
- 	    kill(daemon->tcp_pids[i], SIGALRM);
- 	
--#if defined(HAVE_SCRIPT)
-+#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP)
- 	/* handle pending lease transitions */
- 	if (daemon->helperfd != -1)
- 	  {
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/043-Update_copyright_notices_Happy_new_year.patch b/src/patches/dnsmasq/043-Update_copyright_notices_Happy_new_year.patch
deleted file mode 100644
index 0a166bc..0000000
--- a/src/patches/dnsmasq/043-Update_copyright_notices_Happy_new_year.patch
+++ /dev/null
@@ -1,473 +0,0 @@
-From c49778df4a098aab4e29e0d3e360263293e417c0 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Wed, 6 Jan 2016 18:52:33 +0000
-Subject: [PATCH] Update copyright notices. Happy new year!
-
----
- Makefile             |    2 +-
- debian/copyright     |    2 +-
- src/arp.c            |    2 +-
- src/auth.c           |    2 +-
- src/blockdata.c      |    2 +-
- src/bpf.c            |    2 +-
- src/cache.c          |    2 +-
- src/config.h         |    2 +-
- src/conntrack.c      |    2 +-
- src/dbus.c           |    2 +-
- src/dhcp-common.c    |    2 +-
- src/dhcp-protocol.h  |    2 +-
- src/dhcp.c           |    2 +-
- src/dhcp6-protocol.h |    2 +-
- src/dhcp6.c          |    2 +-
- src/dns-protocol.h   |    2 +-
- src/dnsmasq.c        |    2 +-
- src/dnsmasq.h        |    4 ++--
- src/dnssec.c         |    2 +-
- src/domain.c         |    2 +-
- src/edns0.c          |    2 +-
- src/forward.c        |    2 +-
- src/helper.c         |    2 +-
- src/inotify.c        |    2 +-
- src/ip6addr.h        |    2 +-
- src/lease.c          |    2 +-
- src/log.c            |    2 +-
- src/loop.c           |    2 +-
- src/netlink.c        |    2 +-
- src/network.c        |    2 +-
- src/option.c         |    2 +-
- src/outpacket.c      |    2 +-
- src/poll.c           |    2 +-
- src/radv-protocol.h  |    2 +-
- src/radv.c           |    2 +-
- src/rfc1035.c        |    2 +-
- src/rfc2131.c        |    2 +-
- src/rfc3315.c        |    2 +-
- src/rrfilter.c       |    2 +-
- src/slaac.c          |    2 +-
- src/tftp.c           |    2 +-
- src/util.c           |    2 +-
- 42 files changed, 43 insertions(+), 43 deletions(-)
-
-diff --git a/Makefile b/Makefile
-index 41e368f..dd0513b 100644
---- a/Makefile
-+++ b/Makefile
-@@ -1,4 +1,4 @@
--# dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+# dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- #
- #  This program is free software; you can redistribute it and/or modify
- #  it under the terms of the GNU General Public License as published by
-diff --git a/src/arp.c b/src/arp.c
-index d17eedb..73a0250 100644
---- a/src/arp.c
-+++ b/src/arp.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/auth.c b/src/auth.c
-index 85bd5e7..1821c8f 100644
---- a/src/auth.c
-+++ b/src/auth.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/blockdata.c b/src/blockdata.c
-index c8f5eae..a8fdd59 100644
---- a/src/blockdata.c
-+++ b/src/blockdata.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/bpf.c b/src/bpf.c
-index a066641..7c4bead 100644
---- a/src/bpf.c
-+++ b/src/bpf.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/cache.c b/src/cache.c
-index 4da380a..d4b71a5 100644
---- a/src/cache.c
-+++ b/src/cache.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/config.h b/src/config.h
-index 309be6b..c3bbbcb 100644
---- a/src/config.h
-+++ b/src/config.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/conntrack.c b/src/conntrack.c
-index 0fa2da9..9ac2c14 100644
---- a/src/conntrack.c
-+++ b/src/conntrack.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dbus.c b/src/dbus.c
-index 3555f49..7e0d342 100644
---- a/src/dbus.c
-+++ b/src/dbus.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dhcp-common.c b/src/dhcp-common.c
-index 8fc171a..08528e8 100644
---- a/src/dhcp-common.c
-+++ b/src/dhcp-common.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dhcp-protocol.h b/src/dhcp-protocol.h
-index 701b6cb..a31d829 100644
---- a/src/dhcp-protocol.h
-+++ b/src/dhcp-protocol.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dhcp.c b/src/dhcp.c
-index 1c85e42..c11675d 100644
---- a/src/dhcp.c
-+++ b/src/dhcp.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dhcp6-protocol.h b/src/dhcp6-protocol.h
-index 928a2fa..4ca5d20 100644
---- a/src/dhcp6-protocol.h
-+++ b/src/dhcp6-protocol.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dhcp6.c b/src/dhcp6.c
-index 0e2e171..7269fd2 100644
---- a/src/dhcp6.c
-+++ b/src/dhcp6.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dns-protocol.h b/src/dns-protocol.h
-index addfa9e..95c55f2 100644
---- a/src/dns-protocol.h
-+++ b/src/dns-protocol.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 5cbfdbd..41d4f4e 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index fec0f8d..b2d1c5e 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
-  
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-@@ -14,7 +14,7 @@
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
- 
--#define COPYRIGHT "Copyright (c) 2000-2015 Simon Kelley" 
-+#define COPYRIGHT "Copyright (c) 2000-2016 Simon Kelley"
- 
- #ifndef NO_LARGEFILE
- /* Ensure we can use files >2GB (log files may grow this big) */
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 5a1190d..a432ebf 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1,5 +1,5 @@
- /* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky(a)develer.com>
--           and Copyright (c) 2012-2015 Simon Kelley
-+           and Copyright (c) 2012-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/domain.c b/src/domain.c
-index 278698c..1dd5027 100644
---- a/src/domain.c
-+++ b/src/domain.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/edns0.c b/src/edns0.c
-index 12e0210..7e8fe64 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/forward.c b/src/forward.c
-index 911f46e..47c6ded 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/helper.c b/src/helper.c
-index 517cfd9..6ee21bd 100644
---- a/src/helper.c
-+++ b/src/helper.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/inotify.c b/src/inotify.c
-index ef05c58..c0a6fdb 100644
---- a/src/inotify.c
-+++ b/src/inotify.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
-  
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/ip6addr.h b/src/ip6addr.h
-index f0b7e82..67deea5 100644
---- a/src/ip6addr.h
-+++ b/src/ip6addr.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/lease.c b/src/lease.c
-index 8adb605..a4c06c8 100644
---- a/src/lease.c
-+++ b/src/lease.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/log.c b/src/log.c
-index 27b2e59..8e66629 100644
---- a/src/log.c
-+++ b/src/log.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/loop.c b/src/loop.c
-index c9ed075..2ed691f 100644
---- a/src/loop.c
-+++ b/src/loop.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/netlink.c b/src/netlink.c
-index 3376d68..049247b 100644
---- a/src/netlink.c
-+++ b/src/netlink.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/network.c b/src/network.c
-index 819302f..66b91ad 100644
---- a/src/network.c
-+++ b/src/network.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/option.c b/src/option.c
-index f359bc5..0e126f2 100644
---- a/src/option.c
-+++ b/src/option.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/outpacket.c b/src/outpacket.c
-index 5b1ff93..a414efa 100644
---- a/src/outpacket.c
-+++ b/src/outpacket.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/poll.c b/src/poll.c
-index d71b1b9..9a20c3e 100644
---- a/src/poll.c
-+++ b/src/poll.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/radv-protocol.h b/src/radv-protocol.h
-index 4cc1ea4..2ea7d49 100644
---- a/src/radv-protocol.h
-+++ b/src/radv-protocol.h
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/radv.c b/src/radv.c
-index 39f1e92..5c5382f 100644
---- a/src/radv.c
-+++ b/src/radv.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 5d89287..55dec48 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/rfc2131.c b/src/rfc2131.c
-index 9f69ed5..e21efb5 100644
---- a/src/rfc2131.c
-+++ b/src/rfc2131.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/rfc3315.c b/src/rfc3315.c
-index 31bb41b..3f4d69c 100644
---- a/src/rfc3315.c
-+++ b/src/rfc3315.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/rrfilter.c b/src/rrfilter.c
-index b26b39f..38afbee 100644
---- a/src/rrfilter.c
-+++ b/src/rrfilter.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/slaac.c b/src/slaac.c
-index abaad53..8034805 100644
---- a/src/slaac.c
-+++ b/src/slaac.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/tftp.c b/src/tftp.c
-index 350a587..00ed2fc 100644
---- a/src/tftp.c
-+++ b/src/tftp.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-diff --git a/src/util.c b/src/util.c
-index 469eaed..93b24f5 100644
---- a/src/util.c
-+++ b/src/util.c
-@@ -1,4 +1,4 @@
--/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
-+/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
- 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compilation_time.patch b/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compilation_time.patch
deleted file mode 100644
index 6a9bf43..0000000
--- a/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compilation_time.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From b633de94131361b28f47aa59d91e3eef49575942 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Wed, 6 Jan 2016 22:51:17 +0000
-Subject: [PATCH] Fix FTBFS when scripts excluded at compilation time.
-
----
- src/dnsmasq.c |    2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 41d4f4e..8032fc7 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -937,7 +937,7 @@ int main (int argc, char **argv)
-       while (do_script_run(now));
- #    endif
- 
--      while (do_arp_script_run(now));
-+      while (do_arp_script_run());
- 
- #    ifdef HAVE_TFTP 
-       while (do_tftp_script_run());
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch b/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch
deleted file mode 100644
index 11cf20a..0000000
--- a/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 5757371d43891e830abe19aacae5378a79c7851c Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 11 Jan 2016 22:50:00 +0000
-Subject: [PATCH] Inhibit DNSSEC validation when forwarding to private servers
- for a domain.
-
-server=/example.com/<ip-of-server>
-
-The rationale is that the chain-of-trust will not be complete to
-private servers. If it was, it would not be necessary to access the
-server direct.
----
- src/forward.c |    5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/src/forward.c b/src/forward.c
-index 47c6ded..1458578 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -406,7 +406,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 	}
-       
- #ifdef HAVE_DNSSEC
--      if (option_bool(OPT_DNSSEC_VALID))
-+      if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN))
- 	{
- 	  size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
- 	 
-@@ -858,7 +858,8 @@ void reply_query(int fd, int family, time_t now)
- 	no_cache_dnssec = 1;
-       
- #ifdef HAVE_DNSSEC
--      if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
-+      if (server && !(server->flags & SERV_HAS_DOMAIN) && 
-+	  option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
- 	{
- 	  int status = 0;
- 
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch b/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch
deleted file mode 100644
index b58b6d2..0000000
--- a/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From a63b8b89e66a097fca7cba3efc7923636574ec2c Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Tue, 12 Jan 2016 11:28:58 +0000
-Subject: [PATCH] DNSSEC: Handle non-root trust anchors, and check we have a
- root trust anchor.
-
----
- src/dnsmasq.c |   12 ++++++++++--
- src/dnssec.c  |   19 ++++++++++++++++++-
- 2 files changed, 28 insertions(+), 3 deletions(-)
-
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index 8032fc7..e993629 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -169,8 +169,16 @@ int main (int argc, char **argv)
-   if (option_bool(OPT_DNSSEC_VALID))
-     {
- #ifdef HAVE_DNSSEC
--      if (!daemon->ds)
--	die(_("no trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
-+      struct ds_config *ds;
-+
-+      /* Must have at least a root trust anchor, or the DNSSEC code
-+	 can loop forever. */
-+      for (ds = daemon->ds; ds; ds = ds->next)
-+	if (ds->name[0] == 0)
-+	  break;
-+
-+      if (!ds)
-+	die(_("no root trust anchor provided for DNSSEC"), NULL, EC_BADCONF);
-       
-       if (daemon->cachesize < CACHESIZ)
- 	die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
-diff --git a/src/dnssec.c b/src/dnssec.c
-index a432ebf..18efa59 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1873,10 +1873,27 @@ 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)
- {
--  int name_start = strlen(name);
-+  int name_start = strlen(name); /* for when TA is root */
-   struct crec *crecp;
-   char *p;
-+
-+  /* First, work towards the root, looking for a trust anchor.
-+     This can either be one configured, or one previously cached.
-+     We can assume, if we don't find one first, that there is
-+     a trust anchor at the root. */
-+  for (p = name; p; p = strchr(p, '.'))
-+    {
-+      if (*p == '.')
-+	p++;
-+
-+      if (cache_find_by_name(NULL, p, now, F_DS))
-+	{
-+	  name_start = p - name;
-+	  break;
-+	}
-+    }
-   
-+  /* Now work away from the trust anchor */
-   while (1)
-     {
-       strcpy(keyname, &name[name_start]);
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch b/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch
deleted file mode 100644
index 71db7e7..0000000
--- a/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From eddf3652845b30236a99187db19d13bc6d1f282d Mon Sep 17 00:00:00 2001
-From: =?utf8?q?Andr=C3=A9=20Gl=C3=BCpker?= <andre.gluepker(a)st.ovgu.de>
-Date: Tue, 12 Jan 2016 12:54:17 +0000
-Subject: [PATCH] Fix bad cache-size calculation when hosts-file read fails.
-
----
- CHANGELOG   |    4 ++++
- src/cache.c |    2 +-
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index 93c73d0..dcaa699 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -18,6 +18,10 @@ version 2.76
- 	    that the same name is empty. Thanks to Edwin Török for
- 	    the patch.
- 
-+	    Fix failure to correctly calculate cache-size when 
-+	    reading a hosts-file fails. Thanks to André Glüpker 
-+	    for the patch.
-+
- 	
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-diff --git a/src/cache.c b/src/cache.c
-index d4b71a5..a9eaa65 100644
---- a/src/cache.c
-+++ b/src/cache.c
-@@ -919,7 +919,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
-   if (!f)
-     {
-       my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
--      return 0;
-+      return cache_size;
-     }
-   
-   eatspace(f);
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch b/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch
deleted file mode 100644
index 62d4f8d..0000000
--- a/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch
+++ /dev/null
@@ -1,217 +0,0 @@
-From 367341f7456c33c66142d66b0e76c56d53bca4f2 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Tue, 12 Jan 2016 15:58:23 +0000
-Subject: [PATCH] Disable DNSSEC for server=/domain/.. servers unless
- trust-anchor provided.
-
----
- src/dnsmasq.h |    1 +
- src/dnssec.c  |    2 +-
- src/forward.c |   30 ++++++++++++++++++++++--------
- src/network.c |   38 ++++++++++++++++++++++++++++++++++----
- 4 files changed, 58 insertions(+), 13 deletions(-)
-
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index b2d1c5e..543481c 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -477,6 +477,7 @@ union mysockaddr {
- #define SERV_NO_REBIND      2048  /* inhibit dns-rebind protection */
- #define SERV_FROM_FILE      4096  /* read from --servers-file */
- #define SERV_LOOP           8192  /* server causes forwarding loop */
-+#define SERV_DO_DNSSEC     16384  /* Validate DNSSEC when using this server */
- 
- struct serverfd {
-   int fd;
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 18efa59..ebb9c93 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -1892,7 +1892,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
- 	  break;
- 	}
-     }
--  
-+
-   /* Now work away from the trust anchor */
-   while (1)
-     {
-diff --git a/src/forward.c b/src/forward.c
-index 1458578..11c0d45 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -106,8 +106,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
-   return 1;
- }
-           
--static unsigned int search_servers(time_t now, struct all_addr **addrpp, 
--				     unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind)
-+static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype,
-+				   char *qdomain, int *type, char **domain, int *norebind)
- 			      
- {
-   /* If the query ends in the domain in one of our servers, set
-@@ -175,7 +175,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
- 		
- 		if (domainlen >= matchlen)
- 		  {
--		    *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
-+		    *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
- 		    *domain = serv->domain;
- 		    matchlen = domainlen;
- 		    if (serv->flags & SERV_NO_ADDR)
-@@ -233,12 +233,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 			 struct frec *forward, int ad_reqd, int do_bit)
- {
-   char *domain = NULL;
--  int type = 0, norebind = 0;
-+  int type = SERV_DO_DNSSEC, norebind = 0;
-   struct all_addr *addrp = NULL;
-   unsigned int flags = 0;
-   struct server *start = NULL;
- #ifdef HAVE_DNSSEC
-   void *hash = hash_questions(header, plen, daemon->namebuff);
-+  int do_dnssec = 0;
- #else
-   unsigned int crc = questions_crc(header, plen, daemon->namebuff);
-   void *hash = &crc;
-@@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 	  daemon->last_server = NULL;
- 	}
-       type = forward->sentto->flags & SERV_TYPE;
-+#ifdef HAVE_DNSSEC
-+      do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
-+#endif
-+
-       if (!(start = forward->sentto->next))
- 	start = daemon->servers; /* at end of list, recycle */
-       header->id = htons(forward->new_id);
-@@ -324,6 +329,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-       if (gotname)
- 	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
-       
-+#ifdef HAVE_DNSSEC
-+      do_dnssec = type & SERV_DO_DNSSEC;
-+      type &= ~SERV_DO_DNSSEC;
-+#endif      
-+
-       if (!flags && !(forward = get_new_frec(now, NULL, 0)))
- 	/* table full - server failure. */
- 	flags = F_NEG;
-@@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- 	}
-       
- #ifdef HAVE_DNSSEC
--      if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN))
-+      if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
- 	{
- 	  size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
- 	 
-@@ -858,7 +868,7 @@ void reply_query(int fd, int family, time_t now)
- 	no_cache_dnssec = 1;
-       
- #ifdef HAVE_DNSSEC
--      if (server && !(server->flags & SERV_HAS_DOMAIN) && 
-+      if (server && (server->flags & SERV_DO_DNSSEC) && 
- 	  option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
- 	{
- 	  int status = 0;
-@@ -1640,6 +1650,10 @@ unsigned char *tcp_request(int confd, time_t now,
- 	      if (gotname)
- 		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
- 	      
-+#ifdef HAVE_DNSSEC
-+	      type &= ~SERV_DO_DNSSEC;
-+#endif
-+	      
- 	      if (type != 0  || option_bool(OPT_ORDER) || !daemon->last_server)
- 		last_server = daemon->servers;
- 	      else
-@@ -1711,7 +1725,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 			    }
- 			  
- #ifdef HAVE_DNSSEC
--			  if (option_bool(OPT_DNSSEC_VALID))
-+			  if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
- 			    {
- 			      new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
- 			      
-@@ -1757,7 +1771,7 @@ unsigned char *tcp_request(int confd, time_t now,
- #endif 
- 
- #ifdef HAVE_DNSSEC
--		      if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled)
-+		      if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
- 			{
- 			  int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
- 			  int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
-diff --git a/src/network.c b/src/network.c
-index 66b91ad..303ae50 100644
---- a/src/network.c
-+++ b/src/network.c
-@@ -1430,12 +1430,38 @@ void check_servers(void)
-   if (!option_bool(OPT_NOWILD))
-     enumerate_interfaces(0);
-   
-+#ifdef HAVE_DNSSEC
-+ /* Disable DNSSEC validation when using server=/domain/.... servers
-+    unless there's a configured trust anchor. */
-+  for (serv = daemon->servers; serv; serv = serv->next)
-+    serv->flags |= SERV_DO_DNSSEC;
-+#endif
-+
-   for (serv = daemon->servers; serv; serv = serv->next)
-     {
--       if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
-+      if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
- 	{
--	  port = prettyprint_addr(&serv->addr, daemon->namebuff);
-+#ifdef HAVE_DNSSEC
-+	  if (option_bool(OPT_DNSSEC_VALID) && (serv->flags & SERV_HAS_DOMAIN))
-+	    {
-+	      struct ds_config *ds;
-+	      char *domain = serv->domain;
-+
-+	      /* .example.com is valid */
-+	      while (*domain == '.')
-+		domain++;
-+	      
-+	      for (ds = daemon->ds; ds; ds = ds->next)
-+		if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
-+		  break;
- 
-+	      if (!ds)
-+		serv->flags &= ~SERV_DO_DNSSEC;
-+	    }
-+#endif
-+
-+	  port = prettyprint_addr(&serv->addr, daemon->namebuff);
-+	  
- 	  /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
- 	  if (serv->addr.sa.sa_family == AF_INET &&
- 	      serv->addr.in.sin_addr.s_addr == 0)
-@@ -1471,7 +1497,11 @@ void check_servers(void)
- 	{
- 	  if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
- 	    {
--	      char *s1, *s2;
-+	      char *s1, *s2, *s3 = "";
-+#ifdef HAVE_DNSSEC
-+	      if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
-+		s3 = _("(no DNSSEC)");
-+#endif
- 	      if (!(serv->flags & SERV_HAS_DOMAIN))
- 		s1 = _("unqualified"), s2 = _("names");
- 	      else if (strlen(serv->domain) == 0)
-@@ -1484,7 +1514,7 @@ void check_servers(void)
- 	      else if (serv->flags & SERV_USE_RESOLV)
- 		my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
- 	      else 
--		my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
-+		my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
- 	    }
- #ifdef HAVE_LOOP
- 	  else if (serv->flags & SERV_LOOP)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/049-arp_c_tidy_up.patch b/src/patches/dnsmasq/049-arp_c_tidy_up.patch
deleted file mode 100644
index 2847eec..0000000
--- a/src/patches/dnsmasq/049-arp_c_tidy_up.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From bb58f63ce598763231fbf320bace1dbd777afd37 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Thu, 14 Jan 2016 19:23:10 +0000
-Subject: [PATCH] arp.c tidy up.
-
----
- src/arp.c |    4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/arp.c b/src/arp.c
-index 73a0250..968455c 100644
---- a/src/arp.c
-+++ b/src/arp.c
-@@ -132,7 +132,7 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
- 	  }
- #endif
- 	
--	/* Only accept poitive entries unless in lazy mode. */
-+	/* Only accept positive entries unless in lazy mode. */
- 	if (arp->status != ARP_EMPTY || lazy || updated)
- 	  {
- 	    if (mac && arp->hwlen != 0)
-@@ -148,7 +148,7 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
-        last = now;
- 
-        /* Mark all non-negative entries */
--       for (arp = arps, up = &arps; arp; arp = arp->next)
-+       for (arp = arps; arp; arp = arp->next)
- 	 if (arp->status != ARP_EMPTY)
- 	   arp->status = ARP_MARK;
-        
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/050-Complete_work_to_allow_DNSSEC_validation_with_private_DNS_servers.patch b/src/patches/dnsmasq/050-Complete_work_to_allow_DNSSEC_validation_with_private_DNS_servers.patch
deleted file mode 100644
index b969eee..0000000
--- a/src/patches/dnsmasq/050-Complete_work_to_allow_DNSSEC_validation_with_private_DNS_servers.patch
+++ /dev/null
@@ -1,139 +0,0 @@
-From 92be34a4077672f592d47e2991b3530305517a28 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Sat, 16 Jan 2016 18:39:54 +0000
-Subject: [PATCH] Complete work to allow DNSSEC validation with private DNS
- servers.
-
----
- man/dnsmasq.8 |    5 ++++-
- src/forward.c |   34 +++++++++++++++++++++++++++++++---
- src/network.c |   33 +++++++++++++++++++--------------
- 3 files changed, 54 insertions(+), 18 deletions(-)
-
-diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
-index d51b10f..69acdae 100644
---- a/man/dnsmasq.8
-+++ b/man/dnsmasq.8
-@@ -405,7 +405,10 @@ xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving  the flag
- .B -S /internal.thekelleys.org.uk/192.168.1.1 
- will send all queries for
- internal machines to that nameserver, everything else will go to the
--servers in /etc/resolv.conf. An empty domain specification,
-+servers in /etc/resolv.conf. DNSSEC validation is turned off for such
-+private nameservers, UNLESS a
-+.B --trust-anchor
-+is specified for the domain in question. An empty domain specification,
- .B // 
- has the special meaning of "unqualified names only" ie names without any
- dots in them. A non-standard port may be specified as 
-diff --git a/src/forward.c b/src/forward.c
-index 11c0d45..c48fd75 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -151,7 +151,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
- 	    hostname_isequal(matchstart, serv->domain) &&
- 	    (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
- 	  {
--	    if (serv->flags & SERV_NO_REBIND)	
-+	    if ((serv->flags & SERV_NO_REBIND) && norebind)	
- 	      *norebind = 1;
- 	    else
- 	      {
-@@ -644,7 +644,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
-     return resize_packet(header, n, pheader, plen);
-   
-   /* Complain loudly if the upstream server is non-recursive. */
--  if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
-+  if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR &&
-       server && !(server->flags & SERV_WARNED_RECURSIVE))
-     {
-       prettyprint_addr(&server->addr, daemon->namebuff);
-@@ -923,12 +923,40 @@ void reply_query(int fd, int family, time_t now)
- 		    status = STAT_ABANDONED;
- 		  else
- 		    {
--		      int fd;
-+		      int fd, type;
- 		      struct frec *next = new->next;
-+		      char *domain;
-+		      
- 		      *new = *forward; /* copy everything, then overwrite */
- 		      new->next = next;
- 		      new->blocking_query = NULL;
-+
-+		      /* Find server to forward to. This will normally be the 
-+			 same as for the original query, but may be another if
-+			 servers for domains are involved. */		      
-+		      if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0)
-+			{
-+			   struct server *start = server;
-+			   type &= ~SERV_DO_DNSSEC;
-+			   
-+			   while (1)
-+			     {
-+			       if (type == (start->flags & SERV_TYPE) &&
-+				   (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
-+				   !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
-+				 {
-+				   server = start;
-+				   break;
-+				 }
-+			       
-+			       if (!(start = start->next))
-+				 start = daemon->servers;
-+			       if (start == server)
-+				 break;
-+			     }
-+			}
- 		      new->sentto = server;
-+
- 		      new->rfd4 = NULL;
- #ifdef HAVE_IPV6
- 		      new->rfd6 = NULL;
-diff --git a/src/network.c b/src/network.c
-index 303ae50..5451c6c 100644
---- a/src/network.c
-+++ b/src/network.c
-@@ -1442,20 +1442,25 @@ void check_servers(void)
-       if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
- 	{
- #ifdef HAVE_DNSSEC
--	  if (option_bool(OPT_DNSSEC_VALID) && (serv->flags & SERV_HAS_DOMAIN))
--	    {
--	      struct ds_config *ds;
--	      char *domain = serv->domain;
--
--	      /* .example.com is valid */
--	      while (*domain == '.')
--		domain++;
--	      
--	      for (ds = daemon->ds; ds; ds = ds->next)
--		if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
--		  break;
--
--	      if (!ds)
-+	  if (option_bool(OPT_DNSSEC_VALID))
-+	    { 
-+	      if (serv->flags & SERV_HAS_DOMAIN)
-+		{
-+		  struct ds_config *ds;
-+		  char *domain = serv->domain;
-+		  
-+		  /* .example.com is valid */
-+		  while (*domain == '.')
-+		    domain++;
-+		  
-+		  for (ds = daemon->ds; ds; ds = ds->next)
-+		    if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
-+		      break;
-+		  
-+		  if (!ds)
-+		    serv->flags &= ~SERV_DO_DNSSEC;
-+		}
-+	      else if (serv->flags & SERV_FOR_NODOTS) 
- 		serv->flags &= ~SERV_DO_DNSSEC;
- 	    }
- #endif
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch b/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch
deleted file mode 100644
index aff7f37..0000000
--- a/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 1801a29226c53e8af3f7a0f149d3ec9f06c04f3c Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Sun, 17 Jan 2016 21:53:57 +0000
-Subject: [PATCH] Fix botch in forward.c flags code.
-
-Thanks to Matthias Anfree for spotting this.
----
- src/forward.c |    4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/forward.c b/src/forward.c
-index c48fd75..95c5ef9 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -810,9 +810,9 @@ void reply_query(int fd, int family, time_t now)
- 	    {
- 	      header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
- 	      header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
--	      if (forward->flags |= FREC_CHECKING_DISABLED)
-+	      if (forward->flags & FREC_CHECKING_DISABLED)
- 		header->hb4 |= HB4_CD;
--	      if (forward->flags |= FREC_AD_QUESTION)
-+	      if (forward->flags & FREC_AD_QUESTION)
- 		header->hb4 |= HB4_AD;
- 	      if (forward->flags & FREC_DO_QUESTION)
- 		add_do_bit(header, nn,  (unsigned char *)pheader + plen);
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch b/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch
deleted file mode 100644
index 54efae9..0000000
--- a/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From f4d0c660ca403e933d51093167c0d01526c7f9d1 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 18 Jan 2016 12:51:08 +0000
-Subject: [PATCH] Fix sporadic crash in find_mac() - hwlen must be zero for
- empty entries.
-
----
- src/arp.c |    3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/arp.c b/src/arp.c
-index 968455c..d70d2af 100644
---- a/src/arp.c
-+++ b/src/arp.c
-@@ -188,7 +188,8 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
-       arps = arp;
-       arp->status = ARP_EMPTY;
-       arp->family = addr->sa.sa_family;
--      
-+      arp->hwlen = 0;
-+
-       if (addr->sa.sa_family == AF_INET)
- 	arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
- #ifdef HAVE_IPV6
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch b/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch
deleted file mode 100644
index 3f8b053..0000000
--- a/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch
+++ /dev/null
@@ -1,270 +0,0 @@
-From f344dbc62216570b6471c81e4e39fc99bf47af5f Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Mon, 18 Jan 2016 18:04:17 +0000
-Subject: [PATCH] Complete DNSSEC server-selection code and set conntrack on
- DNSSEC queries.
-
----
- src/forward.c |  148 ++++++++++++++++++++++++++++++++++++++++++++++-----------
- 1 file changed, 121 insertions(+), 27 deletions(-)
-
-diff --git a/src/forward.c b/src/forward.c
-index 95c5ef9..506d194 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -923,7 +923,7 @@ void reply_query(int fd, int family, time_t now)
- 		    status = STAT_ABANDONED;
- 		  else
- 		    {
--		      int fd, type;
-+		      int fd, type = SERV_DO_DNSSEC;
- 		      struct frec *next = new->next;
- 		      char *domain;
- 		      
-@@ -936,7 +936,7 @@ void reply_query(int fd, int family, time_t now)
- 			 servers for domains are involved. */		      
- 		      if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0)
- 			{
--			   struct server *start = server;
-+			  struct server *start = server, *new_server = NULL;
- 			   type &= ~SERV_DO_DNSSEC;
- 			   
- 			   while (1)
-@@ -945,8 +945,12 @@ void reply_query(int fd, int family, time_t now)
- 				   (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
- 				   !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
- 				 {
--				   server = start;
--				   break;
-+				   new_server = start;
-+				   if (server == start)
-+				     {
-+				       new_server = NULL;
-+				       break;
-+				     }
- 				 }
- 			       
- 			       if (!(start = start->next))
-@@ -954,7 +958,11 @@ void reply_query(int fd, int family, time_t now)
- 			       if (start == server)
- 				 break;
- 			     }
-+			
-+			   if (new_server)
-+			     server = new_server;
- 			}
-+
- 		      new->sentto = server;
- 
- 		      new->rfd4 = NULL;
-@@ -1010,6 +1018,15 @@ void reply_query(int fd, int family, time_t now)
- 		      
- 		      if (fd != -1)
- 			{
-+#ifdef HAVE_CONNTRACK
-+			  /* Copy connection mark of incoming query to outgoing connection. */
-+			  if (option_bool(OPT_CONNTRACK))
-+			    {
-+			      unsigned int mark;
-+			      if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
-+				setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
-+			    }
-+#endif
- 			  while (retry_send(sendto(fd, (char *)header, nn, 0, 
- 						   &server->addr.sa, 
- 						   sa_len(&server->addr)))); 
-@@ -1072,7 +1089,7 @@ void reply_query(int fd, int family, time_t now)
-       else
- 	header->hb4 &= ~HB4_CD;
-       
--      if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, 
-+      if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, 
- 			      forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, 
- 			      forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
- 	{
-@@ -1433,20 +1450,27 @@ void receive_query(struct listener *listen, time_t now)
- }
- 
- #ifdef HAVE_DNSSEC
-+/* Recurse up the key heirarchy */
- static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, 
--			   int class, char *name, char *keyname, struct server *server, int *keycount)
-+			   int class, char *name, char *keyname, struct server *server, 
-+			   int have_mark, unsigned int mark, int *keycount)
- {
--  /* Recurse up the key heirarchy */
-   int new_status;
-   unsigned char *packet = NULL;
--  size_t m; 
-   unsigned char *payload = NULL;
-   struct dns_header *new_header = NULL;
-   u16 *length = NULL;
--  unsigned char c1, c2;
-+
-+  (void)have_mark;
-+  (void)mark;
- 
-   while (1)
-     {
-+      int type = SERV_DO_DNSSEC;
-+      char *domain;
-+      size_t m; 
-+      unsigned char c1, c2;
-+            
-       /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
-       if (--(*keycount) == 0)
- 	new_status = STAT_ABANDONED;
-@@ -1480,6 +1504,67 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
- 				new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
-       
-       *length = htons(m);
-+
-+      /* Find server to forward to. This will normally be the 
-+	 same as for the original query, but may be another if
-+	 servers for domains are involved. */		      
-+      if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) == 0)
-+	{
-+	  struct server *start = server, *new_server = NULL;
-+	  type &= ~SERV_DO_DNSSEC;
-+			   
-+	  while (1)
-+	    {
-+	      if (type == (start->flags & SERV_TYPE) &&
-+		  (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
-+		  !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
-+		{
-+		  new_server = start;
-+		  if (server == start)
-+		    {
-+		      new_server = NULL;
-+		      break;
-+		    }
-+		}
-+			       
-+	      if (!(start = start->next))
-+		start = daemon->servers;
-+	      if (start == server)
-+		break;
-+	    }
-+       
-+
-+	  if (new_server)
-+	    {
-+	      server = new_server;
-+	      /* may need to make new connection. */
-+	      if (server->tcpfd == -1)
-+		{
-+		  if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
-+		    {
-+		      new_status = STAT_ABANDONED;
-+		      break;
-+		    }
-+
-+#ifdef HAVE_CONNTRACK
-+		  /* Copy connection mark of incoming query to outgoing connection. */
-+		  if (have_mark)
-+		    setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
-+#endif	
-+			  
-+		  if (!local_bind(server->tcpfd,  &server->source_addr, server->interface, 1) ||
-+		      connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
-+		    {
-+		      close(server->tcpfd);
-+		      server->tcpfd = -1;
-+		      new_status = STAT_ABANDONED;
-+		      break;
-+		    }
-+
-+		}
-+	    }
-+	}
-+
-       
-       if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
- 	  !read_write(server->tcpfd, &c1, 1, 1) ||
-@@ -1492,7 +1577,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
- 
-       m = (c1 << 8) | c2;
-       
--      new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
-+      new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
-       
-       if (new_status != STAT_OK)
- 	break;
-@@ -1536,10 +1621,30 @@ unsigned char *tcp_request(int confd, time_t now,
-   socklen_t peer_len = sizeof(union mysockaddr);
-   int query_count = 0;
-   unsigned char *pheader;
-+#ifdef HAVE_CONNTRACK
-+  unsigned int mark = 0;
-+  int have_mark = 0;
-+#endif
- 
-   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
-     return packet;
--  
-+
-+#ifdef HAVE_CONNTRACK
-+  /* Get connection mark of incoming query to set on outgoing connections. */
-+  if (option_bool(OPT_CONNTRACK))
-+    {
-+      struct all_addr local;
-+#ifdef HAVE_IPV6		      
-+      if (local_addr->sa.sa_family == AF_INET6)
-+	local.addr.addr6 = local_addr->in6.sin6_addr;
-+      else
-+#endif
-+	local.addr.addr4 = local_addr->in.sin_addr;
-+      
-+      have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
-+    }
-+#endif	
-+
-   /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
-   if (option_bool(OPT_LOCAL_SERVICE))
-     {
-@@ -1665,7 +1770,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 	    {
- 	      unsigned int flags = 0;
- 	      struct all_addr *addrp = NULL;
--	      int type = 0;
-+	      int type = SERV_DO_DNSSEC;
- 	      char *domain = NULL;
- 	      size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
- 
-@@ -1728,20 +1833,8 @@ unsigned char *tcp_request(int confd, time_t now,
- 			  
- #ifdef HAVE_CONNTRACK
- 			  /* Copy connection mark of incoming query to outgoing connection. */
--			  if (option_bool(OPT_CONNTRACK))
--			    {
--			      unsigned int mark;
--			      struct all_addr local;
--#ifdef HAVE_IPV6		      
--			      if (local_addr->sa.sa_family == AF_INET6)
--				local.addr.addr6 = local_addr->in6.sin6_addr;
--			      else
--#endif
--				local.addr.addr4 = local_addr->in.sin_addr;
--			      
--			      if (get_incoming_mark(&peer_addr, &local, 1, &mark))
--				setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
--			    }
-+			  if (have_mark)
-+			    setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
- #endif	
- 		      
- 			  if ((!local_bind(last_server->tcpfd,  &last_server->source_addr, last_server->interface, 1) ||
-@@ -1802,7 +1895,8 @@ unsigned char *tcp_request(int confd, time_t now,
- 		      if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
- 			{
- 			  int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
--			  int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
-+			  int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, 
-+						       last_server, have_mark, mark, &keycount);
- 			  char *result, *domain = "result";
- 			  
- 			  if (status == STAT_ABANDONED)
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch b/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch
deleted file mode 100644
index f409038..0000000
--- a/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From f7443d76f7b4ff1c2eb05a0313619b0a4bb8787e Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Tue, 19 Jan 2016 20:29:57 +0000
-Subject: [PATCH] Fix problems in last commit when DNSSEC not enabled.
-
----
- src/forward.c |   11 ++---------
- 1 file changed, 2 insertions(+), 9 deletions(-)
-
-diff --git a/src/forward.c b/src/forward.c
-index 506d194..ff0ab7e 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -331,8 +331,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-       
- #ifdef HAVE_DNSSEC
-       do_dnssec = type & SERV_DO_DNSSEC;
--      type &= ~SERV_DO_DNSSEC;
--#endif      
-+#endif
-+      type &= ~SERV_DO_DNSSEC;      
- 
-       if (!flags && !(forward = get_new_frec(now, NULL, 0)))
- 	/* table full - server failure. */
-@@ -1461,9 +1461,6 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
-   struct dns_header *new_header = NULL;
-   u16 *length = NULL;
- 
--  (void)have_mark;
--  (void)mark;
--
-   while (1)
-     {
-       int type = SERV_DO_DNSSEC;
-@@ -1621,10 +1618,8 @@ unsigned char *tcp_request(int confd, time_t now,
-   socklen_t peer_len = sizeof(union mysockaddr);
-   int query_count = 0;
-   unsigned char *pheader;
--#ifdef HAVE_CONNTRACK
-   unsigned int mark = 0;
-   int have_mark = 0;
--#endif
- 
-   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
-     return packet;
-@@ -1783,9 +1778,7 @@ unsigned char *tcp_request(int confd, time_t now,
- 	      if (gotname)
- 		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
- 	      
--#ifdef HAVE_DNSSEC
- 	      type &= ~SERV_DO_DNSSEC;
--#endif
- 	      
- 	      if (type != 0  || option_bool(OPT_ORDER) || !daemon->last_server)
- 		last_server = daemon->servers;
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch b/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch
deleted file mode 100644
index 9eea14a..0000000
--- a/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From d05dd58de1113bb99060af2772247a45ceb3a1ad Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon(a)thekelleys.org.uk>
-Date: Tue, 19 Jan 2016 21:23:30 +0000
-Subject: [PATCH] Fix wrong reply to simple name when --domain-needed set and
- no servers configured.
-
-Also return REFUSED and not SERVFAIL when out of memory.
-
-Thanks to Allain Legacy for problem report.
----
- CHANGELOG     |    9 +++++++++
- src/forward.c |   13 +++++++------
- src/rfc1035.c |    4 +---
- 3 files changed, 17 insertions(+), 9 deletions(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index dcaa699..d3cf909 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -22,6 +22,15 @@ version 2.76
- 	    reading a hosts-file fails. Thanks to André Glüpker 
- 	    for the patch.
- 
-+	    Fix wrong answer to simple name query when --domain-needed
-+	    set, but no upstream servers configured. Dnsmasq returned
-+	    REFUSED, in this case, when it should be the same as when
-+	    upstream servers are configured - NOERROR. Thanks to 
-+	    Allain Legacy for spotting the problem.
-+
-+	    Return REFUSED when running out of forwarding table slots,
-+	    not SERVFAIL.
-+
- 	
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-diff --git a/src/forward.c b/src/forward.c
-index ff0ab7e..414f988 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -249,9 +249,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
-  (void)do_bit;
- 
-   /* may be no servers available. */
--  if (!daemon->servers)
--    forward = NULL;
--  else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
-+  if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
-     {
-       /* If we didn't get an answer advertising a maximal packet in EDNS,
- 	 fall back to 1280, which should work everywhere on IPv6.
-@@ -334,9 +332,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
- #endif
-       type &= ~SERV_DO_DNSSEC;      
- 
--      if (!flags && !(forward = get_new_frec(now, NULL, 0)))
--	/* table full - server failure. */
--	flags = F_NEG;
-+      if (daemon->servers && !flags)
-+	forward = get_new_frec(now, NULL, 0);
-+      /* table full - flags == 0, return REFUSED */
-       
-       if (forward)
- 	{
-@@ -1621,6 +1619,9 @@ unsigned char *tcp_request(int confd, time_t now,
-   unsigned int mark = 0;
-   int have_mark = 0;
- 
-+  (void)mark;
-+  (void)have_mark;
-+
-   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
-     return packet;
- 
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 55dec48..9c0ddb5 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -896,9 +896,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
-   header->nscount = htons(0);
-   header->arcount = htons(0);
-   header->ancount = htons(0); /* no answers unless changed below */
--  if (flags == F_NEG)
--    SET_RCODE(header, SERVFAIL); /* couldn't get memory */
--  else if (flags == F_NOERR)
-+  if (flags == F_NOERR)
-     SET_RCODE(header, NOERROR); /* empty domain */
-   else if (flags == F_NXDOMAIN)
-     SET_RCODE(header, NXDOMAIN);
--- 
-1.7.10.4
-
diff --git a/src/patches/dnsmasq/056-Add_--max-port_config_option.patch b/src/patches/dnsmasq/056-Add_--max-port_config_option.patch
deleted file mode 100644
index 7457be8..0000000
--- a/src/patches/dnsmasq/056-Add_--max-port_config_option.patch
+++ /dev/null
@@ -1,166 +0,0 @@
-From 926332a76454c7621f569d6c76d2697a83074d99 Mon Sep 17 00:00:00 2001
-From: Hans Dedecker <dedeckeh(a)gmail.com>
-Date: Sat, 23 Jan 2016 10:48:12 +0000
-Subject: [PATCH] Add --max-port config option.
-
----
- CHANGELOG          |    3 +++
- man/dnsmasq.8      |    7 +++++++
- src/dns-protocol.h |    1 +
- src/dnsmasq.c      |    8 +++++++-
- src/dnsmasq.h      |    2 +-
- src/network.c      |    6 +++---
- src/option.c       |    9 +++++++++
- 7 files changed, 31 insertions(+), 5 deletions(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index d3cf909..bc1e930 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -31,6 +31,9 @@ version 2.76
- 	    Return REFUSED when running out of forwarding table slots,
- 	    not SERVFAIL.
- 
-+            Add --max-port configuration. Thanks to Hans Dedecker for
-+	    the patch.
-+	
- 	
- version 2.75
-             Fix reversion on 2.74 which caused 100% CPU use when a 
-diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
-index 69acdae..103a813 100644
---- a/man/dnsmasq.8
-+++ b/man/dnsmasq.8
-@@ -174,6 +174,13 @@ queries. Dnsmasq picks random ports as source for outbound queries:
- when this option is given, the ports used will always to larger
- than that specified. Useful for systems behind firewalls. 
- .TP
-+.B --max-port=<port>
-+Use ports lower than that given as source for outbound DNS queries.
-+Dnsmasq picks random ports as source for outbound queries:
-+when this option is given, the ports used will always be lower
-+than that specified. Useful for systems behind firewalls.
-+.TP
-+
- .B \-i, --interface=<interface name>
- Listen only on the specified interface(s). Dnsmasq automatically adds
- the loopback (local) interface to the list of interfaces to use when
-diff --git a/src/dns-protocol.h b/src/dns-protocol.h
-index 95c55f2..75d8ffb 100644
---- a/src/dns-protocol.h
-+++ b/src/dns-protocol.h
-@@ -16,6 +16,7 @@
- 
- #define NAMESERVER_PORT 53
- #define TFTP_PORT       69
-+#define MAX_PORT        65535u
- 
- #define IN6ADDRSZ       16
- #define INADDRSZ        4
-diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index e993629..0bb3e03 100644
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -219,7 +219,13 @@ int main (int argc, char **argv)
-   if (option_bool(OPT_LOOP_DETECT))
-     die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
- #endif
--  
-+
-+  if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
-+    daemon->min_port = 1024u;
-+
-+  if (daemon->max_port < daemon->min_port)
-+    die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
-+
-   now = dnsmasq_time();
- 
-   /* Create a serial at startup if not configured. */
-diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index 543481c..fd483a6 100644
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -950,7 +950,7 @@ extern struct daemon {
-   char *log_file; /* optional log file */
-   int max_logs;  /* queue limit */
-   int cachesize, ftabsize;
--  int port, query_port, min_port;
-+  int port, query_port, min_port, max_port;
-   unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
-   char *dns_client_id;
-   struct hostsfile *addn_hosts;
-diff --git a/src/network.c b/src/network.c
-index 5451c6c..91ac40a 100644
---- a/src/network.c
-+++ b/src/network.c
-@@ -1119,7 +1119,7 @@ int random_sock(int family)
-   if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
-     {
-       union mysockaddr addr;
--      unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
-+      unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
-       int tries = ports_avail < 30 ? 3 * ports_avail : 100;
- 
-       memset(&addr, 0, sizeof(addr));
-@@ -1132,8 +1132,8 @@ int random_sock(int family)
- 	  {
- 	    unsigned short port = rand16();
- 	    
--	    if (daemon->min_port != 0)
--	      port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
-+            if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
-+              port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
- 	    
- 	    if (family == AF_INET) 
- 	      {
-diff --git a/src/option.c b/src/option.c
-index 0e126f2..f40e9e2 100644
---- a/src/option.c
-+++ b/src/option.c
-@@ -154,6 +154,7 @@ struct myoption {
- #define LOPT_HOST_INOTIFY  342
- #define LOPT_DNSSEC_STAMP  343
- #define LOPT_TFTP_NO_FAIL  344
-+#define LOPT_MAXPORT       345
- #define LOPT_DNS_CLIENT_ID 355
- 
- #ifdef HAVE_GETOPT_LONG
-@@ -271,6 +272,7 @@ static const struct myoption opts[] =
-     { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
-     { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
-     { "min-port", 1, 0, LOPT_MINPORT },
-+    { "max-port", 1, 0, LOPT_MAXPORT },
-     { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
-     { "cname", 1, 0, LOPT_CNAME },
-     { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
-@@ -438,6 +440,7 @@ static struct {
-   { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
-   { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
-   { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
-+  { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
-   { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
-   { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
-   { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
-@@ -2512,6 +2515,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
- 	ret_err(gen_err);
-       break;
- 
-+    case LOPT_MAXPORT:  /* --max-port */
-+      if (!atoi_check16(arg, &daemon->max_port))
-+	ret_err(gen_err);
-+      break;
-+
-     case '0':  /* --dns-forward-max */
-       if (!atoi_check(arg, &daemon->ftabsize))
- 	ret_err(gen_err);
-@@ -4462,6 +4470,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
-   daemon->soa_refresh = SOA_REFRESH;
-   daemon->soa_retry = SOA_RETRY;
-   daemon->soa_expiry = SOA_EXPIRY;
-+  daemon->max_port = MAX_PORT;
- 
-   add_txt("version.bind", "dnsmasq-" VERSION, 0 );
-   add_txt("authors.bind", "Simon Kelley", 0);
--- 
-1.7.10.4
-
-- 
2.7.0


                 reply	other threads:[~2016-02-04 19:16 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1454613368-17813-1-git-send-email-matthias.fischer@ipfire.org \
    --to=matthias.fischer@ipfire.org \
    --cc=development@lists.ipfire.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox