From mboxrd@z Thu Jan 1 00:00:00 1970 From: Matthias Fischer To: development@lists.ipfire.org Subject: [PATCH] dnsmasq 276test8: latest patches from upstream (001-002) Date: Thu, 04 Feb 2016 20:16:08 +0100 Message-ID: <1454613368-17813-1-git-send-email-matthias.fischer@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5376467388965487908==" List-Id: --===============5376467388965487908== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=3Ddnsmasq.git;a=3Dcommit;h=3D1e5051228d543= d0db4b32f24a2e6a97f2d061cf0 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 --- 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_c= hecks.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_arbit= ary_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-optio= n.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_repl= ies_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_i= notify_code.patch delete mode 100644 src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794= 513abe510817e2cf3ca.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_corr= ectly.patch delete mode 100644 src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-d= ir.patch delete mode 100644 src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_v= alidation.patch delete mode 100644 src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_return= ing_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_r= eplies.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_validat= e_ds.patch delete mode 100644 src/patches/dnsmasq/024-Do_a_better_job_of_determining_wh= ich_DNSSEC_sig_algos_are_supported.patch delete mode 100644 src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_a= nd_computation_use_of_udp.patch delete mode 100644 src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_D= NSSEC_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.pa= tch 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_so= urce_file.patch delete mode 100644 src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.pat= ch delete mode 100644 src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_b= ytes_that_the_client_isnt_expecting.patch delete mode 100644 src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_cod= e_omitted.patch delete mode 100644 src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_an= d_DS_also_digest_with_DS.patch delete mode 100644 src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.pat= ch delete mode 100644 src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_t= able.patch delete mode 100644 src/patches/dnsmasq/037-First_complete_version_of_DNS-cli= ent-id_EDNS0_and_ARP_tracking_code.patch delete mode 100644 src/patches/dnsmasq/038-Correct_logic_for_when_to_start_h= elper.patch delete mode 100644 src/patches/dnsmasq/039-Trivial_code_tweak.patch delete mode 100644 src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_bro= ke_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_suppo= rt_enabled_and_DHCP_disabled.patch delete mode 100644 src/patches/dnsmasq/043-Update_copyright_notices_Happy_ne= w_year.patch delete mode 100644 src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_a= t_compilation_time.patch delete mode 100644 src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_fo= rwarding_to_private_servers_for_a_domain.patch delete mode 100644 src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anch= ors_and_check_we_have_a_root-trust_anchor.patch delete mode 100644 src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_wh= en_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_val= idation_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.pa= tch 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_wh= en_--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 @@ =20 include Config =20 -VER =3D 2.75 +VER =3D 2.76test8 =20 THISAPP =3D dnsmasq-$(VER) DL_FILE =3D $(THISAPP).tar.xz @@ -43,7 +43,7 @@ objects =3D $(DL_FILE) =20 $(DL_FILE) =3D $(DL_FROM)/$(DL_FILE) =20 -$(DL_FILE)_MD5 =3D 887236f1ddde6eb57cdb9d01916c9f72 +$(DL_FILE)_MD5 =3D fecf1d0be1266e033872e5ed4cb7fc72 =20 install : $(TARGET) =20 @@ -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_a= dd_subnet_to_allow_arbitary_subnet_addresses.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/003-dont_answ= er_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_behav= iour_of_empty_dhcp-option.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/005-suggest_s= olution_to_ENOMEM_error_with_IPv6_multicast.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/006-clarify_m= an_page_on_RDNSS_set_in_router_advertisement.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/007-handle_si= gned_dangling_CNAME_replies_to_DS_queries.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/008-DHCPv6_op= tion_56_does_not_hold_an_address_list.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/009-Respect_t= he_--no_resolv_flag_in_inotify_code.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/010-Rationali= se_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/011-Catch_err= ors_from_sendmsg_in_DHCP_code.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/012-Update_li= st_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_un= known_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_rat= ionalisation_of_DNSSEC_validation.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/017-Abandon_c= aching_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-Generalis= e_RR-filtering_code_for_use_with_EDNS0.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/020-DNSSEC_va= lidation_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_D= NSSEC_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_bett= er_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/025-Major_tid= y_up_of_EDNS0_handling_and_computation_use_of_udp.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/026-More_twea= ks_in_handling_unknown_DNSSEC_algorithms.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/027-Nasty_rar= e_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/028-Minor_twe= ak_to_previous_commit.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/029-NSEC3_che= ck_RFC5155_para_8_2.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/030-Split_EDN= S0_stuff_into_its_own_source_file.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/031-Handle_ex= tending_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_signa= ture_algo_with_DNSKEY_and_DS_also_digest_with_DS.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/035-More_EDNS= 0_packet_size_tweaks.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/036-Cache_acc= ess_to_the_kernels_ARP_table.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/037-First_com= plete_version_of_DNS-client-id_EDNS0_and_ARP_tracking_code.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/038-Correct_l= ogic_for_when_to_start_helper.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/039-Trivial_c= ode_tweak.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/040-Fix_datat= ype-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_bu= ilding_with_script_support_enabled_and_DHCP_disabled.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/043-Update_co= pyright_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_D= NSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/046-DNSSEC_Ha= ndle_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_c= ache-size_calculation_when_hosts-file_read_fails.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/048-Disable_D= NSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch - cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/049-arp_c_tid= y_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_spora= dic_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_probl= ems_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_name= s_of_ARP_script_actions_consistent.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-t= o-read-ISC-DHCP-lease-file.patch =20 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 +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 +=20 + #include ++#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) + #include ++#endif + #include + #include + #include +--=20 +2.1.0 + diff --git a/src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.p= atch 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 -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=20 -+ translates to hosts on the local network, or, at=20 -+ least, 0.0.0.0 accesses the local host, so could -+ be targets for DNS rebinding. See RFC 5735 section 3=20 -+ for details. Thanks to Stephen R=C3=83=C2=B6ttger for the bug report. -+ =20 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 - 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 =3D ntohl(addr.s_addr); -=20 - return -- (((ip_addr & 0xFF000000) =3D=3D 0x7F000000) && ban_localhost) /* 127.0= .0.0/8 (loopback) */ ||=20 -+ (((ip_addr & 0xFF000000) =3D=3D 0x7F000000) && ban_localhost) /* 127.0= .0.0/8 (loopback) */ || -+ ((ip_addr & 0xFF000000) =3D=3D 0x00000000) /* RFC 5735 section 3. "her= e" network */ || - ((ip_addr & 0xFFFF0000) =3D=3D 0xC0A80000) /* 192.168.0.0/16 (private)= */ || - ((ip_addr & 0xFF000000) =3D=3D 0x0A000000) /* 10.0.0.0/8 (private)= */ || - ((ip_addr & 0xFFF00000) =3D=3D 0xAC100000) /* 172.16.0.0/12 (private)= */ || ---=20 -1.7.10.4 diff --git a/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consist= ent.patch b/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consiste= nt.patch new file mode 100644 index 0000000..d510fe5 --- /dev/null +++ b/src/patches/dnsmasq/002-Make_names_of_ARP_script_actions_consistent.pat= ch @@ -0,0 +1,88 @@ +From e6e751b066f8f45bb708a2e4fd69890496b943f0 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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. +=20 +=20 + 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 th= e future, so ++to the script, "init", "arp-add", "arp-del" and "tftp". More may be added i= n the future, so + scripts should be written to ignore unknown actions. "init" is + described below in=20 + .B --leasefile-ro +@@ -1560,10 +1560,10 @@ The "tftp" action is invoked when a TFTP file transf= er completes: the + arguments are the file size in bytes, the address to which the file + was sent, and the complete pathname of the file. + =20 +-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 indic= ates 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" ind= icates the deletion of same. +=20 + .TP + .B --dhcp-luascript=3D +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 =3D old; + old =3D 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 +=20 + #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 =3D=3D ACTION_ARP) + { +- action_str =3D "arp"; ++ action_str =3D "arp-add"; + is6 =3D (data.flags !=3D AF_INET); + } +- else if (data.action =3D=3D ACTION_ARP_OLD) ++ else if (data.action =3D=3D ACTION_ARP_DEL) + { +- action_str =3D "arp-old"; ++ action_str =3D "arp-del"; + is6 =3D (data.flags !=3D AF_INET); + data.action =3D ACTION_ARP; + } +--=20 +2.1.0 + diff --git a/src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_sub= net_addresses.patch b/src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arb= itary_subnet_addresses.patch deleted file mode 100644 index 2d3d6e4..0000000 --- a/src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_add= resses.patch +++ /dev/null @@ -1,271 +0,0 @@ -From a7369bef8abd241c3d85633fa9c870943f091e76 Mon Sep 17 00:00:00 2001 -From: Ed Bardsley -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=20 - for details. Thanks to Stephen R=C3=83=C2=B6ttger for the bug report. -+ -+ Enhance --add-subnet to allow arbitrary subnet addresses. -+ Thanks to Ed Barsley for the patch. -+=09 - =20 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 -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=20 --.B --add-subnet[[=3D],] --Add the subnet address of the requestor to the DNS queries which are --forwarded upstream. The amount of the address forwarded depends on the --prefix length parameter: 32 (128 for IPv6) forwards the whole address, --zero forwards none of it but still marks the request so that no --upstream nameserver will add client address information either. The --default is zero for both IPv4 and IPv6. Note that upstream nameservers --may be configured to return different results based on this --information, but the dnsmasq cache does not take account. If a dnsmasq --instance is configured such that different results may be encountered, --caching should be disabled. -+.B --add-subnet[[=3D[/]][,[= /]]] -+Add a subnet address to the DNS queries which are forwarded -+upstream. If an address is specified in the flag, it will be used, -+otherwise, the address of the requestor will be used. The amount of -+the address forwarded depends on the prefix length parameter: 32 (128 -+for IPv6) forwards the whole address, zero forwards none of it but -+still marks the request so that no upstream nameserver will add client -+address information either. The default is zero for both IPv4 and -+IPv6. Note that upstream nameservers may be configured to return -+different results based on this information, but the dnsmasq cache -+does not take account. If a dnsmasq instance is configured such that -+different results may be encountered, caching should be disabled. -+ -+For example, -+.B --add-subnet=3D24,96 -+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 request= ors, respectively. -+.B --add-subnet=3D1.2.3.4/24 -+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors. -+.B --add-subnet=3D1.2.3.4/24,1.2.3.4/24 -+will add 1.2.3.0/24 for both IPv4 and IPv6 requestors. -+ - .TP - .B \-c, --cache-size=3D - Set the size of dnsmasq's cache. The default is 150 names. Setting the cach= e 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; - }; -=20 -+/* 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;=20 -+ 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, "", 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 addr= ess to forwarded DNS queries."), NULL }, -- { LOPT_ADD_SBNET, ARG_ONE, "[,]", gettext_noop("Add req= uestor's IP subnet to forwarded DNS queries."), NULL }, -+ { LOPT_ADD_SBNET, ARG_ONE, "[,]", gettext_noop("Add spe= cified IP subnet to forwarded DNS queries."), NULL }, - { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validat= ion results from upstream nameservers."), NULL }, - { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocat= e sequential IP addresses to DHCP clients."), NULL }, - { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-trac= k mark from queries to upstream connections."), NULL }, -@@ -722,6 +722,20 @@ static void do_usage(void) -=20 - #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0) -=20 -+static char *parse_mysockaddr(char *arg, union mysockaddr *addr)=20 -+{ -+ if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) -+ addr->sa.sa_family =3D AF_INET; -+#ifdef HAVE_IPV6 -+ else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0) -+ addr->sa.sa_family =3D AF_INET6; -+#endif -+ else -+ return _("bad address"); -+ =20 -+ return NULL; -+} -+ - char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *sou= rce_addr, char *interface, int *flags) - { - int source_port =3D 0, serv_port =3D NAMESERVER_PORT; -@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char *errstr= , char *gen_err, int comma - li =3D match_suffix->next; - free(match_suffix->suffix); - free(match_suffix); -- } =20 -+ } - break; - } -=20 -@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, char *errs= tr, char *gen_err, int comma - set_option_bool(OPT_CLIENT_SUBNET); - if (arg) - { -+ char *err, *end; - comma =3D split(arg); -- if (!atoi_check(arg, &daemon->addr4_netmask) ||=20 -- (comma && !atoi_check(comma, &daemon->addr6_netmask))) -- ret_err(gen_err); -+ -+ struct mysubnet* new =3D opt_malloc(sizeof(struct mysubnet)); -+ if ((end =3D split_chr(arg, '/'))) -+ { -+ /* has subnet+len */ -+ err =3D parse_mysockaddr(arg, &new->addr); -+ if (err) -+ ret_err(err); -+ if (!atoi_check(end, &new->mask)) -+ ret_err(gen_err); -+ new->addr_used =3D 1; -+ }=20 -+ else if (!atoi_check(arg, &new->mask)) -+ ret_err(gen_err); -+ =20 -+ daemon->add_subnet4 =3D new; -+ -+ new =3D opt_malloc(sizeof(struct mysubnet)); -+ if (comma) -+ { -+ if ((end =3D split_chr(comma, '/'))) -+ { -+ /* has subnet+len */ -+ err =3D parse_mysockaddr(comma, &new->addr); -+ if (err) -+ ret_err(err); -+ if (!atoi_check(end, &new->mask)) -+ ret_err(gen_err); -+ new->addr_used =3D 1; -+ } -+ else -+ { -+ if (!atoi_check(comma, &new->mask)) -+ ret_err(gen_err); -+ } -+ } -+ daemon->add_subnet6 =3D new; - } - break; -=20 -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 - }; -=20 -+static void *get_addrp(union mysockaddr *addr, const short family)=20 -+{ -+#ifdef HAVE_IPV6 -+ if (family =3D=3D 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 *sou= rce) - { - /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ - =20 - int len; - void *addrp; -+ int sa_family =3D source->sa.sa_family; -=20 - #ifdef HAVE_IPV6 - if (source->sa.sa_family =3D=3D AF_INET6) - { -- opt->family =3D htons(2); -- opt->source_netmask =3D daemon->addr6_netmask; -- addrp =3D &source->in6.sin6_addr; -+ opt->source_netmask =3D daemon->add_subnet6->mask; -+ if (daemon->add_subnet6->addr_used)=20 -+ { -+ sa_family =3D daemon->add_subnet6->addr.sa.sa_family; -+ addrp =3D get_addrp(&daemon->add_subnet6->addr, sa_family); -+ }=20 -+ else=20 -+ addrp =3D &source->in6.sin6_addr; - } - else - #endif - { -- opt->family =3D htons(1); -- opt->source_netmask =3D daemon->addr4_netmask; -- addrp =3D &source->in.sin_addr; -+ opt->source_netmask =3D daemon->add_subnet4->mask; -+ if (daemon->add_subnet4->addr_used) -+ { -+ sa_family =3D daemon->add_subnet4->addr.sa.sa_family; -+ addrp =3D get_addrp(&daemon->add_subnet4->addr, sa_family); -+ }=20 -+ else=20 -+ addrp =3D &source->in.sin_addr; - } - =20 - opt->scope_netmask =3D 0; -@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, u= nion mysockaddr *source) - =20 - if (opt->source_netmask !=3D 0) - { -+#ifdef HAVE_IPV6 -+ opt->family =3D htons(sa_family =3D=3D AF_INET6 ? 2 : 1); -+#else -+ opt->family =3D htons(1); -+#endif - len =3D ((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, - =20 - return len; - } -- ---=20 -1.7.10.4 diff --git a/src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zo= nes_locally_when_localise_queries_set.patch b/src/patches/dnsmasq/003-dont_an= swer_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_loc= ally_when_localise_queries_set.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 3a3965ac21b1b759eab8799b6edb09195b671306 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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) -=20 - #ifdef HAVE_AUTH - /* find queries for zones we're authoritative for, and answer them di= rectly */ -- if (!auth_dns) -+ if (!auth_dns && !option_bool(OPT_LOCALISE)) - for (zone =3D daemon->auth_zones; zone; zone =3D zone->next) - if (in_zone(zone, daemon->namebuff, NULL)) - { -@@ -1904,7 +1904,7 @@ unsigned char *tcp_request(int confd, time_t now, - =20 - #ifdef HAVE_AUTH - /* find queries for zones we're authoritative for, and answer them direc= tly */ -- if (!auth_dns) -+ if (!auth_dns && !option_bool(OPT_LOCALISE)) - for (zone =3D daemon->auth_zones; zone; zone =3D zone->next) - if (in_zone(zone, daemon->namebuff, NULL)) - { ---=20 -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 -Date: Tue, 25 Aug 2015 23:08:39 +0100 -Subject: [PATCH] Fix behaviour of empty dhcp-option=3Doption6:dns-server, wh= ich - 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) - =20 - if (opt_cfg->opt =3D=3D OPTION6_REFRESH_TIME) - done_refresh =3D 1; -+ =20 -+ if (opt_cfg->opt =3D=3D OPTION6_DNS_SERVER) -+ done_dns =3D 1; - =20 -- if (opt_cfg->flags & DHOPT_ADDR6) -+ /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */ -+ if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt =3D=3D OPTION6_DNS= _SERVER) - { - int len, j; - struct in6_addr *a; - =20 -- if (opt_cfg->opt =3D=3D OPTION6_DNS_SERVER) -- done_dns =3D 1; -- =20 - for (a =3D (struct in6_addr *)opt_cfg->val, len =3D opt_cfg->len, j =3D = 0;=20 - j < opt_cfg->len; j +=3D IN6ADDRSZ, a++) - if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_add= r)) || ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IP= v6_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_mult= icast.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 9cdcfe9f19ffd45bac4e5b459879bf7c50a287ed Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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) - =20 - if ((daemon->doing_dhcp6 || daemon->relay6) && - setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(= mreq)) =3D=3D -1) -- err =3D 1; -+ err =3D errno; - =20 - inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr); - =20 - if (daemon->doing_dhcp6 &&=20 - setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(= mreq)) =3D=3D -1) -- err =3D 1; -+ err =3D errno; - =20 - inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr); - =20 - if (daemon->doing_ra && - setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(= mreq)) =3D=3D -1) -- err =3D 1; -+ err =3D errno; - =20 - if (err) - { - char *s =3D _("interface %s failed to join DHCPv6 multicast group: %s"); -+ errno =3D err; -+ -+#ifdef HAVE_LINUX_NETWORK -+ if (errno =3D=3D ENOMEM) -+ my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max")); -+#endif -+ - if (dienow) - die(s, iface->name, EC_BADNET); - else ---=20 -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_i= n_router_advertisement.patch deleted file mode 100644 index 19c76e6..0000000 --- a/src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_adverti= sement.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 20fd11e11a9d09edcea94de135396ae1541fbbab Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 D= HCP 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=20 --the machine running dnsmasq. By default, he "managed address" bits are set,= and -+router as the relevant link-local address on=20 -+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 lis= t (DNSSL). - .TP - .B --ra-param=3D,[high|low],[[],] - Set non-default values for router advertisements sent via an ---=20 -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_repli= es_to_DS_queries.patch deleted file mode 100644 index 832a22e..0000000 --- a/src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_quer= ies.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 6de81f1250fd323c9155de065d5a9dc200a6f20b Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 - =20 - /* If we return STAT_NO_SIG, name contains the name of the DS query */ - if (val =3D=3D STAT_NO_SIG) -- { -- *keyname =3D 0; -- return val; -- } =20 -- -+ return val; -+ =20 - /* 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. */ ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_addres= s_list.patch b/src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_addr= ess_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 -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[] =3D { - { "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 } ---=20 -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.pa= tch +++ /dev/null @@ -1,47 +0,0 @@ -From 77607cbea0ad0f876dfb79c8b2c121ee400d57d0 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 -=20 - 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=20 -+ was a dangling symbolic link, even of --no-resolv set. -+ Thanks to Alexander Kurtz for spotting the problem. -+ - =09 -- =20 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 - 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() - =20 - if (daemon->inotifyfd =3D=3D -1) - die(_("failed to create inotify: %s"), NULL, EC_MISC); -+ -+ if (option_bool(OPT_NO_RESOLV)) -+ return; - =20 - for (res =3D daemon->resolv_files; res; res =3D res->next) - { ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe5= 10817e2cf3ca.patch b/src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b379= 4513abe510817e2cf3ca.patch deleted file mode 100644 index 281697f..0000000 --- a/src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2= cf3ca.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 27b78d990b7cd901866ad6f1a17b9d633a95fdce Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 *st= ate, int do_refresh) - if (opt_cfg->opt =3D=3D OPTION6_DNS_SERVER) - done_dns =3D 1; - =20 -- /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */ -- if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt =3D=3D OPTION6_DNS= _SERVER) -+ if (opt_cfg->flags & DHOPT_ADDR6) - { - int len, j; - struct in6_addr *a; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.p= atch 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 -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 - =20 - while(retry_send(sendmsg(fd, &msg, 0))); -+ -+ /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */ -+ if (errno !=3D 0) -+ my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s= "), -+ inet_ntoa(dest.sin_addr), strerror(errno)); - } --=20 -+ - /* check against secondary interface addresses */ - static int check_listen_addrs(struct in_addr local, int if_index, char *lab= el, - struct in_addr netmask, struct in_addr broadcast, void *vparam) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.p= atch 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 -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 ---- - 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) =3D=3D 0x7F000000) && ban_localhost) /* 127.0= .0.0/8 (loopback) */ || - ((ip_addr & 0xFF000000) =3D=3D 0x00000000) /* RFC 5735 section 3. "her= e" network */ || -- ((ip_addr & 0xFFFF0000) =3D=3D 0xC0A80000) /* 192.168.0.0/16 (private)= */ || - ((ip_addr & 0xFF000000) =3D=3D 0x0A000000) /* 10.0.0.0/8 (private)= */ || - ((ip_addr & 0xFFF00000) =3D=3D 0xAC100000) /* 172.16.0.0/12 (private)= */ || -- ((ip_addr & 0xFFFF0000) =3D=3D 0xA9FE0000) /* 169.254.0.0/16 (zeroconf= ) */ ; -+ ((ip_addr & 0xFFFF0000) =3D=3D 0xC0A80000) /* 192.168.0.0/16 (private)= */ || -+ ((ip_addr & 0xFFFF0000) =3D=3D 0xA9FE0000) /* 169.254.0.0/16 (zeroconf= ) */ || -+ ((ip_addr & 0xFFFFFF00) =3D=3D 0xC0000200) /* 192.0.2.0/24 (test-net= ) */ || -+ ((ip_addr & 0xFFFFFF00) =3D=3D 0xC6336400) /* 198.51.100.0/24(test-net= ) */ || -+ ((ip_addr & 0xFFFFFF00) =3D=3D 0xCB007100) /* 203.0.113.0/24 (test-net= ) */ || -+ ((ip_addr & 0xFFFFFFFF) =3D=3D 0xFFFFFFFF) /* 255.255.255.255/32 (broa= dcast)*/ ; - } -=20 - static unsigned char *do_doctor(unsigned char *p, int count, struct dns_hea= der *header, size_t qlen, char *name, int *doctored) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_ov= erlays_A_record_from.patch b/src/patches/dnsmasq/013-Fix_crash_when_empty_add= ress_from_DNS_overlays_A_record_from.patch deleted file mode 100644 index 736cf38..0000000 --- a/src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_= A_record_from.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 41a8d9e99be9f2cc8b02051dd322cb45e0faac87 Mon Sep 17 00:00:00 2001 -From: =3D?utf8?q?Edwin=3D20T=3DC3=3DB6r=3DC3=3DB6k?=3D -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. -=20 -+ 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=C3=83=C2=B6r=C3=83=C2= =B6k for -+ the patch. -+ - =09 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 -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 *a= ddr, - existing record is for an A or AAAA and - the record we're trying to insert is the same,=20 - 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 =3D=3D addr->addr.addr4.s_addr) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.p= atch 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 -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_head= er *header, size_t plen, ch - if (crecp->flags & F_NEG) - return STAT_INSECURE_DS; - =20 -+ /* 4035 5.2=20 -+ 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 =3D crecp; recp1; recp1 =3D cache_find_by_name(recp1, name, no= w, F_DS)) -+ if (hash_find(ds_digest_name(recp1->addr.ds.digest))) -+ break; -+ =20 -+ if (!recp1) -+ return STAT_INSECURE_DS; -+ - /* NOTE, we need to find ONE DNSKEY which matches the DS */ - for (valid =3D 0, j =3D ntohs(header->ancount); j !=3D 0 && !valid; j--) = - { ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patc= h 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 -Date: Sat, 21 Nov 2015 21:47:41 +0000 -Subject: [PATCH] Fix crash at start up with conf-dir=3D/path,* - -Thanks to Brian Carpenter and American Fuzzy Lop for finding the bug. ---- - src/option.c | 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 *errs= tr, char *gen_err, int comma - li =3D opt_malloc(sizeof(struct list)); - if (*arg =3D=3D '*') - { -- li->next =3D match_suffix; -- match_suffix =3D li; -- /* Have to copy: buffer is overwritten */ -- li->suffix =3D opt_string_alloc(arg+1); -+ /* "*" with no suffix is a no-op */ -+ if (arg[1] =3D=3D 0) -+ free(li); -+ else -+ { -+ li->next =3D match_suffix; -+ match_suffix =3D li; -+ /* Have to copy: buffer is overwritten */ -+ li->suffix =3D opt_string_alloc(arg+1); -+ } - } - else - { ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validati= on.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 -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 -=20 - #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 -=20 - #ifdef HAVE_DNSSEC - #define HASH_SIZE 20 /* SHA-1 digest size */ -@@ -626,9 +621,7 @@ struct frec { - #ifdef HAVE_DNSSEC=20 - 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 *na= me, 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 ple= n, 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 ple= n, 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, - } - } -=20 --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 =3D *sz; -- =20 -- if (new_sz > new) -+ int old =3D *szp; -+ -+ if (old >=3D new+1) - return 1; -=20 - if (new >=3D 100) - return 0; -=20 -- new_sz +=3D 5; -+ new +=3D 5; - =20 -- if (!(p =3D whine_malloc((new_sz) * sizeof(unsigned char **)))) -+ if (!(p =3D whine_malloc(new * sizeof(unsigned char **)))) - return 0; =20 - =20 -- if (*wkspc) -+ if (old !=3D 0 && *wkspc) - { -- memcpy(p, *wkspc, *sz * sizeof(unsigned char **)); -+ memcpy(p, *wkspc, old * sizeof(unsigned char **)); - free(*wkspc); - } - =20 - *wkspc =3D p; -- *sz =3D new_sz; -+ *szp =3D new; -=20 - return 1; - } -@@ -706,47 +708,28 @@ static void sort_rrset(struct dns_header *header, size= _t plen, u16 *rr_desc, int - } while (swap); - } -=20 --/* Validate a single RRset (class, type, name) in the supplied DNS reply=20 -- Return code: -- STAT_SECURE if it validates. -- STAT_SECURE_WILDCARD if it validates and is the result of wildcard expan= sion. -- (In this case *wildcard_out points to the "body" of the wildcard within = name.)=20 -- 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 ke= yname) -- -- if key is non-NULL, use that key, which has the algo and tag given in th= e params of those names, -- otherwise find the key in the cache. -+static unsigned char **rrset =3D NULL, **sigs =3D NULL; -=20 -- 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 ple= n, int class, int type,=20 -- 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,=20 -+ char *name, char *keyname, int *sigcnt, int *rrcnt) - { -- static unsigned char **rrset =3D NULL, **sigs =3D NULL; -- static int rrset_sz =3D 0, sig_sz =3D 0; -- =20 -+ static int rrset_sz =3D 0, sig_sz =3D 0;=20 - unsigned char *p; -- int rrsetidx, sigidx, res, rdlen, j, name_labels; -- struct crec *crecp =3D NULL; -- int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, = key_tag; -- u16 *rr_desc =3D get_desc(type); --=20 -- if (wildcard_out) -- *wildcard_out =3D NULL; -- =20 -+ int rrsetidx, sigidx, j, rdlen, res; -+ int name_labels =3D count_labels(name); /* For 4035 5.3.2 check */ -+ int gotkey =3D 0; -+ - if (!(p =3D skip_questions(header, plen))) - return STAT_BOGUS; -- =20 -- name_labels =3D count_labels(name); /* For 4035 5.3.2 check */ -=20 -- /* 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 =3D 0, sigidx =3D 0, j =3D ntohs(header->ancount) + ntohs(h= eader->nscount);=20 - j !=3D 0; j--)=20 - { - unsigned char *pstart, *pdata; -- int stype, sclass; -+ int stype, sclass, algo, type_covered, labels, sig_expiration, sig_in= ception; -=20 - pstart =3D p; - =20 -@@ -762,14 +745,14 @@ static int validate_rrset(time_t now, struct dns_heade= r *header, size_t plen, in - GETSHORT(rdlen, p); - =20 - if (!CHECK_LEN(header, p, plen, rdlen)) -- return STAT_BOGUS;=20 -+ return 0;=20 - =20 - if (res =3D=3D 1 && sclass =3D=3D class) - { - if (stype =3D=3D type) - { - if (!expand_workspace(&rrset, &rrset_sz, rrsetidx)) -- return STAT_BOGUS;=20 -+ return 0;=20 - =20 - rrset[rrsetidx++] =3D pstart; - } -@@ -777,14 +760,54 @@ static int validate_rrset(time_t now, struct dns_heade= r *header, size_t plen, in - if (stype =3D=3D T_RRSIG) - { - if (rdlen < 18) -- return STAT_BOGUS; /* bad packet */=20 -+ return 0; /* bad packet */=20 - =20 - GETSHORT(type_covered, p); -+ algo =3D *p++; -+ labels =3D *p++; -+ p +=3D 4; /* orig_ttl */ -+ GETLONG(sig_expiration, p); -+ GETLONG(sig_inception, p); -+ p +=3D 2; /* key_tag */ - =20 -- if (type_covered =3D=3D 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) !=3D 1) -+ return 0; -+ } -+ else -+ { -+ gotkey =3D 1; -+ =20 -+ if (!extract_name(header, plen, &p, keyname, 1, 0)) -+ return 0; -+ =20 -+ /* 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=20 -+ an attacker using signatures made with the key of an unrelated=20 -+ zone he controls. Note that the root key is always allowed. */ -+ if (*keyname !=3D 0) -+ { -+ char *name_start; -+ for (name_start =3D name; !hostname_isequal(name_start, keyname); ) -+ if ((name_start =3D strchr(name_start, '.'))) -+ name_start++; /* chop a label off and try again */ -+ else -+ return 0; -+ } -+ } -+ =20 -+ /* Don't count signatures for algos we don't support */ -+ if (check_date_range(sig_inception, sig_expiration) && -+ labels <=3D name_labels && -+ type_covered =3D=3D type &&=20 -+ algo_digest_name(algo)) - { - if (!expand_workspace(&sigs, &sig_sz, sigidx)) -- return STAT_BOGUS;=20 -+ return 0;=20 - =20 - sigs[sigidx++] =3D pdata; - }=20 -@@ -794,17 +817,45 @@ static int validate_rrset(time_t now, struct dns_heade= r *header, size_t plen, in - } - =20 - if (!ADD_RDLEN(header, p, plen, rdlen)) -- return STAT_BOGUS; -+ return 0; - } - =20 -- /* RRset empty */ -- if (rrsetidx =3D=3D 0) -- return STAT_INSECURE;=20 -+ *sigcnt =3D sigidx; -+ *rrcnt =3D rrsetidx; -+ -+ return 1; -+} -+ -+/* Validate a single RRset (class, type, name) in the supplied DNS reply=20 -+ Return code: -+ STAT_SECURE if it validates. -+ STAT_SECURE_WILDCARD if it validates and is the result of wildcard expan= sion. -+ (In this case *wildcard_out points to the "body" of the wildcard within = name.)=20 -+ STAT_BOGUS signature is wrong, bad packet. -+ STAT_NEED_KEY need DNSKEY to complete validation (name is returned in ke= yname) -+ STAT_NEED_DS need DS to complete validation (name is returned in keynam= e) -+ -+ if key is non-NULL, use that key, which has the algo and tag given in th= e params of those names, -+ otherwise find the key in the cache. -=20 -- /* no RRSIGs */ -- if (sigidx =3D=3D 0) -- return STAT_NO_SIG;=20 -+ 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 ple= n, int class, int type, int sigidx, int rrsetidx,=20 -+ 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 =3D NULL; -+ int algo, labels, orig_ttl, key_tag; -+ u16 *rr_desc =3D get_desc(type); -+=20 -+ if (wildcard_out) -+ *wildcard_out =3D NULL; - =20 -+ name_labels =3D count_labels(name); /* For 4035 5.3.2 check */ -+ - /* Sort RRset records into canonical order.=20 - 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_heade= r *header, size_t plen, in - algo =3D *p++; - labels =3D *p++; - GETLONG(orig_ttl, p); -- GETLONG(sig_expiration, p); -- GETLONG(sig_inception, p); -+ p +=3D 8; /* sig_expiration, sig_inception already checked */ - GETSHORT(key_tag, p); - =20 - if (!extract_name(header, plen, &p, keyname, 1, 0)) - return STAT_BOGUS; -=20 -- /* 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=20 -- an attacker using signatures made with the key of an unrelated=20 -- zone he controls. Note that the root key is always allowed. */ -- if (*keyname !=3D 0) -- { -- int failed =3D 0; -- =20 -- for (name_start =3D name; !hostname_isequal(name_start, keyname); ) -- if ((name_start =3D strchr(name_start, '.'))) -- name_start++; /* chop a label off and try again */ -- else -- { -- failed =3D 1; -- break; -- } -- -- /* Bad sig, try another */ -- if (failed) -- continue; -- } -- =20 -- /* Other 5.3.1 checks */ -- if (!check_date_range(sig_inception, sig_expiration) || -- labels > name_labels || -- !(hash =3D hash_find(algo_digest_name(algo))) || -+ if (!(hash =3D hash_find(algo_digest_name(algo))) || - !hash_init(hash, &ctx, &digest)) - continue; --=09 -+ =20 - /* OK, we have the signature record, see if the relevant DNSKEY is in= the cache. */ - if (!key && !(crecp =3D cache_find_by_name(NULL, keyname, now, F_DNSK= EY))) - return STAT_NEED_KEY; -@@ -971,10 +994,11 @@ static int validate_rrset(time_t now, struct dns_heade= r *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=20 -+ 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= =20 -+ STAT_NEED_DNSKEY DNSKEY records to validate a key not found, name in key= name=20 - */ - int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t ple= n, char *name, char *keyname, int class) - { -@@ -1001,23 +1025,6 @@ int dnssec_validate_by_ds(time_t now, struct dns_head= er *header, size_t plen, ch - return STAT_NEED_DS; - } - =20 -- /* If we've cached that DS provably doesn't exist, result must be INSECUR= E */ -- if (crecp->flags & F_NEG) -- return STAT_INSECURE_DS; -- =20 -- /* 4035 5.2=20 -- 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 =3D crecp; recp1; recp1 =3D cache_find_by_name(recp1, name, no= w, F_DS)) -- if (hash_find(ds_digest_name(recp1->addr.ds.digest))) -- break; -- =20 -- if (!recp1) -- return STAT_INSECURE_DS; -- - /* NOTE, we need to find ONE DNSKEY which matches the DS */ - for (valid =3D 0, j =3D ntohs(header->ancount); j !=3D 0 && !valid; j--) = - { -@@ -1070,7 +1077,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_heade= r *header, size_t plen, ch - void *ctx; - unsigned char *digest, *ds_digest; - const struct nettle_hash *hash; -- =20 -+ int sigcnt, rrcnt; -+ - if (recp1->addr.ds.algo =3D=3D algo &&=20 - recp1->addr.ds.keytag =3D=3D keytag && - recp1->uid =3D=3D (unsigned int)class && -@@ -1088,10 +1096,14 @@ int dnssec_validate_by_ds(time_t now, struct dns_hea= der *header, size_t plen, ch - =20 - from_wire(name); - =20 -- if (recp1->addr.ds.keylen =3D=3D (int)hash->digest_size && -+ if (!(recp1->flags & F_NEG) && -+ recp1->addr.ds.keylen =3D=3D (int)hash->digest_size && - (ds_digest =3D blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.= ds.keylen, NULL)) && - memcmp(ds_digest, digest, recp1->addr.ds.keylen) =3D=3D 0 && -- validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL,= key, rdlen - 4, algo, keytag) =3D=3D STAT_SECURE) -+ explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &r= rcnt) && -+ sigcnt !=3D 0 && rrcnt !=3D 0 && -+ validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name,= keyname,=20 -+ NULL, key, rdlen - 4, algo, keytag) =3D=3D STAT_SECURE) - { - valid =3D 1; - break; -@@ -1112,7 +1124,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_heade= r *header, size_t plen, ch - { - /* Ensure we have type, class TTL and length */ - if (!(rc =3D extract_name(header, plen, &p, name, 0, 10))) -- return STAT_INSECURE; /* bad packet */ -+ return STAT_BOGUS; /* bad packet */ - =20 - GETSHORT(qtype, p);=20 - GETSHORT(qclass, p); -@@ -1198,7 +1210,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_heade= r *header, size_t plen, ch - =20 - /* commit cache insert. */ - cache_end_insert(); -- return STAT_SECURE; -+ return STAT_OK; - } -=20 - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY"); -@@ -1207,12 +1219,14 @@ int dnssec_validate_by_ds(time_t now, struct dns_hea= der *header, size_t plen, ch -=20 - /* 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,=20 -+ 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 pac= ket. - STAT_NEED_KEY DNSKEY records to validate a DS not found, name in keyn= ame -+ STAT_NEED_DS DS record needed. - */ -=20 - 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 !=3D T_DS || qclass !=3D class) - val =3D STAT_BOGUS; - else -- val =3D dnssec_validate_reply(now, header, plen, name, keyname, NULL, &= neganswer, &nons); -+ val =3D dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0= , &neganswer, &nons); - /* Note dnssec_validate_reply() will have cached positive answers */ - =20 - if (val =3D=3D STAT_INSECURE) -@@ -1242,22 +1256,21 @@ int dnssec_validate_ds(time_t now, struct dns_header= *header, size_t plen, char - =20 - if (!(p =3D skip_section(p, ntohs(header->ancount), header, plen))) - val =3D STAT_BOGUS; -- =20 -- /* If we return STAT_NO_SIG, name contains the name of the DS query */ -- if (val =3D=3D STAT_NO_SIG) -- return val; - =20 - /* 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 =3D=3D STAT_BOGUS || (val =3D=3D STAT_NEED_KEY && hostname_isequ= al(name, keyname))) -+ if (val =3D=3D STAT_BOGUS || (val =3D=3D STAT_NEED_KEY && hostname_isequa= l(name, keyname))) - { - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS"); - return STAT_BOGUS; - } -+ =20 -+ if (val !=3D STAT_SECURE) -+ return val; -=20 - /* By here, the answer is proved secure, and a positive answer has been c= ached. */ -- if (val =3D=3D STAT_SECURE && neganswer) -+ if (neganswer) - { - int rdlen, flags =3D F_FORWARD | F_DS | F_NEG | F_DNSSECOK; - unsigned long ttl, minttl =3D ULONG_MAX; -@@ -1317,15 +1330,14 @@ int dnssec_validate_ds(time_t now, struct dns_header= *header, size_t plen, char - =20 - cache_end_insert(); =20 - =20 -- 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;=20 - } -=20 -- return val; -+ return STAT_OK; - } -=20 -+ - /* 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 =3D 0x80 >> (type & 0x07); -=20 - if (nons) -- *nons =3D 0; -+ *nons =3D 1; - =20 - /* Find NSEC record that proves name doesn't exist */ - for (i =3D 0; i < nsec_count; i++) -@@ -1480,9 +1492,22 @@ static int prove_non_existence_nsec(struct dns_header= *header, size_t plen, unsi - /* rdlen is now length of type map, and p points to it */ - =20 - /* If we can prove that there's no NS record, return that information. */ -- if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >> T_NS)) =3D= =3D 0) -- *nons =3D 1; -+ if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >> T_NS)) != =3D 0) -+ *nons =3D 0; - =20 -+ if (rdlen >=3D 2 && p[0] =3D=3D 0) -+ { -+ /* A CNAME answer would also be valid, so if there's a CNAME is shou= ld=20 -+ have been returned. */ -+ if ((p[2] & (0x80 >> T_CNAME)) !=3D 0) -+ return STAT_BOGUS; -+ =20 -+ /* If the SOA bit is set for a DS record, then we have the -+ DS from the wrong side of the delegation. */ -+ if (type =3D=3D T_DS && (p[2] & (0x80 >> T_SOA)) !=3D 0) -+ return STAT_BOGUS; -+ } -+ - while (rdlen >=3D 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_cou= nt, 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; -=20 - for (i =3D 0; i < nsec_count; i++) -@@ -1599,7 +1624,9 @@ static int check_nsec3_coverage(struct dns_header *hea= der, size_t plen, int dige - p +=3D 8; /* class, type, TTL */ - GETSHORT(rdlen, p); - psave =3D p; -- p +=3D 4; /* algo, flags, iterations */ -+ p++; /* algo */ -+ flags =3D *p++; /* flags */ -+ p +=3D 2; /* iterations */ - salt_len =3D *p++; /* salt_len */ - p +=3D salt_len; /* salt */ - hash_len =3D *p++; /* p now points to next hashed name */ -@@ -1626,16 +1653,29 @@ static int check_nsec3_coverage(struct dns_header *h= eader, size_t plen, int dige - return 0; - =09 - /* If we can prove that there's no NS record, return that information. */ -- if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >> T_NS)) =3D= =3D 0) -- *nons =3D 1; -+ if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >> T_NS)) !=3D= 0) -+ *nons =3D 0; - =09 -+ if (rdlen >=3D 2 && p[0] =3D=3D 0) -+ { -+ /* A CNAME answer would also be valid, so if there's a CNAME is shoul= d=20 -+ have been returned. */ -+ if ((p[2] & (0x80 >> T_CNAME)) !=3D 0) -+ return 0; -+ =20 -+ /* If the SOA bit is set for a DS record, then we have the -+ DS from the wrong side of the delegation. */ -+ if (type =3D=3D T_DS && (p[2] & (0x80 >> T_SOA)) !=3D 0) -+ return 0; -+ } -+ - while (rdlen >=3D 2) - { - if (p[0] =3D=3D type >> 8) - { - /* Does the NSEC3 say our type exists? */ - if (offset < p[1] && (p[offset+2] & mask) !=3D 0) -- return STAT_BOGUS; -+ return 0; - =09 - break; /* finshed checking */ - } -@@ -1643,7 +1683,7 @@ static int check_nsec3_coverage(struct dns_header *hea= der, size_t plen, int dige - rdlen -=3D p[1]; - p +=3D p[1]; - } -- -+ =09 - return 1; - } - else if (rc < 0) -@@ -1651,16 +1691,27 @@ static int check_nsec3_coverage(struct dns_header *h= eader, size_t plen, int dige - /* Normal case, hash falls between NSEC3 name-hash and next domain name-h= ash, - wrap around case, name-hash falls between NSEC3 name-hash and end */ - if (memcmp(p, digest, digest_len) >=3D 0 || memcmp(workspace2, p, digest_= len) >=3D 0) -- return 1; -+ { -+ if ((flags & 0x01) && nons) /* opt out */ -+ *nons =3D 0; -+ -+ return 1; -+ } - } - else=20 - { - /* wrap around case, name falls between start and next domain name */ - if (memcmp(workspace2, p, digest_len) >=3D 0 && memcmp(p, digest, digest_= len) >=3D 0) -- return 1; -+ { -+ if ((flags & 0x01) && nons) /* opt out */ -+ *nons =3D 0; -+ -+ return 1; -+ } - } - } - } -+ - return 0; - } -=20 -@@ -1673,7 +1724,7 @@ static int prove_non_existence_nsec3(struct dns_header= *header, size_t plen, uns - char *closest_encloser, *next_closest, *wildcard; - =20 - if (nons) -- *nons =3D 0; -+ *nons =3D 1; - =20 - /* Look though the NSEC3 records to find the first one with=20 - an algorithm we support (currently only algo =3D=3D 1). -@@ -1813,16 +1864,81 @@ static int prove_non_existence_nsec3(struct dns_head= er *header, size_t plen, uns - =20 - return STAT_SECURE; - } -- =20 --/* Validate all the RRsets in the answer and authority sections of the repl= y (4035:3.2.3) */ --/* Returns are the same as validate_rrset, plus the class if the missing ke= y 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. -+ =20 -+ name returned unaltered. -+*/ -+static int zone_status(char *name, int class, char *keyname, time_t now) -+{ -+ int name_start =3D strlen(name); -+ struct crec *crecp; -+ char *p; -+ =20 -+ while (1) -+ { -+ strcpy(keyname, &name[name_start]); -+ =20 -+ if (!(crecp =3D cache_find_by_name(NULL, keyname, now, F_DS))) -+ return STAT_NEED_DS; -+ else -+ do=20 -+ { -+ if (crecp->uid =3D=3D (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 he= re, -+ 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 wh= en -+ we prove that we're at a zone cut AND there's no DS record. -+ */ =20 -+ 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(crec= p->addr.ds.algo)) -+ return STAT_INSECURE; /* algo we can't use - insecure */ -+ } -+ } -+ while ((crecp =3D cache_find_by_name(crecp, keyname, now, F_DS))); -+ =20 -+ if (name_start =3D=3D 0) -+ break; -+ -+ for (p =3D &name[name_start-2]; (*p !=3D '.') && (p !=3D name); p--); -+ =20 -+ if (p !=3D name) -+ p++; -+ =20 -+ name_start =3D p - name; -+ }=20 -+ -+ return STAT_SECURE; -+} -+ =20 -+/* Validate all the RRsets in the answer and authority sections of the repl= y (4035:3.2.3)=20 -+ 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 ke= yname, class in *class) -+ STAT_NEED_DS need DS to complete validation (name is returned in keynam= e)=20 -+*/ - int dnssec_validate_reply(time_t now, struct dns_header *header, size_t ple= n, char *name, char *keyname,=20 -- 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 =3D CNAME_CHAIN; -- int nsec_type =3D 0, have_answer =3D 0; -+ static unsigned char **targets =3D NULL; -+ static int target_sz =3D 0; -+ -+ unsigned char *ans_start, *p1, *p2, **nsecs; -+ int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetid= x; -+ int i, j, rc, nsec_count; -+ int nsec_type; -=20 - if (neganswer) - *neganswer =3D 0; -@@ -1833,70 +1949,51 @@ int dnssec_validate_reply(time_t now, struct dns_hea= der *header, size_t plen, ch - if (RCODE(header) !=3D NXDOMAIN && RCODE(header) !=3D NOERROR) - return STAT_INSECURE; -=20 -- qname =3D p1 =3D (unsigned char *)(header+1); -+ p1 =3D (unsigned char *)(header+1); - =20 -+ /* 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; -+ =20 -+ targets[0] =3D p1; -+ targetidx =3D 1; -+ =20 - if (!extract_name(header, plen, &p1, name, 1, 4)) - return STAT_BOGUS; -- -+ =20 - GETSHORT(qtype, p1); - GETSHORT(qclass, p1); - ans_start =3D p1; -- -- if (qtype =3D=3D T_ANY) -- have_answer =3D 1; - =20 -- /* Can't validate an RRISG query */ -+ /* Can't validate an RRSIG query */ - if (qtype =3D=3D T_RRSIG) - return STAT_INSECURE; --=20 -- cname_loop: -- for (j =3D ntohs(header->ancount); j !=3D 0; j--)=20 -- { -- /* leave pointer to missing name in qname */ -- =20 -- if (!(rc =3D extract_name(header, plen, &p1, name, 0, 10))) -- return STAT_BOGUS; /* bad packet */ -- =20 -- GETSHORT(type2, p1);=20 -- GETSHORT(class2, p1); -- p1 +=3D 4; /* TTL */ -- GETSHORT(rdlen2, p1); -- -- if (rc =3D=3D 1 && qclass =3D=3D class2) -- { -- /* Do we have an answer for the question? */ -- if (type2 =3D=3D qtype) -- { -- have_answer =3D 1; -- break; -- } -- else if (type2 =3D=3D T_CNAME) -- { -- qname =3D p1; -- =20 -- /* looped CNAMES */ -- if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0)) -- return STAT_BOGUS; -- =20 -- p1 =3D ans_start; -- goto cname_loop; -- } -- }=20 -- -- if (!ADD_RDLEN(header, p1, plen, rdlen2)) -- return STAT_BOGUS; -- } -- =20 -- if (neganswer && !have_answer) -- *neganswer =3D 1; - =20 -- /* No data, therefore no sigs */ -- if (ntohs(header->ancount) + ntohs(header->nscount) =3D=3D 0) -- { -- *keyname =3D 0; -- return STAT_NO_SIG; -- } -- -+ if (qtype !=3D T_CNAME) -+ for (j =3D ntohs(header->ancount); j !=3D 0; j--)=20 -+ { -+ if (!(p1 =3D skip_name(p1, header, plen, 10))) -+ return STAT_BOGUS; /* bad packet */ -+=09 -+ GETSHORT(type2, p1);=20 -+ p1 +=3D 6; /* class, TTL */ -+ GETSHORT(rdlen2, p1); =20 -+=09 -+ if (type2 =3D=3D T_CNAME) -+ { -+ if (!expand_workspace(&targets, &target_sz, targetidx)) -+ return STAT_BOGUS; -+ =20 -+ targets[targetidx++] =3D p1; /* pointer to target name */ -+ } -+=09 -+ if (!ADD_RDLEN(header, p1, plen, rdlen2)) -+ return STAT_BOGUS; -+ } -+ =20 - for (p1 =3D ans_start, i =3D 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_heade= r *header, size_t plen, ch - /* Not done, validate now */ - if (j =3D=3D 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_h= eader *header, size_t plen, ch - char *wildname; - int have_wildcard =3D 0; -=20 -- rc =3D validate_rrset(now, header, plen, class1, type1, name, keynam= e, &wildname, NULL, 0, 0, 0); -- =20 -- if (rc =3D=3D STAT_SECURE_WILDCARD) -- { -- have_wildcard =3D 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 =3D find_nsec_records(header, plen, &nsec= s, &nsec_count, class1))) -- return STAT_BOGUS; /* No NSECs or bad packet */ -- =20 -- if (nsec_type =3D=3D T_NSEC) -- rc =3D prove_non_existence_nsec(header, plen, nsecs, nsec_count, daem= on->workspacename, keyname, name, type1, NULL); -- else -- rc =3D prove_non_existence_nsec3(header, plen, nsecs, nsec_count, dae= mon->workspacename,=20 -- keyname, name, type1, wildname, NULL); -- =20 -- if (rc !=3D STAT_SECURE) -- return rc; -- }=20 -- else if (rc !=3D STAT_SECURE) -- { -- if (class) -- *class =3D class1; /* Class for DS or DNSKEY */ -+ if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigc= nt, &rrcnt)) -+ return STAT_BOGUS; -=20 -- if (rc =3D=3D STAT_NO_SIG) -+ /* No signatures for RRset. We can be configured to assume this is O= K and return a INSECURE result. */ -+ if (sigcnt =3D=3D 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 =3D=3D CNAME_CHAIN || i < ntohs(header->ancount))=20 -- /* No CNAME chain, or no sig in answer section, return empty name. */ -- *keyname =3D 0; -- else if (!extract_name(header, plen, &qname, keyname, 1, 0)) -- return STAT_BOGUS; -+ rc =3D zone_status(name, class1, keyname, now); -+ if (rc =3D=3D STAT_SECURE) -+ rc =3D STAT_BOGUS; -+ if (class) -+ *class =3D class1; /* Class for NEED_DS or NEED_DNSKEY */ - } --=20 -+ else=20 -+ rc =3D STAT_INSECURE;=20 -+ =20 - return rc; - } - =20 -- /* Cache RRsigs in answer section, and if we just validated a DS RRs= et, 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 =3D zone_status(daemon->workspacename, class1, keyname, now); -+ if (rc !=3D STAT_SECURE) -+ { -+ /* Zone is insecure, don't need to validate RRset */ -+ if (class) -+ *class =3D class1; /* Class for NEED_DS or NEED_DNSKEY */ -+ return rc; -+ }=20 -+ =20 -+ rc =3D validate_rrset(now, header, plen, class1, type1, sigcnt, rrcn= t, name, keyname, &wildname, NULL, 0, 0, 0); - =20 -- for (p2 =3D ans_start, j =3D 0; j < ntohs(header->ancount); j++) -+ if (rc =3D=3D STAT_BOGUS || rc =3D=3D STAT_NEED_KEY || rc =3D=3D STA= T_NEED_DS) - { -- if (!(rc =3D extract_name(header, plen, &p2, name, 0, 10))) -- return STAT_BOGUS; /* bad packet */ -+ if (class) -+ *class =3D class1; /* Class for DS or DNSKEY */ -+ return rc; -+ }=20 -+ else=20 -+ { -+ /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */ -+ =20 -+ /* 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 =3D 0; j addr.ds.digest =3D digest; -- crecp->addr.ds.keydata =3D key; -- crecp->addr.ds.algo =3D algo; -- crecp->addr.ds.keytag =3D keytag; -- crecp->addr.ds.keylen =3D rdlen2 - 4;=20 -- }=20 -- } -- } -- else if (type2 =3D=3D T_RRSIG) -- { -- if (rdlen2 < 18) -- return STAT_BOGUS; /* bad packet */ -+ if (nsec_type =3D=3D T_NSEC) -+ rc =3D prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon-= >workspacename, keyname, name, type1, NULL); -+ else -+ rc =3D prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon= ->workspacename,=20 -+ keyname, name, type1, wildname, NULL); -+ =20 -+ if (rc =3D=3D STAT_BOGUS) -+ return rc; -+ }=20 -+ =20 -+ /* 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(); -+ =20 -+ for (p2 =3D ans_start, j =3D 0; j < ntohs(header->ancount); j++) -+ { -+ if (!(rc =3D extract_name(header, plen, &p2, name, 0, 10))) -+ return STAT_BOGUS; /* bad packet */ -+ =20 -+ GETSHORT(type2, p2); -+ GETSHORT(class2, p2); -+ GETLONG(ttl, p2); -+ GETSHORT(rdlen2, p2); -+ =20 -+ if (!CHECK_LEN(header, p2, plen, rdlen2)) -+ return STAT_BOGUS; /* bad packet */ -+ =20 -+ if (class2 =3D=3D class1 && rc =3D=3D 1) -+ {=20 -+ psave =3D p2; - =20 -- GETSHORT(type_covered, p2); -- -- if (type_covered =3D=3D type1 &&=20 -- (type_covered =3D=3D T_A || type_covered =3D=3D T_AAAA || -- type_covered =3D=3D T_CNAME || type_covered =3D=3D T_DS ||=20 -- type_covered =3D=3D T_DNSKEY || type_covered =3D=3D T_PTR))=20 -+ if (type1 =3D=3D T_DS && type2 =3D=3D T_DS) - { -- a.addr.dnssec.type =3D type_covered; -- a.addr.dnssec.class =3D class1; -+ if (rdlen2 < 4) -+ return STAT_BOGUS; /* bad packet */ - =20 -- algo =3D *p2++; -- p2 +=3D 13; /* labels, orig_ttl, expiration, inception */ - GETSHORT(keytag, p2); -+ algo =3D *p2++; -+ digest =3D *p2++; -+ =20 -+ /* Cache needs to known class for DNSSEC stuff */ -+ a.addr.dnssec.class =3D class2; - =20 -- /* We don't cache sigs for wildcard answers, because to reproduce = the -- answer from the cache will require one or more NSEC/NSEC3 records=20 -- 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 =3D blockdata_alloc((char*)psave, rdlen= 2))) -+ if ((key =3D blockdata_alloc((char*)p2, rdlen2 - 4))) - { -- if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKE= Y | F_DS))) -+ if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F= _DNSSECOK))) - blockdata_free(key); - else - { -- crecp->addr.sig.keydata =3D key; -- crecp->addr.sig.keylen =3D rdlen2; -- crecp->addr.sig.keytag =3D keytag; -- crecp->addr.sig.type_covered =3D type_covered; -- crecp->addr.sig.algo =3D algo; -+ a.addr.keytag =3D keytag; -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag= %u"); -+ crecp->addr.ds.digest =3D digest; -+ crecp->addr.ds.keydata =3D key; -+ crecp->addr.ds.algo =3D algo; -+ crecp->addr.ds.keytag =3D keytag; -+ crecp->addr.ds.keylen =3D rdlen2 - 4;=20 -+ }=20 -+ } -+ } -+ else if (type2 =3D=3D T_RRSIG) -+ { -+ if (rdlen2 < 18) -+ return STAT_BOGUS; /* bad packet */ -+ =20 -+ GETSHORT(type_covered, p2); -+ =20 -+ if (type_covered =3D=3D type1 &&=20 -+ (type_covered =3D=3D T_A || type_covered =3D=3D T_AAAA || -+ type_covered =3D=3D T_CNAME || type_covered =3D=3D T_DS ||=20 -+ type_covered =3D=3D T_DNSKEY || type_covered =3D=3D T_PTR))=20 -+ { -+ a.addr.dnssec.type =3D type_covered; -+ a.addr.dnssec.class =3D class1; -+ =20 -+ algo =3D *p2++; -+ p2 +=3D 13; /* labels, orig_ttl, expiration, inception */ -+ GETSHORT(keytag, p2); -+ =20 -+ /* 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 f= or -+ this RRset asking for a secure answer will always be forwarded. */ -+ if (!have_wildcard && (key =3D blockdata_alloc((char*)psave, rdlen2))) -+ { -+ if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_D= NSKEY | F_DS))) -+ blockdata_free(key); -+ else -+ { -+ crecp->addr.sig.keydata =3D key; -+ crecp->addr.sig.keylen =3D rdlen2; -+ crecp->addr.sig.keytag =3D keytag; -+ crecp->addr.sig.type_covered =3D type_covered; -+ crecp->addr.sig.algo =3D algo; -+ } - } - } - } -+ =20 -+ p2 =3D psave; - } - =20 -- p2 =3D psave; -+ if (!ADD_RDLEN(header, p2, plen, rdlen2)) -+ return STAT_BOGUS; /* bad packet */ - } - =20 -- if (!ADD_RDLEN(header, p2, plen, rdlen2)) -- return STAT_BOGUS; /* bad packet */ -+ cache_end_insert(); - } -- =20 -- cache_end_insert(); - } - } -=20 -@@ -2083,143 +2223,49 @@ int dnssec_validate_reply(time_t now, struct dns_he= ader *header, size_t plen, ch - return STAT_BOGUS; - } -=20 -- /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN r= eply */ -- if (have_answer) -- return STAT_SECURE; -- =20 -- /* 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 =3D 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-ex= istence -- if DS records in CNAME chains. */ -- if (cname_count =3D=3D CNAME_CHAIN) /* No CNAME chain, return empty n= ame. */ -- *keyname =3D 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 po= inting into -- an unsigned zone. Return STAT_NO_SIG to cause this to be proved. */ -- } -- =20 -- /* Get name of missing answer */ -- if (!extract_name(header, plen, &qname, name, 1, 0)) -- return STAT_BOGUS; -- =20 -- if (nsec_type =3D=3D 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, daemo= n->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_*=20 -- STAT_BOGUS - error -- STAT_INSECURE - name of first non-secure record in name=20 --*/ --int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, = char *name, char *keyname) --{ -- unsigned char *p =3D (unsigned char *)(header+1); -- int type, class, qclass, rdlen, j, rc; -- int cname_count =3D CNAME_CHAIN; -- char *wildname; -- -- /* Get question */ -- if (!extract_name(header, plen, &p, name, 1, 4)) -- return STAT_BOGUS; -- =20 -- p +=3D2; /* type */ -- GETSHORT(qclass, p); -- -- while (1) -- { -- for (j =3D ntohs(header->ancount); j !=3D 0; j--)=20 -- { -- if (!(rc =3D extract_name(header, plen, &p, name, 0, 10))) -- return STAT_BOGUS; /* bad packet */ -- =20 -- GETSHORT(type, p);=20 -- GETSHORT(class, p); -- p +=3D 4; /* TTL */ -- GETSHORT(rdlen, p); -- -- /* Not target, loop */ -- if (rc =3D=3D 2 || qclass !=3D class) -- { -- if (!ADD_RDLEN(header, p, plen, rdlen)) -- return STAT_BOGUS; -- continue; -- } -- =20 -- /* Got to end of CNAME chain. */ -- if (type !=3D T_CNAME) -- return STAT_INSECURE; -- =20 -- /* validate CNAME chain, return if insecure or need more data */ -- rc =3D validate_rrset(now, header, plen, class, type, name, keyname, &wi= ldname, NULL, 0, 0, 0); -- =20 -- if (rc =3D=3D 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 =3D find_nsec_records(header, plen, &nsecs, &nsec_co= unt, class))) -- return STAT_BOGUS; /* No NSECs or bad packet */ -- =20 -- /* 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 =3D 0; i < nsec_count; i++) -- { -- unsigned char *p1 =3D nsecs[i]; -- =20 -- if (!extract_name(header, plen, &p1, daemon->workspacename, 1, 0)) -- return STAT_BOGUS; -- -- rc =3D validate_rrset(now, header, plen, class, nsec_type, daemon->work= spacename, keyname, NULL, NULL, 0, 0, 0); -+ /* OK, all the RRsets validate, now see if we have a missing answer or CN= AME target. */ -+ for (j =3D 0; j = workspacename, keyname, name, type, NULL); -- else -- rc =3D prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon-= >workspacename,=20 -- keyname, name, type, wildname, NULL); -- =20 -- if (rc !=3D STAT_SECURE) -- return rc; -- } -- =20 -- if (rc !=3D STAT_SECURE) -- { -- if (rc =3D=3D STAT_NO_SIG) -- rc =3D STAT_INSECURE; -- return rc; -- } -+ }=20 -+ =09 -+ return STAT_BOGUS; /* signed zone, no NSECs */ -+ } -+ } -=20 -- /* Loop down CNAME chain/ */ -- if (!cname_count-- ||=20 -- !extract_name(header, plen, &p, name, 1, 0) || -- !(p =3D skip_questions(header, plen))) -- return STAT_BOGUS; -- =20 -- break; -- } -+ if (nsec_type =3D=3D T_NSEC) -+ rc =3D prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon-= >workspacename, keyname, name, qtype, nons); -+ else -+ rc =3D prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon= ->workspacename, keyname, name, qtype, NULL, nons); -=20 -- /* End of CNAME chain */ -- return STAT_INSECURE;=09 -- } -+ if (rc !=3D STAT_SECURE) -+ return rc; -+ } -+ =20 -+ return STAT_SECURE; - } -=20 -=20 -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); -=20 --#ifdef HAVE_DNSSEC --static int tcp_key_recurse(time_t now, int status, struct dns_header *heade= r, size_t n,=20 -- int class, char *name, char *keyname, struct server *server, int *key= count); --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_hea= der *header, size_t plen,=20 -- char *name, char *keyname); --#endif -- -- - /* Send a UDP packet with its source address set as "source"=20 - 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,=20 -@@ -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 & FRE= C_CHECKING_DISABLED)) - { -- int status; -+ int status =3D 0; -=20 - /* We've had a reply already, which we're validating. Ignore this duplic= ate */ - if (forward->blocking_query) - return; -- -- if (header->hb3 & HB3_TC) -- { -- /* Truncated answer can't be validated. -+ =20 -+ /* 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 =3D STAT_TRUNCATED; -- } -- else if (forward->flags & FREC_DNSKEY_QUERY) -- status =3D dnssec_validate_by_ds(now, header, n, daemon->namebuff, dae= mon->keyname, forward->class); -- else if (forward->flags & FREC_DS_QUERY) -- { -- status =3D dnssec_validate_ds(now, header, n, daemon->namebuff, daem= on->keyname, forward->class); -- /* Provably no DS, everything below is insecure, even if signatures = are offered */ -- if (status =3D=3D 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=20 -- DS chain, so we don't return replies from cache missing sigs. */ -- status =3D STAT_INSECURE_DS; -- else if (status =3D=3D STAT_NO_SIG) -- { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- { -- status =3D send_check_sign(forward, now, header, n, daemon->namebuf= f, daemon->keyname); -- if (status =3D=3D STAT_INSECURE) -- status =3D STAT_INSECURE_DS; -- } -- else -- status =3D STAT_INSECURE_DS; -- } -- else if (status =3D=3D STAT_NO_NS) -- status =3D STAT_BOGUS; -- } -- else if (forward->flags & FREC_CHECK_NOSIGN) -- { -- status =3D dnssec_validate_ds(now, header, n, daemon->namebuff, daem= on->keyname, forward->class); -- if (status !=3D STAT_NEED_KEY) -- status =3D do_check_sign(forward, status, now, daemon->namebuff, daemon->= keyname); -- } -- else -+ if (header->hb3 & HB3_TC) -+ status =3D STAT_TRUNCATED; -+ =20 -+ while (1) - { -- status =3D dnssec_validate_reply(now, header, n, daemon->namebuff, d= aemon->keyname, &forward->class, NULL, NULL); -- if (status =3D=3D STAT_NO_SIG) -+ /* As soon as anything returns BOGUS, we stop and unwind, to do othe= rwise -+ would invite infinite loops, since the answers to DNSKEY and DS queries -+ will not be cached, so they'll be repeated. */ -+ if (status !=3D STAT_BOGUS && status !=3D STAT_TRUNCATED && status != =3D STAT_ABANDONED) - { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- status =3D send_check_sign(forward, now, header, n, daemon->namebuff,= daemon->keyname); -+ if (forward->flags & FREC_DNSKEY_QUERY) -+ status =3D dnssec_validate_by_ds(now, header, n, daemon->namebuff, da= emon->keyname, forward->class); -+ else if (forward->flags & FREC_DS_QUERY) -+ status =3D dnssec_validate_ds(now, header, n, daemon->namebuff, daemo= n->keyname, forward->class); - else -- status =3D STAT_INSECURE; -+ status =3D dnssec_validate_reply(now, header, n, daemon->namebuff, da= emon->keyname, &forward->class,=20 -+ 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. */ =20 -- if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEED_DS_NEG || stat= us =3D=3D STAT_NEED_KEY) -- { -- struct frec *new, *orig; -- =20 -- /* Free any saved query */ -- if (forward->stash) -- blockdata_free(forward->stash); -- =20 -- /* Now save reply pending receipt of key data */ -- if (!(forward->stash =3D blockdata_alloc((char *)header, n))) -- return; -- forward->stash_len =3D n; - =20 -- anotherkey: =20 -- /* Find the original query that started it all.... */ -- for (orig =3D forward; orig->dependent; orig =3D orig->dependent); -- -- if (--orig->work_counter =3D=3D 0 || !(new =3D get_new_frec(now, NUL= L, 1))) -- status =3D STAT_INSECURE; -- else -+ /* Can't validate, as we're missing key data. Put this -+ answer aside, whilst we get that. */ =20 -+ if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEED_KEY) - { -- int fd; -- struct frec *next =3D new->next; -- *new =3D *forward; /* copy everything, then overwrite */ -- new->next =3D next; -- new->blocking_query =3D NULL; -- new->sentto =3D server; -- new->rfd4 =3D NULL; -- new->orig_domain =3D NULL; --#ifdef HAVE_IPV6 -- new->rfd6 =3D NULL; --#endif -- new->flags &=3D ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_CHECK_NOSIGN= ); -+ struct frec *new, *orig; - =20 -- new->dependent =3D forward; /* to find query awaiting new one. */ -- forward->blocking_query =3D new; /* for garbage cleaning */ -- /* validate routines leave name of required record in daemon->keyname */ -- if (status =3D=3D STAT_NEED_KEY) -- { -- new->flags |=3D FREC_DNSKEY_QUERY;=20 -- nn =3D dnssec_generate_query(header, ((char *) header) + daemon->pa= cket_buff_sz, -- daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->ed= ns_pktsz); -- } -- else=20 -- { -- if (status =3D=3D STAT_NEED_DS_NEG) -- new->flags |=3D FREC_CHECK_NOSIGN; -- else -- new->flags |=3D FREC_DS_QUERY; -- nn =3D dnssec_generate_query(header,((char *) header) + daemon->pac= ket_buff_sz, -- daemon->keyname, forward->class, T_DS, &server->addr, server->edns_p= ktsz); -- } -- if ((hash =3D hash_questions(header, nn, daemon->namebuff))) -- memcpy(new->hash, hash, HASH_SIZE); -- new->new_id =3D get_id(); -- header->id =3D htons(new->new_id); -- /* Save query for retransmission */ -- if (!(new->stash =3D blockdata_alloc((char *)header, nn))) -+ /* Free any saved query */ -+ if (forward->stash) -+ blockdata_free(forward->stash); -+ =20 -+ /* Now save reply pending receipt of key data */ -+ if (!(forward->stash =3D blockdata_alloc((char *)header, n))) - return; -- =20 -- new->stash_len =3D nn; -+ forward->stash_len =3D n; - =20 -- /* Don't resend this. */ -- daemon->srv_save =3D NULL; -+ /* Find the original query that started it all.... */ -+ for (orig =3D forward; orig->dependent; orig =3D orig->dependent); - =20 -- if (server->sfd) -- fd =3D server->sfd->fd; -+ if (--orig->work_counter =3D=3D 0 || !(new =3D get_new_frec(now, NULL, = 1))) -+ status =3D STAT_ABANDONED; - else - { -- fd =3D -1; -+ int fd; -+ struct frec *next =3D new->next; -+ *new =3D *forward; /* copy everything, then overwrite */ -+ new->next =3D next; -+ new->blocking_query =3D NULL; -+ new->sentto =3D server; -+ new->rfd4 =3D NULL; - #ifdef HAVE_IPV6 -- if (server->addr.sa.sa_family =3D=3D AF_INET6) -+ new->rfd6 =3D NULL; -+#endif -+ new->flags &=3D ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY); -+ =20 -+ new->dependent =3D forward; /* to find query awaiting new one. */ -+ forward->blocking_query =3D new; /* for garbage cleaning */ -+ /* validate routines leave name of required record in daemon->keyna= me */ -+ if (status =3D=3D STAT_NEED_KEY) -+ { -+ new->flags |=3D FREC_DNSKEY_QUERY;=20 -+ nn =3D dnssec_generate_query(header, ((char *) header) + daemon->packe= t_buff_sz, -+ daemon->keyname, forward->class, T_DNSKEY, &server->addr, server= ->edns_pktsz); -+ } -+ else=20 - { -- if (new->rfd6 || (new->rfd6 =3D allocate_rfd(AF_INET6))) -- fd =3D new->rfd6->fd; -+ new->flags |=3D FREC_DS_QUERY; -+ nn =3D dnssec_generate_query(header,((char *) header) + daemon->packet= _buff_sz, -+ daemon->keyname, forward->class, T_DS, &server->addr, server->ed= ns_pktsz); - } -+ if ((hash =3D hash_questions(header, nn, daemon->namebuff))) -+ memcpy(new->hash, hash, HASH_SIZE); -+ new->new_id =3D get_id(); -+ header->id =3D htons(new->new_id); -+ /* Save query for retransmission */ -+ new->stash =3D blockdata_alloc((char *)header, nn); -+ new->stash_len =3D nn; -+ =20 -+ /* Don't resend this. */ -+ daemon->srv_save =3D NULL; -+ =20 -+ if (server->sfd) -+ fd =3D server->sfd->fd; - else -+ { -+ fd =3D -1; -+#ifdef HAVE_IPV6 -+ if (server->addr.sa.sa_family =3D=3D AF_INET6) -+ { -+ if (new->rfd6 || (new->rfd6 =3D allocate_rfd(AF_INET6))) -+ fd =3D new->rfd6->fd; -+ } -+ else - #endif -+ { -+ if (new->rfd4 || (new->rfd4 =3D allocate_rfd(AF_INET))) -+ fd =3D new->rfd4->fd; -+ } -+ } -+ =20 -+ if (fd !=3D -1) - { -- if (new->rfd4 || (new->rfd4 =3D allocate_rfd(AF_INET))) -- fd =3D new->rfd4->fd; -+ while (retry_send(sendto(fd, (char *)header, nn, 0,=20 -+ &server->addr.sa,=20 -+ sa_len(&server->addr))));=20 -+ server->queries++; - } -- } -- =20 -- if (fd !=3D -1) -- { -- while (retry_send(sendto(fd, (char *)header, nn, 0,=20 -- &server->addr.sa,=20 -- sa_len(&server->addr))));=20 -- server->queries++; -- } -- =20 -+ } =20 - return; - } -- } - =20 -- /* 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 va= lidate -- and validate them with the new data. Note that if an answer needs mul= tiple -- 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=20 -- (FREC_DNSSEC_QUERY not set) and it validates, return it to the origin= al requestor. */ -- while (forward->dependent) -- { -+ /* Validated original answer, all done. */ -+ if (!forward->dependent) -+ break; -+ =20 -+ /* validated subsdiary query, (and cached result) -+ pop that and return to the previous query we were working on. */ - struct frec *prev =3D forward->dependent; - free_frec(forward); - forward =3D prev; - forward->blocking_query =3D NULL; /* already gone */ - blockdata_retrieve(forward->stash, forward->stash_len, (void *)heade= r); - n =3D forward->stash_len; -- =20 -- if (status =3D=3D STAT_SECURE) -- { -- if (forward->flags & FREC_DNSKEY_QUERY) -- status =3D dnssec_validate_by_ds(now, header, n, daemon->namebuff, da= emon->keyname, forward->class); -- else if (forward->flags & FREC_DS_QUERY) -- { -- status =3D dnssec_validate_ds(now, header, n, daemon->namebuff, dae= mon->keyname, forward->class); -- /* Provably no DS, everything below is insecure, even if signature= s are offered */ -- if (status =3D=3D 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=20 -- DS chain, so we don't return replies from cache missing sigs. */ -- status =3D STAT_INSECURE_DS; -- else if (status =3D=3D STAT_NO_SIG) -- { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- { -- status =3D send_check_sign(forward, now, header, n, daemon->nameb= uff, daemon->keyname);=20 -- if (status =3D=3D STAT_INSECURE) -- status =3D STAT_INSECURE_DS; -- } -- else -- status =3D STAT_INSECURE_DS; -- } -- else if (status =3D=3D STAT_NO_NS) -- status =3D STAT_BOGUS; -- } -- else if (forward->flags & FREC_CHECK_NOSIGN) -- { -- status =3D dnssec_validate_ds(now, header, n, daemon->namebuff, dae= mon->keyname, forward->class); -- if (status !=3D STAT_NEED_KEY) -- status =3D do_check_sign(forward, status, now, daemon->namebuff, daemon-= >keyname); -- } -- else -- { -- status =3D dnssec_validate_reply(now, header, n, daemon->namebuff, = daemon->keyname, &forward->class, NULL, NULL);=09 -- if (status =3D=3D STAT_NO_SIG) -- { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- status =3D send_check_sign(forward, now, header, n, daemon->namebuff= , daemon->keyname); -- else -- status =3D STAT_INSECURE; -- } -- } -- =20 -- if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEED_DS_NEG || sta= tus =3D=3D STAT_NEED_KEY) -- goto anotherkey; -- } - } -+=09 - =20 - no_cache_dnssec =3D 0; -- -- if (status =3D=3D 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=20 -- DS chain, so we don't return replies from cache missing sigs. */ -- status =3D STAT_INSECURE; -- no_cache_dnssec =3D 1; -- } - =20 - if (status =3D=3D STAT_TRUNCATED) - header->hb3 |=3D HB3_TC; -@@ -1062,7 +959,7 @@ void reply_query(int fd, int family, time_t now) - { - char *result, *domain =3D "result"; - =20 -- if (forward->work_counter =3D=3D 0) -+ if (status =3D=3D STAT_ABANDONED) - { - result =3D "ABANDONED"; - status =3D STAT_BOGUS; -@@ -1072,7 +969,7 @@ void reply_query(int fd, int family, time_t now) - =20 - if (status =3D=3D STAT_BOGUS && extract_request(header, n, daemon->n= amebuff, NULL)) - domain =3D daemon->namebuff; -- -+ =20 - log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result); - } - =20 -@@ -1415,315 +1312,49 @@ void receive_query(struct listener *listen, time_t = now) - } -=20 - #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=20 -- 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_hea= der *header, size_t plen,=20 -- char *name, char *keyname) --{ -- int status =3D dnssec_chase_cname(now, header, plen, name, keyname); -- =20 -- if (status !=3D STAT_INSECURE) -- return status; -- -- /* Store the domain we're trying to check. */ -- forward->name_start =3D strlen(name); -- forward->name_len =3D forward->name_start + 1; -- if (!(forward->orig_domain =3D blockdata_alloc(name, forward->name_len))) -- return STAT_BOGUS; -- =20 -- return do_check_sign(forward, 0, now, name, keyname); --} --=20 --/* We either have a a reply (header non-NULL, or we need to start by lookin= g in the cache */=20 --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 th= e original query. */ -- while (forward->dependent && !forward->orig_domain) -- forward =3D forward->dependent; -- -- blockdata_retrieve(forward->orig_domain, forward->name_len, name); -- =20 -- while (1) -- { -- char *p;=20 -- -- if (status =3D=3D 0) -- { -- struct crec *crecp; -- -- /* Haven't received answer, see if in cache */ -- if (!(crecp =3D 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 = */=20 -- if (!(crecp->flags & F_NEG)) -- status =3D STAT_SECURE; -- else if (crecp->flags & F_DNSSECOK) -- status =3D STAT_NO_DS; -- else -- status =3D STAT_NO_NS; -- } -- =20 -- /* Have entered non-signed part of DNS tree. */=20 -- if (status =3D=3D STAT_NO_DS) -- return forward->dependent ? STAT_INSECURE_DS : STAT_INSECURE; -- -- if (status =3D=3D STAT_BOGUS) -- return STAT_BOGUS; -- -- if (status =3D=3D STAT_NO_SIG && *keyname !=3D 0) -- { -- /* There is a validated CNAME chain that doesn't end in a DS record. Sta= rt=20 -- the search again in that domain. */ -- blockdata_free(forward->orig_domain); -- forward->name_start =3D strlen(keyname); -- forward->name_len =3D forward->name_start + 1; -- if (!(forward->orig_domain =3D blockdata_alloc(keyname, forward->name_le= n))) -- return STAT_BOGUS; -- =20 -- strcpy(name, keyname); -- status =3D 0; /* force to cache when we iterate. */ -- continue; -- } -- =20 -- /* There's a proven DS record, or we're within a zone, where there do= esn't need -- to be a DS record. Add a name and try again.=20 -- If we've already tried the whole name, then fail */ -- -- if (forward->name_start =3D=3D 0) -- return STAT_BOGUS; -- =20 -- for (p =3D &name[forward->name_start-2]; (*p !=3D '.') && (p !=3D nam= e); p--); -- =20 -- if (p !=3D name) -- p++; -- =20 -- forward->name_start =3D p - name; -- status =3D 0; /* force to cache when we iterate. */ -- } --} -- --/* Move down from the root, until we find a signed non-existance of a DS, i= n which case -- an unsigned answer is OK, or we find a signed DS, in which case there sh= ould be=20 -- a signature, and the answer is BOGUS */ --static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *head= er, size_t plen, int class, char *name,=20 -- 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 =3D tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, class, na= me, keyname, server, keycount); -- if (status =3D=3D STAT_BOGUS) -- return STAT_BOGUS; -- =20 -- if (!(packet =3D whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16))= )) -- return STAT_BOGUS; -- =20 -- payload =3D &packet[2]; -- header =3D (struct dns_header *)payload; -- length =3D (u16 *)packet; -- -- /* Stash the name away, since the buffer will be trashed when we recurse = */ -- name_len =3D strlen(name) + 1; -- name_start =3D name + name_len - 1; -- =20 -- if (!(block =3D blockdata_alloc(name, name_len))) -- { -- free(packet); -- return STAT_BOGUS; -- } -- -- while (1) -- { -- unsigned char c1, c2; -- struct crec *crecp; -- -- if (--(*keycount) =3D=3D 0) -- { -- free(packet); -- blockdata_free(block); -- return STAT_BOGUS; =20 -- } -- =20 -- while ((crecp =3D cache_find_by_name(NULL, name_start, now, F_DS))) -- { =20 -- 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; -- } -- =20 -- /* Here, either there's a secure DS, or no NS and no DS, and therefore n= o delegation. -- Add another label and continue. */ --=20 -- if (name_start =3D=3D name) -- { -- free(packet); -- blockdata_free(block); -- return STAT_BOGUS; /* run out of labels */ -- } -- =20 -- name_start -=3D 2; -- while (*name_start !=3D '.' && name_start !=3D name)=20 -- name_start--; -- if (name_start !=3D name) -- name_start++; -- } -- =20 -- /* Can't find it in the cache, have to send a query */ -- -- m =3D dnssec_generate_query(header, ((char *) header) + 65536, name_s= tart, class, T_DS, &server->addr, server->edns_pktsz); -- =20 -- *length =3D htons(m); -- =20 -- 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 =3D (c1 << 8) | c2; -- =20 -- /* Note this trashes all three name workspaces */ -- status =3D tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name= , keyname, server, keycount); -- =20 -- if (status =3D=3D STAT_NO_DS) -- { -- /* Found a secure denial of DS - delegation is indeed insecure */ -- free(packet); -- blockdata_free(block); -- return STAT_INSECURE; -- } -- =20 -- if (status =3D=3D STAT_NO_SIG && *keyname !=3D 0) -- { -- /* There is a validated CNAME chain that doesn't end in a DS record.= Start=20 -- the search again in that domain. */ -- blockdata_free(block); -- name_len =3D strlen(keyname) + 1; -- name_start =3D name + name_len - 1; -- =20 -- if (!(block =3D blockdata_alloc(keyname, name_len))) -- return STAT_BOGUS; -- =20 -- strcpy(name, keyname); -- continue; -- } -- =20 -- if (status =3D=3D STAT_BOGUS) -- { -- free(packet); -- blockdata_free(block); -- return STAT_BOGUS; -- } -- =20 -- /* Here, either there's a secure DS, or no NS and no DS, and therefore n= o delegation. -- Add another label and continue. */ -- =20 -- /* Get name we're checking back. */ -- blockdata_retrieve(block, name_len, name); -- =20 -- if (name_start =3D=3D name) -- { -- free(packet); -- blockdata_free(block); -- return STAT_BOGUS; /* run out of labels */ -- } -- =20 -- name_start -=3D 2; -- while (*name_start !=3D '.' && name_start !=3D name)=20 -- name_start--; -- if (name_start !=3D 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 *heade= r, size_t n,=20 - int class, char *name, char *keyname, struct server *server, int *key= count) - { - /* Recurse up the key heirarchy */ - int new_status; -+ unsigned char *packet =3D NULL; -+ size_t m;=20 -+ unsigned char *payload =3D NULL; -+ struct dns_header *new_header =3D NULL; -+ u16 *length =3D NULL; -+ unsigned char c1, c2; -=20 -- /* limit the amount of work we do, to avoid cycling forever on loops in t= he DNS */ -- if (--(*keycount) =3D=3D 0) -- return STAT_INSECURE; -- =20 -- if (status =3D=3D STAT_NEED_KEY) -- new_status =3D dnssec_validate_by_ds(now, header, n, name, keyname, cla= ss); -- else if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEED_DS_NEG) -+ while (1) - { -- new_status =3D dnssec_validate_ds(now, header, n, name, keyname, clas= s); -- if (status =3D=3D STAT_NEED_DS) -+ /* limit the amount of work we do, to avoid cycling forever on loops = in the DNS */ -+ if (--(*keycount) =3D=3D 0) -+ new_status =3D STAT_ABANDONED; -+ else if (status =3D=3D STAT_NEED_KEY) -+ new_status =3D dnssec_validate_by_ds(now, header, n, name, keyname, class); -+ else if (status =3D=3D STAT_NEED_DS) -+ new_status =3D dnssec_validate_ds(now, header, n, name, keyname, class); -+ else=20 -+ new_status =3D dnssec_validate_reply(now, header, n, name, keyname, &class= , option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL); -+ =20 -+ if (new_status !=3D STAT_NEED_DS && new_status !=3D 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 =3D=3D STAT_NO_DS) -- new_status =3D STAT_INSECURE_DS; -- if (new_status =3D=3D STAT_NO_SIG) -- { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- { -- new_status =3D tcp_check_for_unsigned_zone(now, header, n, class, name, = keyname, server, keycount); -- if (new_status =3D=3D STAT_INSECURE) -- new_status =3D STAT_INSECURE_DS; -- } -- else -- new_status =3D STAT_INSECURE_DS; -- } -- else if (new_status =3D=3D STAT_NO_NS) -- new_status =3D STAT_BOGUS; -+ packet =3D whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16)); -+ payload =3D &packet[2]; -+ new_header =3D (struct dns_header *)payload; -+ length =3D (u16 *)packet; - } -- } -- else if (status =3D=3D STAT_CHASE_CNAME) -- new_status =3D dnssec_chase_cname(now, header, n, name, keyname); -- else=20 -- { -- new_status =3D dnssec_validate_reply(now, header, n, name, keyname, &= class, NULL, NULL); - =20 -- if (new_status =3D=3D STAT_NO_SIG) -+ if (!packet) - { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- new_status =3D tcp_check_for_unsigned_zone(now, header, n, class, name= , keyname, server, keycount); -- else -- new_status =3D STAT_INSECURE; -+ new_status =3D 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 =3D=3D STAT_NEED_DS || new_status =3D=3D STAT_NEED_KEY) -- { -- size_t m;=20 -- unsigned char *packet =3D whine_malloc(65536 + MAXDNAME + RRFIXEDSZ += sizeof(u16)); -- unsigned char *payload =3D &packet[2]; -- struct dns_header *new_header =3D (struct dns_header *)payload; -- u16 *length =3D (u16 *)packet; -- unsigned char c1, c2; -- =20 -- if (!packet) -- return STAT_INSECURE; -- -- another_tcp_key: -+ =20 - m =3D dnssec_generate_query(new_header, ((char *) new_header) + 65536= , keyname, class,=20 - new_status =3D=3D STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, serve= r->edns_pktsz); - =20 -@@ -1733,65 +1364,22 @@ static int tcp_key_recurse(time_t now, int status, s= truct 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 =3D STAT_INSECURE; -- else - { -- m =3D (c1 << 8) | c2; -- =20 -- new_status =3D tcp_key_recurse(now, new_status, new_header, m, class, na= me, keyname, server, keycount); -- =20 -- if (new_status =3D=3D 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. */ -- =20 -- if (status =3D=3D STAT_NEED_KEY) -- new_status =3D dnssec_validate_by_ds(now, header, n, name, keyname, class= ); -- else if (status =3D=3D STAT_NEED_DS || status =3D=3D STAT_NEED_DS_NE= G) -- { -- new_status =3D dnssec_validate_ds(now, header, n, name, keyname, class); -- if (status =3D=3D STAT_NEED_DS) -- { -- if (new_status =3D=3D STAT_NO_DS) -- new_status =3D STAT_INSECURE_DS; -- else if (new_status =3D=3D STAT_NO_SIG) -- { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- { -- new_status =3D tcp_check_for_unsigned_zone(now, header, n, class, = name, keyname, server, keycount);=20 -- if (new_status =3D=3D STAT_INSECURE) -- new_status =3D STAT_INSECURE_DS; -- } -- else -- new_status =3D STAT_INSECURE_DS; -- } -- else if (new_status =3D=3D STAT_NO_NS) -- new_status =3D STAT_BOGUS; -- } -- } -- else if (status =3D=3D STAT_CHASE_CNAME) -- new_status =3D dnssec_chase_cname(now, header, n, name, keyname); -- else=20 -- { -- new_status =3D dnssec_validate_reply(now, header, n, name, keyname, &cl= ass, NULL, NULL); -- =20 -- if (new_status =3D=3D STAT_NO_SIG) -- { -- if (option_bool(OPT_DNSSEC_NO_SIGN)) -- new_status =3D tcp_check_for_unsigned_zone(now, header, n, class, name, = keyname, server, keycount); -- else -- new_status =3D STAT_INSECURE; -- } -- } -- =20 -- if (new_status =3D=3D STAT_NEED_DS || new_status =3D=3D STAT_NEED_KE= Y) -- goto another_tcp_key; -- } -+ new_status =3D STAT_ABANDONED; -+ break; - } -+ -+ m =3D (c1 << 8) | c2; - =20 -- free(packet); -+ new_status =3D tcp_key_recurse(now, new_status, new_header, m, class,= name, keyname, server, keycount); -+ =20 -+ if (new_status !=3D STAT_OK) -+ break; - } -+ -+ if (packet) -+ free(packet); -+ =20 - 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 =3D DNSSEC_WORK; /* Limit to number of DNSSEC questions, = to catch loops and avoid filling cache. */ -- int status =3D tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daem= on->namebuff, daemon->keyname, last_server, &keycount); -+ int status =3D tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->nam= ebuff, daemon->keyname, last_server, &keycount); - char *result, *domain =3D "result"; -- -- if (status =3D=3D 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=20 -- DS chain, so we don't return replies from cache missing sigs. */ -- status =3D STAT_INSECURE; -- no_cache_dnssec =3D 1; -- } - =20 -- if (keycount =3D=3D 0) -+ if (status =3D=3D STAT_ABANDONED) - { - result =3D "ABANDONED"; - status =3D STAT_BOGUS; -@@ -2179,7 +1758,6 @@ static struct frec *allocate_frec(time_t now) - f->dependent =3D NULL; - f->blocking_query =3D NULL; - f->stash =3D NULL; -- f->orig_domain =3D NULL; - #endif - daemon->frec_list =3D f; - } -@@ -2248,12 +1826,6 @@ static void free_frec(struct frec *f) - f->stash =3D NULL; - } -=20 -- if (f->orig_domain) -- { -- blockdata_free(f->orig_domain); -- f->orig_domain =3D 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 =3D f; - else=20 - { -- if (difftime(now, f->time) >=3D 4*TIMEOUT) -- { -- free_frec(f); -- target =3D f; -- } --=09 -- if (!oldest || difftime(f->time, oldest->time) <=3D 0) -- oldest =3D 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=20 -+ is freed. */ -+ if (!f->dependent) -+#endif -+ { -+ if (difftime(now, f->time) >=3D 4*TIMEOUT) -+ { -+ free_frec(f); -+ target =3D f; -+ } -+ =20 -+ =20 -+ if (!oldest || difftime(f->time, oldest->time) <=3D 0) -+ oldest =3D f; -+ } - } -=20 - if (target) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_the= m_from_cache.patch b/src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_retur= ning_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 -Date: Tue, 15 Dec 2015 12:04:40 +0000 -Subject: [PATCH] Abandon caching RRSIGs and returning them from cache. - -The list of exceptions to being able to locally answer -cached data for validated records when DNSSEC data is requested -was getting too long, so don't ever do that. This means -that the cache no longer has to hold RRSIGS and allows -us to lose lots of code. Note that cached validated -answers are still returned as long as do=3D0 ---- - src/cache.c | 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 - } - =20 - #ifdef HAVE_DNSSEC -- /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also=20 -- type-covered sensitive for RRSIG */ -- if ((flags & (F_DNSKEY | F_DS)) && -- (flags & (F_DNSKEY | F_DS)) =3D=3D (crecp->flags & (F_DNSKEY | F_DS)) && -- crecp->uid =3D=3D addr->addr.dnssec.class && -- (!((flags & (F_DS | F_DNSKEY)) =3D=3D (F_DS | F_DNSKEY)) ||=20 -- crecp->addr.sig.type_covered =3D=3D addr->addr.dnssec.type)) -+ /* Deletion has to be class-sensitive for DS and DNSKEY */ -+ if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid =3D=3D = 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 =3D new->addr.addr;; -=20 - #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 =3D new->uid; -- if ((new->flags & (F_DS | F_DNSKEY)) =3D=3D (F_DS | F_DNSKEY)) -- free_addr.addr.dnssec.type =3D new->addr.sig.type_covered; -- } -+ free_addr.addr.dnssec.class =3D new->uid; - #endif - =20 - free_avail =3D 1; /* Must be free space now. */ -@@ -653,9 +639,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char= *name, time_t now, unsi - if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp)) - { - if ((crecp->flags & F_FORWARD) &&=20 --#ifdef HAVE_DNSSEC -- (((crecp->flags & (F_DNSKEY | F_DS)) =3D=3D (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 -=20 - if (ans &&=20 - (ans->flags & F_FORWARD) && --#ifdef HAVE_DNSSEC -- (((ans->flags & (F_DNSKEY | F_DS)) =3D=3D (prot & (F_DNSKEY | F_DS)))= || (prot & F_NSIGMATCH)) && --#endif - (ans->flags & prot) && =20 - 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 =3D "C"; - #ifdef HAVE_DNSSEC -- else if ((cache->flags & (F_DS | F_DNSKEY)) =3D=3D (F_DS | F_DNSKEY)) -- t =3D "G"; /* DNSKEY and DS set -> RRISG */ - else if (cache->flags & F_DS) - t =3D "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;=20 - } ds;=20 -- 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;=20 - 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) -=20 - /* 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_heade= r *header, size_t plen, ch - { - unsigned char *psave, *p =3D (unsigned char *)(header+1); - struct crec *crecp, *recp1; -- int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_co= vered; -+ int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag; - struct blockdata *key; - struct all_addr a; -=20 -@@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_heade= r *header, size_t plen, ch -=20 - 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(); - =20 - p =3D skip_questions(header, plen); -@@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_head= er *header, size_t plen, ch - if ((key =3D blockdata_alloc((char*)p, rdlen - 4))) - { - if (!(recp1 =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSK= EY | F_DNSSECOK))) -- blockdata_free(key); -+ { -+ blockdata_free(key); -+ return STAT_BOGUS; -+ } - else - { - a.addr.keytag =3D keytag; -@@ -1169,38 +1172,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_head= er *header, size_t plen, ch - } - } - } -- else if (qtype =3D=3D T_RRSIG) -- { -- /* RRSIG, cache if covers DNSKEY RRset */ -- if (rdlen < 18) -- return STAT_BOGUS; /* bad packet */ -- =20 -- GETSHORT(type_covered, p); -- =20 -- if (type_covered =3D=3D T_DNSKEY) -- { -- a.addr.dnssec.class =3D class; -- a.addr.dnssec.type =3D type_covered; -- =20 -- algo =3D *p++; -- p +=3D 13; /* labels, orig_ttl, expiration, inception */ -- GETSHORT(keytag, p);=09 -- if ((key =3D blockdata_alloc((char*)psave, rdlen))) -- { -- if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY= | F_DS))) -- blockdata_free(key); -- else -- { -- crecp->addr.sig.keydata =3D key; -- crecp->addr.sig.keylen =3D rdlen; -- crecp->addr.sig.keytag =3D keytag; -- crecp->addr.sig.type_covered =3D type_covered; -- crecp->addr.sig.algo =3D algo; -- } -- } -- } -- } -- =20 -+ =20 - p =3D psave; - } -=20 -@@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *= header, size_t plen, char - cache_start_insert(); - =20 - a.addr.dnssec.class =3D class; -- cache_insert(name, &a, now, ttl, flags); -+ if (!cache_insert(name, &a, now, ttl, flags)) -+ return STAT_BOGUS; - =20 - cache_end_insert(); =20 - =20 -@@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct dns_hea= der *header, size_t plen, ch - /* Not done, validate now */ - if (j =3D=3D 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 =3D 0; -- -+ =20 - if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigc= nt, &rrcnt)) - return STAT_BOGUS; -=20 -@@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct dns_heade= r *header, size_t plen, ch - =20 - if (rc =3D=3D STAT_SECURE_WILDCARD) - { -- have_wildcard =3D 1; -- =20 - /* 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_heade= r *header, size_t plen, ch - return rc; - }=20 - =20 -- /* 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(); - =20 -@@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct dns_head= er *header, size_t plen, ch - }=20 - } - } -- else if (type2 =3D=3D T_RRSIG) -- { -- if (rdlen2 < 18) -- return STAT_BOGUS; /* bad packet */ -- =20 -- GETSHORT(type_covered, p2); -- =20 -- if (type_covered =3D=3D type1 &&=20 -- (type_covered =3D=3D T_A || type_covered =3D=3D T_AAAA || -- type_covered =3D=3D T_CNAME || type_covered =3D=3D T_DS ||=20 -- type_covered =3D=3D T_DNSKEY || type_covered =3D=3D T_PTR))=20 -- { -- a.addr.dnssec.type =3D type_covered; -- a.addr.dnssec.class =3D class1; -- =20 -- algo =3D *p2++; -- p2 +=3D 13; /* labels, orig_ttl, expiration, inception */ -- GETSHORT(keytag, p2); -- =20 -- /* 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 f= or -- this RRset asking for a secure answer will always be forwarded. */ -- if (!have_wildcard && (key =3D blockdata_alloc((char*)psave, rdlen2))) -- { -- if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_D= NSKEY | F_DS))) -- blockdata_free(key); -- else -- { -- crecp->addr.sig.keydata =3D key; -- crecp->addr.sig.keylen =3D rdlen2; -- crecp->addr.sig.keytag =3D keytag; -- crecp->addr.sig.type_covered =3D type_covered; -- crecp->addr.sig.algo =3D algo; -- } -- } -- } -- } -- =20 -+ - p2 =3D psave; - } - =20 -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; -=20 - /* Note: the call to cache_find_by_name is intended to find any record wh= ich matches -- ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting bot= h 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. */ -=20 -- if ((crecp =3D cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CN= AME | F_DS | F_NO_RR | F_NSIGMATCH)) && -+ if ((crecp =3D cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CN= AME |F_NO_RR)) && - (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) - return 1; - =20 -@@ -1566,9 +1564,11 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - GETSHORT(flags, pheader); - =20 - if ((sec_reqd =3D flags & 0x8000)) -- *do_bit =3D 1;/* do bit */=20 -+ { -+ *do_bit =3D 1;/* do bit */=20 -+ *ad_reqd =3D 1; -+ } -=20 -- *ad_reqd =3D 1; - dryrun =3D 1; - } -=20 -@@ -1636,98 +1636,6 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - } - } -=20 --#ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID) && (qtype =3D=3D T_DNSKEY || qtype = =3D=3D T_DS)) -- { -- int gotone =3D 0; -- struct blockdata *keydata; -- -- /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */ -- if (sec_reqd) -- { -- crecp =3D NULL; -- while ((crecp =3D cache_find_by_name(crecp, name, now, F_DNSKEY | F_= DS))) -- if (crecp->uid =3D=3D qclass && crecp->addr.sig.type_covered =3D=3D qtype) -- break; -- } -- =20 -- if (!sec_reqd || crecp) -- { -- if (qtype =3D=3D T_DS) -- { -- crecp =3D NULL; -- while ((crecp =3D cache_find_by_name(crecp, name, now, F_DS))) -- if (crecp->uid =3D=3D qclass) -- { -- gotone =3D 1;=20 -- if (!dryrun) -- { -- if (crecp->flags & F_NEG) -- { -- if (crecp->flags & F_NXDOMAIN) -- nxdomain =3D 1; -- log_query(F_UPSTREAM, name, NULL, "no DS");=09 -- } -- else if ((keydata =3D blockdata_retrieve(crecp->addr.ds.keydata, cre= cp->addr.ds.keylen, NULL))) -- { =20 -- struct all_addr a; -- a.addr.keytag =3D 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,=20 -- crec_ttl(crecp, now), &nameoffset, -- T_DS, qclass, "sbbt",=20 -- crecp->addr.ds.keytag, crecp->addr.ds.algo,=20 -- crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata)) -- anscount++; -- =09 -- }=20 -- } -- } -- } -- else /* DNSKEY */ -- { -- crecp =3D NULL; -- while ((crecp =3D cache_find_by_name(crecp, name, now, F_DNSKEY))) -- if (crecp->uid =3D=3D qclass) -- { -- gotone =3D 1; -- if (!dryrun && (keydata =3D blockdata_retrieve(crecp->addr.key.keydata, = crecp->addr.key.keylen, NULL))) -- { =20 -- struct all_addr a; -- a.addr.keytag =3D crecp->addr.key.keytag; -- log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY ke= ytag %u"); -- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,=20 -- crec_ttl(crecp, now), &nameoffset, -- T_DNSKEY, qclass, "sbbt",=20 -- crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.k= eylen, keydata)) -- anscount++; -- } -- } -- } -- } -- =20 -- /* Now do RRSIGs */ -- if (gotone) -- { -- ans =3D 1; -- auth =3D 0; -- if (!dryrun && sec_reqd) -- { -- crecp =3D NULL; -- while ((crecp =3D cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)= )) -- if (crecp->uid =3D=3D qclass && crecp->addr.sig.type_covered =3D=3D q= type && -- (keydata =3D blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig= .keylen, NULL))) -- { -- add_resource_record(header, limit, &trunc, nameoffset, &ansp,=20 -- crec_ttl(crecp, now), &nameoffset, -- T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata); -- anscount++; -- } -- } -- } -- } --#endif =20 -- =20 - if (qclass =3D=3D 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 =3D=3D qtype || qtype =3D=3D T_ANY) && hostname_isequal(= name, t->name)) - { - ans =3D 1; -+ sec_data =3D 0; - if (!dryrun) - { - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); -@@ -1792,6 +1701,7 @@ size_t answer_request(struct dns_header *header, char = *limit, size_t qlen, - =20 - if (intr) - { -+ sec_data =3D 0; - ans =3D 1; - if (!dryrun) - { -@@ -1805,6 +1715,7 @@ size_t answer_request(struct dns_header *header, char = *limit, size_t qlen, - else if (ptr) - { - ans =3D 1; -+ sec_data =3D 0; - if (!dryrun) - { - log_query(F_CONFIG | F_RRNAME, name, NULL, ""); -@@ -1819,38 +1730,8 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - } - else if ((crecp =3D 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) && (c= recp->flags & F_DNSSECOK))) -- crecp =3D NULL; --#ifdef HAVE_DNSSEC -- else if (crecp->flags & F_DNSSECOK) -- { -- int gotsig =3D 0; -- struct crec *rr_crec =3D NULL; -- -- while ((rr_crec =3D cache_find_by_name(rr_crec, name, now, F_DS | F_DN= SKEY))) -- { -- if (rr_crec->addr.sig.type_covered =3D=3D T_PTR && rr_crec->uid = =3D=3D C_IN) -- { -- char *sigdata =3D blockdata_retrieve(rr_crec->addr.sig.keydata, rr_cr= ec->addr.sig.keylen, NULL); -- gotsig =3D 1; -- =20 -- if (!dryrun &&=20 -- add_resource_record(header, limit, &trunc, nameoffset, &ansp,=20 -- rr_crec->ttd - now, &nameoffset, -- T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata)) -- anscount++; -- } -- }=20 -- =20 -- if (!gotsig) -- crecp =3D NULL; -- } --#endif -- } -- -- if (crecp) -+ /* Don't use cache when DNSSEC data required. */ -+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(cr= ecp->flags & F_DNSSECOK)) - { - do=20 - {=20 -@@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header *header, cha= r *limit, size_t qlen, - =20 - if (!(crecp->flags & F_DNSSECOK)) - sec_data =3D 0; -- =20 -+ =20 -+ ans =3D 1; -+ =20 - if (crecp->flags & F_NEG) - { -- ans =3D 1; - auth =3D 0; - if (crecp->flags & F_NXDOMAIN) - nxdomain =3D 1; - if (!dryrun) - log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL); - } -- else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bo= ol(OPT_DNSSEC_VALID)) -+ else - { -- ans =3D 1; - if (!(crecp->flags & (F_HOSTS | F_DHCP))) - auth =3D 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 =3D 1; -+ sec_data =3D 0; - if (!dryrun) - { - log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);=20 -@@ -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 =3D 1; -+ sec_data =3D 0; - nxdomain =3D 1; - if (!dryrun) - log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,=20 -@@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header *header, char = *limit, size_t qlen, - if (i =3D=3D 4) - { - ans =3D 1; -+ sec_data =3D 0; - if (!dryrun) - { - addr.addr.addr4.s_addr =3D htonl(a); -@@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header *header, char = *limit, size_t qlen, - continue; - #endif=09 - ans =3D 1;=09 -+ sec_data =3D 0; - if (!dryrun) - { - gotit =3D 1; -@@ -2032,48 +1917,8 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - crecp =3D save; - } -=20 -- /* 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 neg= ative, -- 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) && (c= recp->flags & F_DNSSECOK))) -- crecp =3D 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 =3D NULL; -- int sigtype =3D type; -- /* The signature may have expired even though the data is still in cac= he,=20 -- forward instead of answering from cache if so. */ -- int gotsig =3D 0; -- =20 -- if (crecp->flags & F_CNAME) -- sigtype =3D T_CNAME; -- =20 -- while ((rr_crec =3D cache_find_by_name(rr_crec, name, now, F_DS | F_DN= SKEY))) -- { -- if (rr_crec->addr.sig.type_covered =3D=3D sigtype && rr_crec->uid = =3D=3D C_IN) -- { -- char *sigdata =3D blockdata_retrieve(rr_crec->addr.sig.keydata, rr_cr= ec->addr.sig.keylen, NULL); -- gotsig =3D 1; -- =20 -- if (!dryrun &&=20 -- add_resource_record(header, limit, &trunc, nameoffset, &ansp,=20 -- rr_crec->ttd - now, &nameoffset, -- T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata)) -- anscount++; -- } -- } -- =20 -- if (!gotsig) -- crecp =3D NULL; -- } --#endif -- } =20 -- -- if (crecp) -+ /* If the client asked for DNSSEC don't use cached data. */ -+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(cr= ecp->flags & F_DNSSECOK)) - do - {=20 - /* don't answer wildcard queries with data not from /etc/hosts ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_m= ore_logical_place.patch b/src/patches/dnsmasq/018-Move_code_which_caches_DS_r= ecords_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_log= ical_place.patch +++ /dev/null @@ -1,269 +0,0 @@ -From d64c81fff7faf4392b688223ef3a617c5c07e7dc Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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_head= er *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 =3D (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; -=20 - if (ntohs(header->qdcount) !=3D 1 || - !(p =3D skip_name(p, header, plen, 4))) -@@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct dns_heade= r *header, size_t plen, char - GETSHORT(qclass, p); -=20 - if (qtype !=3D T_DS || qclass !=3D class) -- val =3D STAT_BOGUS; -+ rc =3D STAT_BOGUS; - else -- val =3D dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0= , &neganswer, &nons); -+ rc =3D dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0,= &neganswer, &nons); - /* Note dnssec_validate_reply() will have cached positive answers */ - =20 -- if (val =3D=3D STAT_INSECURE) -- val =3D STAT_BOGUS; -- -+ if (rc =3D=3D STAT_INSECURE) -+ rc =3D STAT_BOGUS; -+=20 - p =3D (unsigned char *)(header+1); - extract_name(header, plen, &p, name, 1, 4); - p +=3D 4; /* qtype, qclass */ - =20 -- if (!(p =3D skip_section(p, ntohs(header->ancount), header, plen))) -- val =3D STAT_BOGUS; -- =20 - /* 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 =3D=3D STAT_BOGUS || (val =3D=3D STAT_NEED_KEY && hostname_isequa= l(name, keyname))) -+ if (rc =3D=3D STAT_BOGUS || (rc =3D=3D STAT_NEED_KEY && hostname_isequal(= name, keyname))) - { - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS"); - return STAT_BOGUS; - } - =20 -- if (val !=3D STAT_SECURE) -- return val; -- -- /* By here, the answer is proved secure, and a positive answer has been c= ached. */ -- if (neganswer) -+ if (rc !=3D STAT_SECURE) -+ return rc; -+ =20 -+ if (!neganswer) - { -- int rdlen, flags =3D F_FORWARD | F_DS | F_NEG | F_DNSSECOK; -- unsigned long ttl, minttl =3D ULONG_MAX; -- struct all_addr a; -+ cache_start_insert(); -+ =20 -+ for (i =3D 0; i < ntohs(header->ancount); i++) -+ { -+ if (!(rc =3D extract_name(header, plen, &p, name, 0, 10))) -+ return STAT_BOGUS; /* bad packet */ -+ =20 -+ GETSHORT(atype, p); -+ GETSHORT(aclass, p); -+ GETLONG(ttl, p); -+ GETSHORT(rdlen, p); -+ =20 -+ if (!CHECK_LEN(header, p, plen, rdlen)) -+ return STAT_BOGUS; /* bad packet */ -+ =20 -+ if (aclass =3D=3D class && atype =3D=3D T_DS && rc =3D=3D 1) -+ {=20 -+ int algo, digest, keytag; -+ unsigned char *psave =3D p; -+ struct blockdata *key; -+ struct crec *crecp; -=20 -+ if (rdlen < 4) -+ return STAT_BOGUS; /* bad packet */ -+ =20 -+ GETSHORT(keytag, p); -+ algo =3D *p++; -+ digest =3D *p++; -+ =20 -+ /* Cache needs to known class for DNSSEC stuff */ -+ a.addr.dnssec.class =3D class; -+ =20 -+ if ((key =3D blockdata_alloc((char*)p, rdlen - 4))) -+ { -+ if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_D= NSSECOK))) -+ { -+ blockdata_free(key); -+ return STAT_BOGUS; -+ } -+ else -+ { -+ a.addr.keytag =3D keytag; -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %= u"); -+ crecp->addr.ds.digest =3D digest; -+ crecp->addr.ds.keydata =3D key; -+ crecp->addr.ds.algo =3D algo; -+ crecp->addr.ds.keytag =3D keytag; -+ crecp->addr.ds.keylen =3D rdlen - 4;=20 -+ }=20 -+ } -+ =20 -+ p =3D psave; -+ =20 -+ if (!ADD_RDLEN(header, p, plen, rdlen)) -+ return STAT_BOGUS; /* bad packet */ -+ } -+ =20 -+ cache_end_insert(); -+ } -+ } -+ else -+ { -+ int flags =3D F_FORWARD | F_DS | F_NEG | F_DNSSECOK; -+ unsigned long minttl =3D ULONG_MAX; -+ =20 -+ if (!(p =3D skip_section(p, ntohs(header->ancount), header, plen))) -+ return STAT_BOGUS; -+ =20 - if (RCODE(header) =3D=3D NXDOMAIN) - flags |=3D F_NXDOMAIN; - =20 -@@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct dns_header= *header, size_t plen, char - if (!(p =3D skip_name(p, header, plen, 0))) - return STAT_BOGUS; - =20 -- GETSHORT(qtype, p);=20 -- GETSHORT(qclass, p); -+ GETSHORT(atype, p);=20 -+ GETSHORT(aclass, p); - GETLONG(ttl, p); - GETSHORT(rdlen, p); -- -+ =20 - if (!CHECK_LEN(header, p, plen, rdlen)) - return STAT_BOGUS; /* bad packet */ -- =20 -- if (qclass !=3D class || qtype !=3D T_SOA) -+ =20 -+ if (aclass !=3D class || atype !=3D T_SOA) - { - p +=3D rdlen; - continue; - } -- =20 -+ =20 - if (ttl < minttl) - minttl =3D ttl; - =20 -@@ -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"); - } - } -- -+ =20 - return STAT_OK; - } -=20 -@@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct dns_head= er *header, size_t plen, ch - /* Not done, validate now */ - if (j =3D=3D 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; - =20 - if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigc= nt, &rrcnt)) -@@ -2032,6 +2091,7 @@ int dnssec_validate_reply(time_t now, struct dns_heade= r *header, size_t plen, ch - Can't overwrite name here. */ - strcpy(daemon->workspacename, keyname); - rc =3D zone_status(daemon->workspacename, class1, keyname, now); -+ - if (rc !=3D STAT_SECURE) - { - /* Zone is insecure, don't need to validate RRset */ -@@ -2088,65 +2148,6 @@ int dnssec_validate_reply(time_t now, struct dns_head= er *header, size_t plen, ch - if (rc =3D=3D STAT_BOGUS) - return rc; - }=20 -- =20 -- /* 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(); -- =20 -- for (p2 =3D ans_start, j =3D 0; j < ntohs(header->ancount); j++) -- { -- if (!(rc =3D extract_name(header, plen, &p2, name, 0, 10))) -- return STAT_BOGUS; /* bad packet */ -- =20 -- GETSHORT(type2, p2); -- GETSHORT(class2, p2); -- GETLONG(ttl, p2); -- GETSHORT(rdlen2, p2); -- =20 -- if (!CHECK_LEN(header, p2, plen, rdlen2)) -- return STAT_BOGUS; /* bad packet */ -- =20 -- if (class2 =3D=3D class1 && rc =3D=3D 1) -- {=20 -- psave =3D p2; -- =20 -- if (type1 =3D=3D T_DS && type2 =3D=3D T_DS) -- { -- if (rdlen2 < 4) -- return STAT_BOGUS; /* bad packet */ -- =20 -- GETSHORT(keytag, p2); -- algo =3D *p2++; -- digest =3D *p2++; -- =20 -- /* Cache needs to known class for DNSSEC stuff */ -- a.addr.dnssec.class =3D class2; -- =20 -- if ((key =3D blockdata_alloc((char*)p2, rdlen2 - 4))) -- { -- if (!(crecp =3D cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F= _DNSSECOK))) -- blockdata_free(key); -- else -- { -- a.addr.keytag =3D keytag; -- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag= %u"); -- crecp->addr.ds.digest =3D digest; -- crecp->addr.ds.keydata =3D key; -- crecp->addr.ds.algo =3D algo; -- crecp->addr.ds.keytag =3D keytag; -- crecp->addr.ds.keylen =3D rdlen2 - 4;=20 -- }=20 -- } -- } -- -- p2 =3D psave; -- } -- =20 -- if (!ADD_RDLEN(header, p2, plen, rdlen2)) -- return STAT_BOGUS; /* bad packet */ -- } -- =20 -- cache_end_insert(); - } - } - } ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_wit= h_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 -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 =3D cache.o rfc1035.o util.o option.o forward.o netwo= rk.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 -=20 - hdrs =3D 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 :=3D 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 -=20 - LOCAL_MODULE :=3D dnsmasq -=20 -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); -=20 -+/* 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, u= nsigned long date_end) - && serial_compare_32(curtime, date_end) =3D=3D SERIAL_LT; - } -=20 --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. -- */ -- =20 -- static u16 rr_desc[] =3D=20 -- {=20 -- T_NS, 0, -1,=20 -- 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 */ -- };=20 -- =20 -- u16 *p =3D rr_desc; -- =20 -- while (*p !=3D type && *p !=3D 0) -- while (*p++ !=3D (u16)-1); -- -- return p+1; --} -- - /* Return bytes of canonicalised rdata, when the return value is zero, the = remaining=20 - 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, - } - } -=20 --static int expand_workspace(unsigned char ***wkspc, int *szp, int new) --{ -- unsigned char **p; -- int old =3D *szp; -- -- if (old >=3D new+1) -- return 1; -- -- if (new >=3D 100) -- return 0; -- -- new +=3D 5; -- =20 -- if (!(p =3D whine_malloc(new * sizeof(unsigned char **)))) -- return 0; =20 -- =20 -- if (old !=3D 0 && *wkspc) -- { -- memcpy(p, *wkspc, old * sizeof(unsigned char **)); -- free(*wkspc); -- } -- =20 -- *wkspc =3D p; -- *szp =3D new; -- -- return 1; --} -- - /* Bubble sort the RRset into the canonical order.=20 - Note that the byte-streams from two RRs may get unsynced: consider=20 - 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 =3D NULL; - int algo, labels, orig_ttl, key_tag; -- u16 *rr_desc =3D get_desc(type); -+ u16 *rr_desc =3D rrfilter_desc(type); - =20 - if (wildcard_out) - *wildcard_out =3D NULL; -@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct dns_header *head= er, char *end, char *name, i - return ret; - } -=20 --/* Go through a domain name, find "pointers" and fix them up based on how m= any bytes -- we've chopped out of the packet, or check they don't point into an elide= d part. */ --static int check_name(unsigned char **namep, struct dns_header *header, siz= e_t plen, int fixup, unsigned char **rrs, int rr_count) --{ -- unsigned char *ansp =3D *namep; -- -- while(1) -- { -- unsigned int label_type; -- =20 -- if (!CHECK_LEN(header, ansp, plen, 1)) -- return 0; -- =20 -- label_type =3D (*ansp) & 0xc0; -- -- if (label_type =3D=3D 0xc0) -- { -- /* pointer for compression. */ -- unsigned int offset; -- int i; -- unsigned char *p; -- =20 -- if (!CHECK_LEN(header, ansp, plen, 2)) -- return 0; -- -- offset =3D ((*ansp++) & 0x3f) << 8; -- offset |=3D *ansp++; -- -- p =3D offset + (unsigned char *)header; -- =20 -- for (i =3D 0; i < rr_count; i++) -- if (p < rrs[i]) -- break; -- else -- if (i & 1) -- offset -=3D 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 -=3D 2; -- *ansp++ =3D (offset >> 8) | 0xc0; -- *ansp++ =3D offset & 0xff; -- } -- break; -- } -- else if (label_type =3D=3D 0x80) -- return 0; /* reserved */ -- else if (label_type =3D=3D 0x40) -- { -- /* Extended label type */ -- unsigned int count; -- =20 -- if (!CHECK_LEN(header, ansp, plen, 2)) -- return 0; -- =20 -- if (((*ansp++) & 0x3f) !=3D 1) -- return 0; /* we only understand bitstrings */ -- =20 -- count =3D *(ansp++); /* Bits in bitstring */ -- =20 -- if (count =3D=3D 0) /* count =3D=3D 0 means 256 bits */ -- ansp +=3D 32; -- else -- ansp +=3D ((count-1)>>3)+1; -- } -- else -- { /* label type =3D=3D 0 Bottom six bits is length */ -- unsigned int len =3D (*ansp++) & 0x3f; -- =20 -- if (!ADD_RDLEN(header, ansp, plen, len)) -- return 0; -- -- if (len =3D=3D 0) -- break; /* zero length label marks the end. */ -- } -- } -- -- *namep =3D 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 pl= en, int fixup, unsigned char **rrs, int rr_count) --{ -- int i, type, class, rdlen; -- unsigned char *pp; -- =20 -- for (i =3D 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs= (header->arcount); i++) -- { -- pp =3D p; -- -- if (!(p =3D skip_name(p, header, plen, 10))) -- return 0; -- =20 -- GETSHORT(type, p);=20 -- GETSHORT(class, p); -- p +=3D 4; /* TTL */ -- GETSHORT(rdlen, p); -- -- if (type !=3D T_NSEC && type !=3D T_NSEC3 && type !=3D T_RRSIG) -- { -- /* fixup name of RR */ -- if (!check_name(&pp, header, plen, fixup, rrs, rr_count)) -- return 0; -- =20 -- if (class =3D=3D C_IN) -- { -- u16 *d; --=20 -- for (pp =3D p, d =3D get_desc(type); *d !=3D (u16)-1; d++) -- { -- if (*d !=3D 0) -- pp +=3D *d; -- else if (!check_name(&pp, header, plen, fixup, rrs, rr_count)) -- return 0; -- } -- } -- } -- =20 -- if (!ADD_RDLEN(header, p, plen, rdlen)) -- return 0; -- } -- =20 -- return 1; --} --=09 -- --size_t filter_rrsigs(struct dns_header *header, size_t plen) --{ -- static unsigned char **rrs; -- static int rr_sz =3D 0; -- =20 -- unsigned char *p =3D (unsigned char *)(header+1); -- int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar; -- -- if (ntohs(header->qdcount) !=3D 1 || -- !(p =3D skip_name(p, header, plen, 4))) -- return plen; -- =20 -- 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 =3D 0, chop_ns =3D 0, chop_an =3D 0, chop_ar =3D 0, i =3D 0= ;=20 -- i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->= arcount); -- i++) -- { -- unsigned char *pstart =3D p; -- int type, class; -- -- if (!(p =3D skip_name(p, header, plen, 10))) -- return plen; -- =20 -- GETSHORT(type, p);=20 -- GETSHORT(class, p); -- p +=3D 4; /* TTL */ -- GETSHORT(rdlen, p); -- =20 -- if ((type =3D=3D T_NSEC || type =3D=3D T_NSEC3 || type =3D=3D T_RRSIG= ) &&=20 -- (type !=3D qtype || class !=3D qclass)) -- { -- if (!expand_workspace(&rrs, &rr_sz, rr_found + 1)) -- return plen;=20 -- =20 -- rrs[rr_found++] =3D pstart; -- -- if (!ADD_RDLEN(header, p, plen, rdlen)) -- return plen; -- =20 -- rrs[rr_found++] =3D p; -- =20 -- 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; -- } -- =20 -- /* Nothing to do. */ -- if (rr_found =3D=3D 0) -- return plen; -- -- /* Second pass, look for pointers in names in the records we're keeping a= nd 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 =3D (unsigned char *)(header+1); -- =20 -- /* question first */ -- if (!check_name(&p, header, plen, 0, rrs, rr_found)) -- return plen; -- p +=3D 4; /* qclass, qtype */ -- =20 -- /* Now answers and NS */ -- if (!check_rrs(p, header, plen, 0, rrs, rr_found)) -- return plen; -- =20 -- /* Third pass, elide records */ -- for (p =3D rrs[0], i =3D 1; i < rr_found; i +=3D 2) -- { -- unsigned char *start =3D rrs[i]; -- unsigned char *end =3D (i !=3D rr_found - 1) ? rrs[i+1] : ((unsigned = char *)(header+1)) + plen; -- =20 -- memmove(p, start, end-start); -- p +=3D end-start; -- } -- =20 -- plen =3D p - (unsigned char *)header; -- header->ancount =3D htons(ntohs(header->ancount) - chop_an); -- header->nscount =3D htons(ntohs(header->nscount) - chop_ns); -- header->arcount =3D htons(ntohs(header->arcount) - chop_ar); -- -- /* Fourth pass, fix up pointers in the remaining records */ -- p =3D (unsigned char *)(header+1); -- =20 -- check_name(&p, header, plen, 1, rrs, rr_found); -- p +=3D 4; /* qclass, qtype */ -- =20 -- check_rrs(p, header, plen, 1, rrs, rr_found); -- =20 -- 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, t= ime_t now, struct server -=20 - /* If the requestor didn't set the DO bit, don't return DNSSEC info. */ - if (!do_bit) -- n =3D filter_rrsigs(header, n); -+ n =3D rrfilter(header, n, 1); - #endif -=20 - /* 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. -+=20 -+ 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. -+ =20 -+ You should have received a copy of the GNU General Public License -+ along with this program. If not, see . -+*/ -+ -+/* Code to safely remove RRs from an DNS answer */=20 -+ -+#include "dnsmasq.h" -+ -+/* Go through a domain name, find "pointers" and fix them up based on how m= any bytes -+ we've chopped out of the packet, or check they don't point into an elide= d part. */ -+static int check_name(unsigned char **namep, struct dns_header *header, siz= e_t plen, int fixup, unsigned char **rrs, int rr_count) -+{ -+ unsigned char *ansp =3D *namep; -+ -+ while(1) -+ { -+ unsigned int label_type; -+ =20 -+ if (!CHECK_LEN(header, ansp, plen, 1)) -+ return 0; -+ =20 -+ label_type =3D (*ansp) & 0xc0; -+ -+ if (label_type =3D=3D 0xc0) -+ { -+ /* pointer for compression. */ -+ unsigned int offset; -+ int i; -+ unsigned char *p; -+ =20 -+ if (!CHECK_LEN(header, ansp, plen, 2)) -+ return 0; -+ -+ offset =3D ((*ansp++) & 0x3f) << 8; -+ offset |=3D *ansp++; -+ -+ p =3D offset + (unsigned char *)header; -+ =20 -+ for (i =3D 0; i < rr_count; i++) -+ if (p < rrs[i]) -+ break; -+ else -+ if (i & 1) -+ offset -=3D 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 -=3D 2; -+ *ansp++ =3D (offset >> 8) | 0xc0; -+ *ansp++ =3D offset & 0xff; -+ } -+ break; -+ } -+ else if (label_type =3D=3D 0x80) -+ return 0; /* reserved */ -+ else if (label_type =3D=3D 0x40) -+ { -+ /* Extended label type */ -+ unsigned int count; -+ =20 -+ if (!CHECK_LEN(header, ansp, plen, 2)) -+ return 0; -+ =20 -+ if (((*ansp++) & 0x3f) !=3D 1) -+ return 0; /* we only understand bitstrings */ -+ =20 -+ count =3D *(ansp++); /* Bits in bitstring */ -+ =20 -+ if (count =3D=3D 0) /* count =3D=3D 0 means 256 bits */ -+ ansp +=3D 32; -+ else -+ ansp +=3D ((count-1)>>3)+1; -+ } -+ else -+ { /* label type =3D=3D 0 Bottom six bits is length */ -+ unsigned int len =3D (*ansp++) & 0x3f; -+ =20 -+ if (!ADD_RDLEN(header, ansp, plen, len)) -+ return 0; -+ -+ if (len =3D=3D 0) -+ break; /* zero length label marks the end. */ -+ } -+ } -+ -+ *namep =3D 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 pl= en, int fixup, unsigned char **rrs, int rr_count) -+{ -+ int i, j, type, class, rdlen; -+ unsigned char *pp; -+ =20 -+ for (i =3D 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs= (header->arcount); i++) -+ { -+ pp =3D p; -+ -+ if (!(p =3D skip_name(p, header, plen, 10))) -+ return 0; -+ =20 -+ GETSHORT(type, p);=20 -+ GETSHORT(class, p); -+ p +=3D 4; /* TTL */ -+ GETSHORT(rdlen, p); -+ -+ /* If this RR is to be elided, don't fix up its contents */ -+ for (j =3D 0; j < rr_count; j +=3D 2) -+ if (rrs[j] =3D=3D pp) -+ break; -+ -+ if (j >=3D rr_count) -+ { -+ /* fixup name of RR */ -+ if (!check_name(&pp, header, plen, fixup, rrs, rr_count)) -+ return 0; -+ =20 -+ if (class =3D=3D C_IN) -+ { -+ u16 *d; -+=20 -+ for (pp =3D p, d =3D rrfilter_desc(type); *d !=3D (u16)-1; d++) -+ { -+ if (*d !=3D 0) -+ pp +=3D *d; -+ else if (!check_name(&pp, header, plen, fixup, rrs, rr_count)) -+ return 0; -+ } -+ } -+ } -+ =20 -+ if (!ADD_RDLEN(header, p, plen, rdlen)) -+ return 0; -+ } -+ =20 -+ return 1; -+} -+=09 -+ -+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */ -+size_t rrfilter(struct dns_header *header, size_t plen, int mode) -+{ -+ static unsigned char **rrs; -+ static int rr_sz =3D 0; -+ -+ unsigned char *p =3D (unsigned char *)(header+1); -+ int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar; -+ -+ if (ntohs(header->qdcount) !=3D 1 || -+ !(p =3D skip_name(p, header, plen, 4))) -+ return plen; -+ =20 -+ 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 =3D 0, chop_ns =3D 0, chop_an =3D 0, chop_ar =3D 0, i =3D 0= ;=20 -+ i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->= arcount); -+ i++) -+ { -+ unsigned char *pstart =3D p; -+ int type, class; -+ -+ if (!(p =3D skip_name(p, header, plen, 10))) -+ return plen; -+ =20 -+ GETSHORT(type, p);=20 -+ GETSHORT(class, p); -+ p +=3D 4; /* TTL */ -+ GETSHORT(rdlen, p); -+ =20 -+ if (!ADD_RDLEN(header, p, plen, rdlen)) -+ return plen; -+ -+ /* Don't remove the answer. */ -+ if (i < ntohs(header->ancount) && type =3D=3D qtype && class =3D=3D q= class) -+ continue; -+ =20 -+ if (mode =3D=3D 0) /* EDNS */ -+ { -+ /* EDNS mode, remove T_OPT from additional section only */ -+ if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type !=3D T= _OPT) -+ continue; -+ } -+ else if (type !=3D T_NSEC && type !=3D T_NSEC3 && type !=3D T_RRSIG) -+ /* DNSSEC mode, remove SIGs and NSECs from all three sections. */ -+ continue; -+ =20 -+ =20 -+ if (!expand_workspace(&rrs, &rr_sz, rr_found + 1)) -+ return plen;=20 -+ =20 -+ rrs[rr_found++] =3D pstart; -+ rrs[rr_found++] =3D p; -+ =20 -+ if (i < ntohs(header->ancount)) -+ chop_an++; -+ else if (i < (ntohs(header->nscount) + ntohs(header->ancount))) -+ chop_ns++; -+ else -+ chop_ar++; -+ } -+ =20 -+ /* Nothing to do. */ -+ if (rr_found =3D=3D 0) -+ return plen; -+ -+ /* Second pass, look for pointers in names in the records we're keeping a= nd 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 =3D (unsigned char *)(header+1); -+ =20 -+ /* question first */ -+ if (!check_name(&p, header, plen, 0, rrs, rr_found)) -+ return plen; -+ p +=3D 4; /* qclass, qtype */ -+ =20 -+ /* Now answers and NS */ -+ if (!check_rrs(p, header, plen, 0, rrs, rr_found)) -+ return plen; -+ =20 -+ /* Third pass, elide records */ -+ for (p =3D rrs[0], i =3D 1; i < rr_found; i +=3D 2) -+ { -+ unsigned char *start =3D rrs[i]; -+ unsigned char *end =3D (i !=3D rr_found - 1) ? rrs[i+1] : ((unsigned = char *)(header+1)) + plen; -+ =20 -+ memmove(p, start, end-start); -+ p +=3D end-start; -+ } -+ =20 -+ plen =3D p - (unsigned char *)header; -+ header->ancount =3D htons(ntohs(header->ancount) - chop_an); -+ header->nscount =3D htons(ntohs(header->nscount) - chop_ns); -+ header->arcount =3D htons(ntohs(header->arcount) - chop_ar); -+ -+ /* Fourth pass, fix up pointers in the remaining records */ -+ p =3D (unsigned char *)(header+1); -+ =20 -+ check_name(&p, header, plen, 1, rrs, rr_found); -+ p +=3D 4; /* qclass, qtype */ -+ =20 -+ check_rrs(p, header, plen, 1, rrs, rr_found); -+ =20 -+ 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. -+ */ -+ =20 -+ static u16 rr_desc[] =3D=20 -+ {=20 -+ T_NS, 0, -1,=20 -+ 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 */ -+ };=20 -+ =20 -+ u16 *p =3D rr_desc; -+ =20 -+ while (*p !=3D type && *p !=3D 0) -+ while (*p++ !=3D (u16)-1); -+ -+ return p+1; -+} -+ -+int expand_workspace(unsigned char ***wkspc, int *szp, int new) -+{ -+ unsigned char **p; -+ int old =3D *szp; -+ -+ if (old >=3D new+1) -+ return 1; -+ -+ if (new >=3D 100) -+ return 0; -+ -+ new +=3D 5; -+ =20 -+ if (!(p =3D whine_malloc(new * sizeof(unsigned char **)))) -+ return 0; =20 -+ =20 -+ if (old !=3D 0 && *wkspc) -+ { -+ memcpy(p, *wkspc, old * sizeof(unsigned char **)); -+ free(*wkspc); -+ } -+ =20 -+ *wkspc =3D p; -+ *szp =3D new; -+ -+ return 1; -+} ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch b/src/patc= hes/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 -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, si= ze_t plen, int class, int - STAT_NEED_KEY need DNSKEY to complete validation (name is returned in ke= yname) - STAT_NEED_DS need DS to complete validation (name is returned in keynam= e) -=20 -- if key is non-NULL, use that key, which has the algo and tag given in th= e params of those names, -+ If key is non-NULL, use that key, which has the algo and tag given in th= e params of those names, - otherwise find the key in the cache. -=20 -- name is unchanged on exit. keyname is used as workspace and trashed. -+ Name is unchanged on exit. keyname is used as workspace and trashed. -=20 - 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; - } - =20 -+ - /* 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_head= er *header, size_t plen, uns -=20 - /* 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. -- =20 -+ 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 =3D strlen(name); -+ int secure_ds, name_start =3D strlen(name); - struct crec *crecp; - char *p; - =20 -@@ -1850,27 +1851,52 @@ static int zone_status(char *name, int class, char *= keyname, time_t now) - if (!(crecp =3D cache_find_by_name(NULL, keyname, now, F_DS))) - return STAT_NEED_DS; - else -- do=20 -- { -- if (crecp->uid =3D=3D (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 he= re, -- 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 wh= en -- we prove that we're at a zone cut AND there's no DS record. -- */ =20 -- 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(crec= p->addr.ds.algo)) -- return STAT_INSECURE; /* algo we can't use - insecure */ -- } -- } -- while ((crecp =3D cache_find_by_name(crecp, keyname, now, F_DS))); -- =20 -+ { -+ secure_ds =3D 0; -+ =20 -+ do=20 -+ { -+ if (crecp->uid =3D=3D (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 st= art -+ 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. -+ */ =20 -+ 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(cr= ecp->addr.ds.algo)) -+ return STAT_INSECURE; /* algo we can't use - insecure */ -+ else -+ secure_ds =3D 1; -+ } -+ } -+ while ((crecp =3D 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 zo= ne, so we believe -+ that RRset is good. Furthermore the DNSKEY whose hash is proved by th= e DS record is -+ one we can use. However the DNSKEY RRset may contain more than one ke= y and -+ one of the other keys may use an algorithm we don't support. If that'= s=20 -+ the case the zone is insecure for us. */ -+ =20 -+ if (!(crecp =3D cache_find_by_name(NULL, keyname, now, F_DNSKEY))) -+ return STAT_NEED_KEY; -+ -+ do=20 -+ { -+ if (crecp->uid =3D=3D (unsigned int)class && !algo_digest_name(crecp= ->addr.key.algo)) -+ return STAT_INSECURE; -+ } -+ while ((crecp =3D cache_find_by_name(crecp, keyname, now, F_DNSKEY))); -+ } -+ - if (name_start =3D=3D 0) - break; -=20 ---=20 -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 -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_hea= der *header, size_t plen, ch - /* Empty DS without NSECS */ - if (qtype =3D=3D T_DS) - return STAT_BOGUS; -- else -+ =20 -+ rc =3D zone_status(name, qclass, keyname, now); -+ if (rc !=3D STAT_SECURE) - { -- rc =3D zone_status(name, qclass, keyname, now); -- if (rc !=3D STAT_SECURE) -- { -- if (class) -- *class =3D qclass; /* Class for NEED_DS or NEED_DNSKEY */ -- return rc; -- }=20 -- =09 -- return STAT_BOGUS; /* signed zone, no NSECs */ -- } -+ if (class) -+ *class =3D qclass; /* Class for NEED_DS or NEED_DNSKEY */ -+ return rc; -+ }=20 -+ =20 -+ return STAT_BOGUS; /* signed zone, no NSECs */ - } -=20 - if (nsec_type =3D=3D T_NSEC) -diff --git a/src/rfc1035.c b/src/rfc1035.c -index def8fa0..188d05f 100644 ---- a/src/rfc1035.c -+++ b/src/rfc1035.c -@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - int nxdomain =3D 0, auth =3D 1, trunc =3D 0, sec_data =3D 1; - struct mx_srv_record *rec; - size_t len; --=20 -+ =20 -+ if (ntohs(header->ancount) !=3D 0 || -+ ntohs(header->nscount) !=3D 0 || -+ ntohs(header->qdcount) =3D=3D 0 ||=20 -+ OPCODE(header) !=3D QUERY ) -+ return 0; -+ =20 - /* Don't return AD set if checking disabled. */ - if (header->hb4 & HB4_CD) - sec_data =3D 0; -@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header *header, cha= r *limit, size_t qlen, - *ad_reqd =3D header->hb4 & HB4_AD; - *do_bit =3D 0; -=20 -- /* 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. */ -=20 -- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) -- {=20 -- unsigned short flags; -- =20 -- have_pseudoheader =3D 1; -+ if (ntohs(header->arcount) !=3D 0) -+ { -+ dryrun =3D 1; -=20 -- pheader +=3D 4; /* udp size, ext_rcode */ -- GETSHORT(flags, pheader); -- =20 -- if ((sec_reqd =3D flags & 0x8000)) -- { -- *do_bit =3D 1;/* do bit */=20 -- *ad_reqd =3D 1; -+ /* If there's an additional section, there might be an EDNS(0) pseudo= header */ -+ if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) -+ {=20 -+ unsigned short flags; -+ =20 -+ have_pseudoheader =3D 1; -+ =20 -+ pheader +=3D 4; /* udp size, ext_rcode */ -+ GETSHORT(flags, pheader); -+ =20 -+ if ((sec_reqd =3D flags & 0x8000)) -+ { -+ *do_bit =3D 1;/* do bit */=20 -+ *ad_reqd =3D 1; -+ } - } -- -- dryrun =3D 1; - } -=20 -- if (ntohs(header->qdcount) =3D=3D 0 || OPCODE(header) !=3D QUERY ) -- return 0; -- =20 - for (rec =3D daemon->mxnames; rec; rec =3D rec->next) - rec->offset =3D 0; - =20 -@@ -1730,8 +1735,12 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - } - else if ((crecp =3D 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 || !(cr= ecp->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)) ||=20 -+ !sec_reqd ||=20 -+ (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) - { - do=20 - {=20 ---=20 -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_st= atus_is_NSEC_proof_bad.patch +++ /dev/null @@ -1,409 +0,0 @@ -From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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) - } - } -=20 --/* 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, unsign= ed char ***nsecsetp, int *nsecsetl, int class_reqd) --{ -- static unsigned char **nsecset =3D NULL; -- static int nsecset_sz =3D 0; -- =20 -- int type_found =3D 0; -- unsigned char *p =3D skip_questions(header, plen); -- int type, class, rdlen, i, nsecs_found; -- -- /* Move to NS section */ -- if (!p || !(p =3D skip_section(p, ntohs(header->ancount), header, plen))) -- return 0; -- =20 -- for (nsecs_found =3D 0, i =3D ntohs(header->nscount); i !=3D 0; i--) -- { -- unsigned char *pstart =3D p; -- =20 -- if (!(p =3D skip_name(p, header, plen, 10))) -- return 0; -- =20 -- GETSHORT(type, p);=20 -- GETSHORT(class, p); -- p +=3D 4; /* TTL */ -- GETSHORT(rdlen, p); -- -- if (class =3D=3D class_reqd && (type =3D=3D T_NSEC || type =3D=3D T_N= SEC3)) -- { -- /* No mixed NSECing 'round here, thankyouverymuch */ -- if (type_found =3D=3D T_NSEC && type =3D=3D T_NSEC3) -- return 0; -- if (type_found =3D=3D T_NSEC3 && type =3D=3D T_NSEC) -- return 0; -- -- type_found =3D type; -- -- if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found)) -- return 0;=20 -- =20 -- nsecset[nsecs_found++] =3D pstart; -- } -- =20 -- if (!ADD_RDLEN(header, p, plen, rdlen)) -- return 0; -- } -- =20 -- *nsecsetp =3D nsecset; -- *nsecsetl =3D nsecs_found; -- =20 -- 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_heade= r *header, size_t plen, unsi - { - p =3D nsecs[i]; - if (!extract_name(header, plen, &p, workspace1, 1, 10)) -- return STAT_BOGUS; -+ return 0; - p +=3D 8; /* class, type, TTL */ - GETSHORT(rdlen, p); - psave =3D p; - if (!extract_name(header, plen, &p, workspace2, 1, 10)) -- return STAT_BOGUS; -+ return 0; - =20 - rc =3D hostname_cmp(workspace1, name); - =20 -@@ -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 =3D=3D T_NSEC || type =3D=3D T_RRSIG) -- return STAT_SECURE; -+ return 1; -=20 - /* 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_heade= r *header, size_t plen, unsi - /* A CNAME answer would also be valid, so if there's a CNAME is shou= ld=20 - have been returned. */ - if ((p[2] & (0x80 >> T_CNAME)) !=3D 0) -- return STAT_BOGUS; -+ return 0; - =20 - /* If the SOA bit is set for a DS record, then we have the - DS from the wrong side of the delegation. */ - if (type =3D=3D T_DS && (p[2] & (0x80 >> T_SOA)) !=3D 0) -- return STAT_BOGUS; -+ return 0; - } -=20 - while (rdlen >=3D 2) - { - if (!CHECK_LEN(header, p, plen, rdlen)) -- return STAT_BOGUS; -+ return 0; - =20 - if (p[0] =3D=3D type >> 8) - { - /* Does the NSEC say our type exists? */ - if (offset < p[1] && (p[offset+2] & mask) !=3D 0) -- return STAT_BOGUS; -+ return 0; - =20 - break; /* finshed checking */ - } -@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct dns_heade= r *header, size_t plen, unsi - p +=3D p[1]; - } - =20 -- return STAT_SECURE; -+ return 1; - } - else if (rc =3D=3D -1) - { - /* Normal case, name falls between NSEC name and next domain name, - wrap around case, name falls between NSEC name (rc =3D=3D -1) and end= */ - if (hostname_cmp(workspace2, name) >=3D 0 || hostname_cmp(workspace1, wo= rkspace2) >=3D 0) -- return STAT_SECURE; -+ return 1; - } - else=20 - { - /* wrap around case, name falls between start and next domain name */ - if (hostname_cmp(workspace1, workspace2) >=3D 0 && hostname_cmp(workspac= e2, name) >=3D0 ) -- return STAT_SECURE; -+ return 1; - } - } - =20 -- return STAT_BOGUS; -+ return 0; - } -=20 - /* 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 =3D 0; i < nsec_count; i++) - { - if (!(p =3D skip_name(nsecs[i], header, plen, 15))) -- return STAT_BOGUS; /* bad packet */ -+ return 0; /* bad packet */ - =20 - p +=3D 10; /* type, class, TTL, rdlen */ - algo =3D *p++; -@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct dns_head= er *header, size_t plen, uns -=20 - /* No usable NSEC3s */ - if (i =3D=3D nsec_count) -- return STAT_BOGUS; -+ return 0; -=20 - p++; /* flags */ - GETSHORT (iterations, p); - salt_len =3D *p++; - salt =3D p; - if (!CHECK_LEN(header, salt, plen, salt_len)) -- return STAT_BOGUS; /* bad packet */ -+ return 0; /* bad packet */ - =20 - /* Now prune so we only have NSEC3 records with same iterations, salt and= algo */ - for (i =3D 0; i < nsec_count; i++) -@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct dns_header= *header, size_t plen, uns - nsecs[i] =3D NULL; /* Speculative, will be restored if OK. */ - =20 - if (!(p =3D skip_name(nsec3p, header, plen, 15))) -- return STAT_BOGUS; /* bad packet */ -+ return 0; /* bad packet */ - =20 - p +=3D 10; /* type, class, TTL, rdlen */ - =20 -@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct dns_header= *header, size_t plen, uns - continue; - =20 - if (!CHECK_LEN(header, p, plen, salt_len)) -- return STAT_BOGUS; /* bad packet */ -+ return 0; /* bad packet */ -=20 - if (memcmp(p, salt, salt_len) !=3D 0) - continue; -@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct dns_head= er *header, size_t plen, uns -=20 - /* Algo is checked as 1 above */ - if (!(hash =3D hash_find("sha1"))) -- return STAT_BOGUS; -+ return 0; -=20 - if ((digest_len =3D hash_name(name, &digest, hash, salt, salt_len, iterat= ions)) =3D=3D 0) -- return STAT_BOGUS; -+ return 0; - =20 - if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspac= e1, workspace2, nsecs, nsec_count, nons)) -- return STAT_SECURE; -+ return 1; -=20 - /* Can't find an NSEC3 which covers the name directly, we need the "close= st encloser NSEC3"=20 - or an answer inferred from a wildcard record. */ -@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct dns_head= er *header, size_t plen, uns - break; -=20 - if ((digest_len =3D hash_name(closest_encloser, &digest, hash, salt, = salt_len, iterations)) =3D=3D 0) -- return STAT_BOGUS; -+ return 0; - =20 - for (i =3D 0; i < nsec_count; i++) - if ((p =3D nsecs[i])) - { - if (!extract_name(header, plen, &p, workspace1, 1, 0) || - !(base32_len =3D base32_decode(workspace1, (unsigned char *)workspace2))) -- return STAT_BOGUS; -+ return 0; - =20 - if (digest_len =3D=3D base32_len && - memcmp(digest, workspace2, digest_len) =3D=3D 0) -@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct dns_head= er *header, size_t plen, uns - while ((closest_encloser =3D strchr(closest_encloser, '.'))); - =20 - if (!closest_encloser) -- return STAT_BOGUS; -+ return 0; - =20 - /* Look for NSEC3 that proves the non-existence of the next-closest enclo= ser */ - if ((digest_len =3D hash_name(next_closest, &digest, hash, salt, salt_len= , iterations)) =3D=3D 0) -- return STAT_BOGUS; -+ return 0; -=20 - if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspa= ce1, workspace2, nsecs, nsec_count, NULL)) -- return STAT_BOGUS; -+ return 0; - =20 - /* Finally, check that there's no seat of wildcard synthesis */ - if (!wildname) - { - if (!(wildcard =3D strchr(next_closest, '.')) || wildcard =3D=3D next= _closest) -- return STAT_BOGUS; -+ return 0; - =20 - wildcard--; - *wildcard =3D '*'; - =20 - if ((digest_len =3D hash_name(wildcard, &digest, hash, salt, salt_len= , iterations)) =3D=3D 0) -- return STAT_BOGUS; -+ return 0; - =20 - if (!check_nsec3_coverage(header, plen, digest_len, digest, type, wor= kspace1, workspace2, nsecs, nsec_count, NULL)) -- return STAT_BOGUS; -+ return 0; - } - =20 -- 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 =3D NULL; -+ static int nsecset_sz =3D 0; -+ =20 -+ int type_found =3D 0; -+ unsigned char *p =3D skip_questions(header, plen); -+ int type, class, rdlen, i, nsecs_found; -+ =20 -+ /* Move to NS section */ -+ if (!p || !(p =3D skip_section(p, ntohs(header->ancount), header, plen))) -+ return 0; -+ =20 -+ for (nsecs_found =3D 0, i =3D ntohs(header->nscount); i !=3D 0; i--) -+ { -+ unsigned char *pstart =3D p; -+ =20 -+ if (!(p =3D skip_name(p, header, plen, 10))) -+ return 0; -+ =20 -+ GETSHORT(type, p);=20 -+ GETSHORT(class, p); -+ p +=3D 4; /* TTL */ -+ GETSHORT(rdlen, p); -+ -+ if (class =3D=3D qclass && (type =3D=3D T_NSEC || type =3D=3D T_NSEC3= )) -+ { -+ /* No mixed NSECing 'round here, thankyouverymuch */ -+ if (type_found !=3D 0 && type_found !=3D type) -+ return 0; -+ -+ type_found =3D type; -+ -+ if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found)) -+ return 0;=20 -+ =20 -+ nsecset[nsecs_found++] =3D pstart; -+ } -+ =20 -+ if (!ADD_RDLEN(header, p, plen, rdlen)) -+ return 0; -+ } -+ =20 -+ if (type_found =3D=3D T_NSEC) -+ return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, dae= mon->workspacename, keyname, name, qtype, nons); -+ else -+ return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, da= emon->workspacename, keyname, name, qtype, wildname, nons); - } -=20 - /* Check signing status of name. -@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct dns_head= er *header, size_t plen, ch - static unsigned char **targets =3D NULL; - static int target_sz =3D 0; -=20 -- unsigned char *ans_start, *p1, *p2, **nsecs; -+ unsigned char *ans_start, *p1, *p2; - int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetid= x; -- int i, j, rc, nsec_count; -- int nsec_type; -+ int i, j, rc; -=20 - if (neganswer) - *neganswer =3D 0; -@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct dns_hea= der *header, size_t plen, ch - targets[j] =3D NULL; - } - =20 -- if (rc =3D=3D 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 =3D find_nsec_records(header, plen, &nsecs, &nsec_c= ount, class1))) -- return STAT_BOGUS; /* No NSECs or bad packet */ -- =20 -- /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. S= ince the check -- below returns either SECURE or BOGUS, that's not a problem. If the RRse= ts later fail -- we'll return BOGUS then. */ -- -- if (nsec_type =3D=3D T_NSEC) -- rc =3D prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon-= >workspacename, keyname, name, type1, NULL); -- else -- rc =3D prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon= ->workspacename,=20 -- keyname, name, type1, wildname, NULL); -- =20 -- if (rc =3D=3D STAT_BOGUS) -- return rc; -- }=20 -+ /* 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.=20 -+ Note that we may not yet have validated the NSEC/NSEC3 RRsets.=20 -+ That's not a problem since if the RRsets later fail -+ we'll return BOGUS then. */ -+ if (rc =3D=3D 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_hea= der *header, size_t plen, ch -=20 - /* 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 =3D find_nsec_records(header, plen, &nsecs, &nsec_count, q= class))) -+ if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL,= nons)) - { - /* Empty DS without NSECS */ - if (qtype =3D=3D T_DS) - return STAT_BOGUS; - =20 -- rc =3D zone_status(name, qclass, keyname, now); -- if (rc !=3D STAT_SECURE) -+ if ((rc =3D zone_status(name, qclass, keyname, now)) !=3D STAT_SECURE) - { - if (class) - *class =3D qclass; /* Class for NEED_DS or NEED_DNSKEY */ -@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct dns_head= er *header, size_t plen, ch - =20 - return STAT_BOGUS; /* signed zone, no NSECs */ - } -- -- if (nsec_type =3D=3D T_NSEC) -- rc =3D prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon-= >workspacename, keyname, name, qtype, nons); -- else -- rc =3D prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon= ->workspacename, keyname, name, qtype, NULL, nons); -- -- if (rc !=3D STAT_SECURE) -- return rc; - } - =20 - return STAT_SECURE; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.pa= tch 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 -Date: Thu, 17 Dec 2015 16:58:04 +0000 -Subject: [PATCH] Fix brace botch in dnssec_validate_ds() -MIME-Version: 1.0 -Content-Type: text/plain; charset=3Dutf8 -Content-Transfer-Encoding: 8bit - -Thanks to Micha=C3=85=C2=82 K=C3=84=C2=99pie=C3=85=C2=84 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_heade= r *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= =20 -- STAT_NEED_DNSKEY DNSKEY records to validate a key not found, name in key= name=20 -+ 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=20 -+ STAT_NEED_KEY DNSKEY records to validate a key not found, name in keynam= e=20 - */ - int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t ple= n, 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 - } - =20 - p =3D psave; -- =20 -- if (!ADD_RDLEN(header, p, plen, rdlen)) -- return STAT_BOGUS; /* bad packet */ - } -- =20 -- 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 *he= ader, size_t plen, char *key -=20 - /* 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_heade= r *header, size_t plen, ch - if (rc =3D=3D STAT_SECURE) - rc =3D STAT_BOGUS; - if (class) -- *class =3D class1; /* Class for NEED_DS or NEED_DNSKEY */ -+ *class =3D class1; /* Class for NEED_DS or NEED_KEY */ - } - else=20 - rc =3D STAT_INSECURE;=20 -@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct dns_heade= r *header, size_t plen, ch - { - /* Zone is insecure, don't need to validate RRset */ - if (class) -- *class =3D class1; /* Class for NEED_DS or NEED_DNSKEY */ -+ *class =3D class1; /* Class for NEED_DS or NEED_KEY */ - return rc; - }=20 - =20 -@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct dns_heade= r *header, size_t plen, ch - if ((rc =3D zone_status(name, qclass, keyname, now)) !=3D STAT_SECURE) - { - if (class) -- *class =3D qclass; /* Class for NEED_DS or NEED_DNSKEY */ -+ *class =3D qclass; /* Class for NEED_DS or NEED_KEY */ - return rc; - }=20 - =20 ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNS= SEC_sig_algos_are_supported.patch b/src/patches/dnsmasq/024-Do_a_better_job_o= f_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 -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, v= oid **ctxp, unsigned char - } - =20 - 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; - =20 - static struct rsa_public_key *key =3D NULL; - static mpz_t sig_mpz; -+ -+ (void)digest_len; - =20 - if (key =3D=3D NULL) - { -@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata *key_data= , unsigned int key_len, - } =20 -=20 - 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 =3D NULL; - static struct dsa_signature *sig_struct; - =20 -+ (void)digest_len; -+ - if (key =3D=3D NULL) - { - if (!(sig_struct =3D whine_malloc(sizeof(struct dsa_signature))) ||=20 -@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_= data, unsigned int key_len - }=20 - #endif=20 -=20 --static int verify(struct blockdata *key_data, unsigned int key_len, unsigne= d 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 in= t key_len, unsigned char *sig, size_t sig_len, -+ unsigned char *digest, size_t digest_len, int algo) - { -- (void)digest_len; -- -+ =20 -+ /* Enure at runtime that we have support for this digest */ -+ if (!hash_find(algo_digest_name(algo))) -+ return NULL; -+ =20 -+ /* 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, al= go); -+ return dnsmasq_rsa_verify; - =20 - case 3: case 6:=20 -- return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, digest, al= go); -+ return dnsmasq_dsa_verify; - =20 - #ifndef NO_NETTLE_ECC =20 - case 13: case 14: -- return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, = digest_len, algo); -+ return dnsmasq_ecdsa_verify; - #endif - } - =20 -- return 0; -+ return NULL; -+} -+ -+static int verify(struct blockdata *key_data, unsigned int key_len, unsigne= d 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 ch= ar *sig, size_t sig_len, -+ unsigned char *digest, size_t digest_len, int algo); -+ =20 -+ func =3D verify_func(algo); -+ =20 -+ if (!func) -+ return 0; -+ -+ return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo); - } -=20 - /* 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 <=3D name_labels && - type_covered =3D=3D type &&=20 -- algo_digest_name(algo)) -+ verify_func(algo)) - { - if (!expand_workspace(&sigs, &sig_sz, sigidx)) - return 0;=20 -@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class, char *ke= yname, 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(cr= ecp->addr.ds.algo)) -+ else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_f= unc(crecp->addr.ds.algo)) - return STAT_INSECURE; /* algo we can't use - insecure */ - else - secure_ds =3D 1; -@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class, char *ke= yname, time_t now) -=20 - do=20 - { -- if (crecp->uid =3D=3D (unsigned int)class && !algo_digest_name(crecp= ->addr.key.algo)) -+ if (crecp->uid =3D=3D (unsigned int)class && !verify_func(crecp->add= r.key.algo)) - return STAT_INSECURE; - } - while ((crecp =3D cache_find_by_name(crecp, keyname, now, F_DNSKEY))); ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_comp= utation_use_of_udp.patch b/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_han= dling_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 -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) - } -=20 -=20 --size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, tim= e_t now, union mysockaddr *peer_addr, int local_query)=20 -+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, tim= e_t now, union mysockaddr *peer_addr,=20 -+ int local_query, int do_bit, int have_pseudoheader)=20 - { - char *name =3D daemon->namebuff; - unsigned char *p, *ansp; -@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *lim= it, size_t qlen, time_t n - header->ancount =3D htons(anscount); - header->nscount =3D htons(authcount); - header->arcount =3D htons(0); -+ -+ /* Advertise our packet size limit in our reply */ -+ if (have_pseudoheader) -+ return add_pseudoheader(header, ansp - (unsigned char *)header, (unsig= ned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit); -+ - return ansp - (unsigned char *)header; - } - =20 -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, = =20 - struct in_addr local_addr, struct in_addr local_netmask,=20 -- 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,=20 - struct bogus_addr *addr, time_t now); - int check_for_ignored_address(struct dns_header *header, size_t qlen, struc= t 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 *bu= ff); - size_t resize_packet(struct dns_header *header, size_t plen,=20 - unsigned char *pheader, size_t hlen); -+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -+ 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 m= ysockaddr *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,=20 -- 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 -=20 -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 *ud= paddr, - void *hash =3D &crc; - #endif - unsigned int gotname =3D extract_request(header, plen, daemon->namebuff, N= ULL); -- unsigned char *pheader; -=20 - (void)do_bit; -=20 -@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, - 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; - =20 - forward->flags &=3D ~FREC_TEST_PKTSZ; - =20 -@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, - blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); - plen =3D forward->stash_len; - =20 -- if (find_pseudoheader(header, plen, NULL, &pheader, NULL)) -- PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->se= ntto->edns_pktsz, pheader); -+ if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sig= n) -+ PUTSHORT(SAFE_PKTSZ, pheader); -=20 - if (forward->sentto->addr.sa.sa_family =3D=3D AF_INET)=20 - 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 =3D daemon->log_id; - =20 - if (option_bool(OPT_ADD_MAC)) -- plen =3D add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz,= &forward->source); -- =20 -+ { -+ size_t new =3D add_mac(header, plen, ((char *) header) + daemon->packet_= buff_sz, &forward->source); -+ if (new !=3D plen) -+ { -+ plen =3D new; -+ forward->flags |=3D FREC_ADDED_PHEADER; -+ } -+ } -+ - if (option_bool(OPT_CLIENT_SUBNET)) - { - size_t new =3D add_source_addr(header, plen, ((char *) header) + daemon-= >packet_buff_sz, &forward->source);=20 - if (new !=3D plen) - { - plen =3D new; -- forward->flags |=3D FREC_HAS_SUBNET; -+ forward->flags |=3D FREC_HAS_SUBNET | FREC_ADDED_PHEADER; - } - } -=20 - #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID)) - { -- size_t new_plen =3D add_do_bit(header, plen, ((char *) header) + daemon-= >packet_buff_sz); -+ size_t new =3D add_do_bit(header, plen, ((char *) header) + daemon->pack= et_buff_sz); - =20 -+ if (new !=3D plen) -+ forward->flags |=3D FREC_ADDED_PHEADER; -+ -+ plen =3D new; -+ =20 - /* For debugging, set Checking Disabled, otherwise, have the upstream ch= eck too, - this allows it to select auth servers when one is returning bad data.= */ - if (option_bool(OPT_DNSSEC_DEBUG)) - header->hb4 |=3D HB4_CD; -=20 -- if (new_plen !=3D plen) -- forward->flags |=3D FREC_ADDED_PHEADER; -- -- plen =3D new_plen; - } - #endif - =20 -@@ -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_pk= tsz, pheader); - =20 -+#ifdef HAVE_DNSSEC -+ if (option_bool(OPT_DNSSEC_VALID) && !do_bit) -+ { -+ /* Difficult one here. If our client didn't send EDNS0, we will have se= t the UDP -+ packet size to 512. But that won't provide space for the RRSIGS in m= any 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 stri= pping and set -+ the truncated bit? */ =20 -+ 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 - =20 -- /* 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 =3D find_pseudoheader(header, n, &plen, &sizep, &is_sign))) - { -- unsigned short udpsz; -- unsigned char *psave =3D sizep; -- =20 -- GETSHORT(udpsz, sizep); -- -- if (!is_sign && udpsz > daemon->edns_pktsz) -- PUTSHORT(daemon->edns_pktsz, psave); -- =20 - if (check_subnet && !check_source(header, plen, pheader, query_source= )) - { - my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch")= ); - return 0; - } - =20 -- if (added_pheader) -+ if (!is_sign) - { -- pheader =3D 0;=20 -- header->arcount =3D htons(0); -+ if (added_pheader) -+ { -+ /* client didn't send EDNS0, we added one, strip it off before retur= ning answer. */ -+ n =3D rrfilter(header, n, 0); -+ pheader =3D 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 =3D sizep; -+ =20 -+ GETSHORT(udpsz, sizep); -+ if (udpsz > daemon->edns_pktsz) -+ PUTSHORT(daemon->edns_pktsz, psave); -+ } - } - } - =20 -@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header,= time_t now, struct server - } -=20 - if (option_bool(OPT_DNSSEC_VALID)) -- header->hb4 &=3D ~HB4_AD; -- =20 -- if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) -- header->hb4 |=3D HB4_AD; -- -- /* If the requestor didn't set the DO bit, don't return DNSSEC info. */ -- if (!do_bit) -- n =3D rrfilter(header, n, 1); -+ { -+ header->hb4 &=3D ~HB4_AD; -+ =20 -+ if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) -+ header->hb4 |=3D HB4_AD; -+ =20 -+ /* If the requestor didn't set the DO bit, don't return DNSSEC info. = */ -+ if (!do_bit) -+ n =3D rrfilter(header, n, 1); -+ } - #endif -=20 - /* 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 =3D resize_packet(header, (size_t)n, pheader, plen))) - { - header->hb3 &=3D ~(HB3_QR | HB3_AA | HB3_TC); -- header->hb4 &=3D ~(HB4_RA | HB4_RCODE); -- forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0); -+ header->hb4 &=3D ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD); -+ if (forward->flags |=3D FREC_CHECKING_DISABLED) -+ header->hb4 |=3D HB4_CD; -+ if (forward->flags |=3D FREC_AD_QUESTION) -+ header->hb4 |=3D 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 n= ow) - { - struct dns_header *header =3D (struct dns_header *)daemon->packet; - union mysockaddr source_addr; -- unsigned short type; -+ unsigned char *pheader; -+ unsigned short type, udp_size =3D 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 =3D 0, auth_dns =3D 0; -+ int if_index =3D 0, auth_dns =3D 0, do_bit =3D 0, have_pseudoheader =3D 0; - #ifdef HAVE_AUTH - int local_auth =3D 0; - #endif -@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t n= ow) - #endif - } - =20 -+ if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL)) -+ {=20 -+ unsigned short flags; -+ =20 -+ have_pseudoheader =3D 1; -+ GETSHORT(udp_size, pheader); -+ pheader +=3D 2; /* ext_rcode */ -+ GETSHORT(flags, pheader); -+ =20 -+ if (flags & 0x8000) -+ do_bit =3D 1;/* do bit */=20 -+=09 -+ /* If the client provides an EDNS0 UDP size, use that to limit our re= ply. -+ (bounded by the maximum configured). If no EDNS0, then it -+ defaults to 512 */ -+ if (udp_size > daemon->edns_pktsz) -+ udp_size =3D daemon->edns_pktsz; -+ } -+ - #ifdef HAVE_AUTH - if (auth_dns) - { -- m =3D answer_auth(header, ((char *) header) + daemon->packet_buff_sz,= (size_t)n, now, &source_addr, local_auth); -+ m =3D answer_auth(header, ((char *) header) + udp_size, (size_t)n, no= w, &source_addr,=20 -+ local_auth, do_bit, have_pseudoheader); - if (m >=3D 1) - { - send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERB= IND), -@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t no= w) - else - #endif - { -- int ad_reqd, do_bit; -- m =3D answer_request(header, ((char *) header) + daemon->packet_buff_= sz, (size_t)n,=20 -- dst_addr_4, netmask, now, &ad_reqd, &do_bit); -+ int ad_reqd =3D do_bit; -+ /* RFC 6840 5.7 */ -+ if (header->hb4 & HB4_AD) -+ ad_reqd =3D 1; -+ -+ m =3D answer_request(header, ((char *) header) + udp_size, (size_t)n,= =20 -+ dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); - =20 - if (m >=3D 1) - { -@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now, - #ifdef HAVE_AUTH - int local_auth =3D 0; - #endif -- int checking_disabled, ad_question, do_bit, added_pheader =3D 0; -+ int checking_disabled, do_bit, added_pheader =3D 0, have_pseudoheader =3D= 0; - int check_subnet, no_cache_dnssec =3D 0, cache_secure =3D 0, bogusanswer = =3D 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 =3D sizeof(union mysockaddr); - int query_count =3D 0; -+ unsigned char *pheader; -=20 - if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) =3D=3D -= 1) - return packet; -@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now, - else - dst_addr_4.s_addr =3D 0; - =20 -+ do_bit =3D 0; -+ -+ if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL)) -+ {=20 -+ unsigned short flags; -+ =20 -+ have_pseudoheader =3D 1; -+ pheader +=3D 4; /* udp_size, ext_rcode */ -+ GETSHORT(flags, pheader); -+ =20 -+ if (flags & 0x8000) -+ do_bit =3D 1;/* do bit */=20 -+ } -+ - #ifdef HAVE_AUTH - if (auth_dns) -- m =3D answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &p= eer_addr, local_auth); -+ m =3D answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &p= eer_addr,=20 -+ local_auth, do_bit, have_pseudoheader); - else - #endif - { -- /* m > 0 if answered from cache */ -- m =3D answer_request(header, ((char *) header) + 65536, (size_t)size,=20 -- dst_addr_4, netmask, now, &ad_question, &do_bit); -+ int ad_reqd =3D do_bit; -+ /* RFC 6840 5.7 */ -+ if (header->hb4 & HB4_AD) -+ ad_reqd =3D 1; -+ =20 -+ /* m > 0 if answered from cache */ -+ m =3D answer_request(header, ((char *) header) + 65536, (size_t)size,=20 -+ dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); - =20 - /* Do this by steam now we're not in the select() loop */ - check_log_writer(1);=20 -@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now, - } - =20 - #ifdef HAVE_DNSSEC -+ added_pheader =3D 0; =20 - if (option_bool(OPT_DNSSEC_VALID)) - { - size_t new_size =3D add_do_bit(header, size, ((char *) header) + 6= 5536); -@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now, -=20 - m =3D process_reply(header, now, last_server, (unsigned int)m,=20 - option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure= , bogusanswer, -- ad_question, do_bit, added_pheader, check_subnet, &peer_addr);=20 -+ ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);=20 - =20 - 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 (*callba= ck)()) - rta =3D RTA_NEXT(rta, len1); - } -=20 -- 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 =3D 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; - }; - =20 --static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsi= gned char *limit,=20 -- int optno, unsigned char *opt, size_t optlen, int set_do) -+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -+ unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int= set_do) - {=20 - 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++ =3D 0; /* empty name */ - PUTSHORT(T_OPT, p); -- PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritt= en */ -+ 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 =3D 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 */ -=20 -- parm->plen =3D add_pseudoheader(parm->header, parm->plen, parm->limit, E= DNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); -+ parm->plen =3D add_pseudoheader(parm->header, parm->plen, parm->limit, PA= CKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); - =20 - return 0; /* done */ - } =20 -@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, = char *limit, union mysock - { - struct macparm parm; - =20 --/* Must have an existing pseudoheader as the only ar-record,=20 -- or have no ar-records. Must also not be signed */ -- =20 -- if (ntohs(header->arcount) > 1) -- return plen; -- - parm.header =3D header; - parm.limit =3D (unsigned char *)limit; - parm.plen =3D plen; -@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size= _t plen, char *limit, unio - struct subnet_opt opt; - =20 - len =3D calc_subnet_opt(&opt, source); -- return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTIO= N_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); -+ return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, E= DNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); - } -=20 - #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 -=20 -@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, ti= me_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, = =20 - struct in_addr local_addr, struct in_addr local_netmask,=20 -- time_t now, int *ad_reqd, int *do_bit)=20 -+ time_t now, int ad_reqd, int do_bit, int have_pseudoheader)=20 - { - char *name =3D 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 =3D 0, addncount =3D 0; -- int dryrun =3D 0, sec_reqd =3D 0, have_pseudoheader =3D 0; -+ int dryrun =3D 0; - struct crec *crecp; - int nxdomain =3D 0, auth =3D 1, trunc =3D 0, sec_data =3D 1; - struct mx_srv_record *rec; -@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, cha= r *limit, size_t qlen, - if (header->hb4 & HB4_CD) - sec_data =3D 0; - =20 -- /* RFC 6840 5.7 */ -- *ad_reqd =3D header->hb4 & HB4_AD; -- *do_bit =3D 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) !=3D 0) -- { -- dryrun =3D 1; -- -- /* If there's an additional section, there might be an EDNS(0) pseudo= header */ -- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) -- {=20 -- unsigned short flags; -- =20 -- have_pseudoheader =3D 1; -- =20 -- pheader +=3D 4; /* udp size, ext_rcode */ -- GETSHORT(flags, pheader); -- =20 -- if ((sec_reqd =3D flags & 0x8000)) -- { -- *do_bit =3D 1;/* do bit */=20 -- *ad_reqd =3D 1; -- } -- } -- } -+ dryrun =3D 1; -=20 - for (rec =3D daemon->mxnames; rec; rec =3D rec->next) - rec->offset =3D 0; -@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char= *limit, size_t qlen, - GETSHORT(qtype, p);=20 - GETSHORT(qclass, p); -=20 -- /* Don't filter RRSIGS from answers to ANY queries, even if do-bit -- not set. */ -- if (qtype =3D=3D T_ANY) -- *do_bit =3D 1; -- - ans =3D 0; /* have we answered this question */ - =20 - if (qtype =3D=3D T_TXT || qtype =3D=3D T_ANY) -@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char = *limit, size_t qlen, - the zone is unsigned, which implies that we're doing - validation. */ - if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||=20 -- !sec_reqd ||=20 -+ !do_bit ||=20 - (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) - { - do=20 -@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char = *limit, size_t qlen, - } -=20 - /* If the client asked for DNSSEC don't use cached data. */ -- if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(cr= ecp->flags & F_DNSSECOK)) -+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crec= p->flags & F_DNSSECOK)) - do - {=20 - /* don't answer wildcard queries with data not from /etc/hosts -@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, cha= r *limit, size_t qlen, - =09 - if (crecp->flags & F_NEG) - { -- /* We don't cache NSEC records, so if a DNSSEC-validated negative an= swer -- is cached and the client wants DNSSEC, forward rather than answer= ing from the cache */ -- if (!sec_reqd || !(crecp->flags & F_DNSSECOK)) -- { -- ans =3D 1; -- auth =3D 0; -- if (crecp->flags & F_NXDOMAIN) -- nxdomain =3D 1; -- if (!dryrun) -- log_query(crecp->flags, name, NULL, NULL); -- } -+ ans =3D 1; -+ auth =3D 0; -+ if (crecp->flags & F_NXDOMAIN) -+ nxdomain =3D 1; -+ if (!dryrun) -+ log_query(crecp->flags, name, NULL, NULL); - } - else=20 - { -@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, cha= r *limit, size_t qlen, -=20 - len =3D ansp - (unsigned char *)header; - =20 -+ /* Advertise our packet size limit in our reply */ - if (have_pseudoheader) -- len =3D add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, = 0, sec_reqd); -+ len =3D add_pseudoheader(header, len, (unsigned char *)limit, daemon->e= dns_pktsz, 0, NULL, 0, do_bit); - =20 -- if (*ad_reqd && sec_data) -+ if (ad_reqd && sec_data) - header->hb4 |=3D HB4_AD; - else - header->hb4 &=3D ~HB4_AD; -diff --git a/src/rrfilter.c b/src/rrfilter.c -index ae12261..b26b39f 100644 ---- a/src/rrfilter.c -+++ b/src/rrfilter.c -@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, = int mode) - for (p =3D rrs[0], i =3D 1; i < rr_found; i +=3D 2) - { - unsigned char *start =3D rrs[i]; -- unsigned char *end =3D (i !=3D rr_found - 1) ? rrs[i+1] : ((unsigned = char *)(header+1)) + plen; -+ unsigned char *end =3D (i !=3D rr_found - 1) ? rrs[i+1] : ((unsigned = char *)header) + plen; - =20 - memmove(p, start, end-start); - p +=3D end-start; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_a= lgorithms.patch b/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNS= SEC_algorithms.patch deleted file mode 100644 index 910921b..0000000 --- a/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorith= ms.patch +++ /dev/null @@ -1,262 +0,0 @@ -From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -Date: Sun, 20 Dec 2015 20:44:23 +0000 -Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms. - ---- - src/dnssec.c | 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; - } - } -- =20 -+ =20 -+/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-par= ameters.xhtml */ -+static char *nsec3_digest_name(int digest) -+{ -+ switch (digest) -+ { -+ case 1: return "sha1"; -+ default: return NULL; -+ } -+} -+=20 - /* 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 =3D 0, sig_sz =3D 0;=20 - unsigned char *p; - int rrsetidx, sigidx, j, rdlen, res; -- int name_labels =3D count_labels(name); /* For 4035 5.3.2 check */ - int gotkey =3D 0; -=20 - if (!(p =3D skip_questions(header, plen))) -@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header *header, size= _t plen, int class, int - j !=3D 0; j--)=20 - { - unsigned char *pstart, *pdata; -- int stype, sclass, algo, type_covered, labels, sig_expiration, sig_in= ception; -+ int stype, sclass, type_covered; -=20 - pstart =3D p; - =20 -@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, siz= e_t plen, int class, int - return 0; /* bad packet */=20 - =20 - GETSHORT(type_covered, p); -- algo =3D *p++; -- labels =3D *p++; -- p +=3D 4; /* orig_ttl */ -- GETLONG(sig_expiration, p); -- GETLONG(sig_inception, p); -- p +=3D 2; /* key_tag */ -+ p +=3D 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception,= key_tag */ - =20 - if (gotkey) - { -@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, siz= e_t plen, int class, int - } - } - =20 -- /* Don't count signatures for algos we don't support */ -- if (check_date_range(sig_inception, sig_expiration) && -- labels <=3D name_labels && -- type_covered =3D=3D type &&=20 -- verify_func(algo)) -+ =20 -+ if (type_covered =3D=3D type) - { - if (!expand_workspace(&sigs, &sig_sz, sigidx)) - return 0;=20 -@@ -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 =3D NULL; - int algo, labels, orig_ttl, key_tag; - u16 *rr_desc =3D rrfilter_desc(type); -@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct dns_heade= r *header, size_t plen, in - algo =3D *p++; - labels =3D *p++; - GETLONG(orig_ttl, p); -- p +=3D 8; /* sig_expiration, sig_inception already checked */ -+ GETLONG(sig_expiration, p); -+ GETLONG(sig_inception, p); - GETSHORT(key_tag, p); - =20 - if (!extract_name(header, plen, &p, keyname, 1, 0)) - return STAT_BOGUS; -=20 -- if (!(hash =3D hash_find(algo_digest_name(algo))) || -+ if (!check_date_range(sig_inception, sig_expiration) || -+ labels > name_labels || -+ !(hash =3D hash_find(algo_digest_name(algo))) || - !hash_init(hash, &ctx, &digest)) - continue; - =20 -@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_head= er *header, size_t plen, ch - else - { - a.addr.keytag =3D 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 keyta= g %u"); -+ else -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keyta= g %u (not supported)"); - =20 - recp1->addr.key.keylen =3D rdlen - 4; - recp1->addr.key.keydata =3D key; -@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct dns_header = *header, size_t plen, char - else - { - a.addr.keytag =3D 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 (no= t supported)"); -+ =20 - crecp->addr.ds.digest =3D digest; - crecp->addr.ds.keydata =3D key; - crecp->addr.ds.algo =3D algo; -@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct dns_header= *header, size_t plen, uns - *nons =3D 1; - =20 - /* Look though the NSEC3 records to find the first one with=20 -- an algorithm we support (currently only algo =3D=3D 1). -+ an algorithm we support. -=20 - Take the algo, iterations, and salt of that record - as the ones we're going to use, and prune any=20 -@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct dns_header= *header, size_t plen, uns - p +=3D 10; /* type, class, TTL, rdlen */ - algo =3D *p++; - =20 -- if (algo =3D=3D 1) -+ if ((hash =3D hash_find(nsec3_digest_name(algo)))) - break; /* known algo */ - } -=20 -@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_heade= r *header, size_t plen, uns - nsecs[i] =3D nsec3p; - } -=20 -- /* Algo is checked as 1 above */ -- if (!(hash =3D hash_find("sha1"))) -- return 0; -- - if ((digest_len =3D hash_name(name, &digest, hash, salt, salt_len, iterat= ions)) =3D=3D 0) - return 0; - =20 -@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *hea= der, size_t plen, char *key - =20 - if (type_found =3D=3D T_NSEC) - return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, dae= mon->workspacename, keyname, name, qtype, nons); -- else -+ else if (type_found =3D=3D T_NSEC3) - return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, da= emon->workspacename, keyname, name, qtype, wildname, nons); -+ else -+ return 0; - } -=20 - /* Check signing status of name. -@@ -1857,7 +1866,7 @@ static int prove_non_existence(struct dns_header *head= er, size_t plen, char *key - */ - static int zone_status(char *name, int class, char *keyname, time_t now) - { -- int secure_ds, name_start =3D strlen(name); -+ int name_start =3D strlen(name); - struct crec *crecp; - char *p; - =20 -@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *= keyname, time_t now) - =20 - if (!(crecp =3D cache_find_by_name(NULL, keyname, now, F_DS))) - return STAT_NEED_DS; -+ =20 -+ /* F_DNSSECOK misused in DS cache records to non-existance of NS rec= ord. -+ 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 =3D 0; -- =20 -+ int gotone =3D 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=20 - { -- if (crecp->uid =3D=3D (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 st= art -- 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. -- */ =20 -- 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_f= unc(crecp->addr.ds.algo)) -- return STAT_INSECURE; /* algo we can't use - insecure */ -- else -- secure_ds =3D 1; -- } -+ if (crecp->uid =3D=3D (unsigned int)class && -+ hash_find(ds_digest_name(crecp->addr.ds.digest)) && -+ verify_func(crecp->addr.ds.algo)) -+ gotone =3D 1; - } - while ((crecp =3D 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 zo= ne, so we believe -- that RRset is good. Furthermore the DNSKEY whose hash is proved by th= e DS record is -- one we can use. However the DNSKEY RRset may contain more than one ke= y and -- one of the other keys may use an algorithm we don't support. If that'= s=20 -- the case the zone is insecure for us. */ -- =20 -- if (!(crecp =3D cache_find_by_name(NULL, keyname, now, F_DNSKEY))) -- return STAT_NEED_KEY; -=20 -- do=20 -- { -- if (crecp->uid =3D=3D (unsigned int)class && !verify_func(crecp->add= r.key.algo)) -- return STAT_INSECURE; -- } -- while ((crecp =3D cache_find_by_name(crecp, keyname, now, F_DNSKEY))); -+ if (!gotone) -+ return STAT_INSECURE; - } -=20 - if (name_start =3D=3D 0) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNS= SEC_hostname_cmp.patch b/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-b= y-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_hos= tname_cmp.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -Date: Sun, 20 Dec 2015 20:50:05 +0000 -Subject: [PATCH] Nasty, rare and obscure off-by-one in DNSSEC hostname_cmp(). - ---- - src/dnssec.c | 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 =3D=3D b) - return 1; - =20 -- ea =3D sa--; -- eb =3D sb--; -+ ea =3D --sa; -+ eb =3D --sb; - } - } -=20 ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch b/s= rc/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 -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 *ke= yname, time_t now) - } - else - { -- int gotone =3D 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 =3D=3D (unsigned int)class && - hash_find(ds_digest_name(crecp->addr.ds.digest)) && - verify_func(crecp->addr.ds.algo)) -- gotone =3D 1; -+ break; - } - while ((crecp =3D cache_find_by_name(crecp, keyname, now, F_DS))); -=20 -- if (!gotone) -+ if (!crecp) - return STAT_INSECURE; - } -=20 ---=20 -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 -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 =3D 0; i < nsec_count; i++) - { - unsigned char *nsec3p =3D nsecs[i]; -- int this_iter; -+ int this_iter, flags; -=20 - nsecs[i] =3D NULL; /* Speculative, will be restored if OK. */ - =20 -@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct dns_heade= r *header, size_t plen, uns - if (*p++ !=3D algo) - continue; - =20 -- p++; /* flags */ -+ flags =3D *p++; /* flags */ - =20 -+ /* 5155 8.2 */ -+ if (flags !=3D 0 && flags !=3D 1) -+ continue; -+ - GETSHORT(this_iter, p); - if (this_iter !=3D iterations) - continue; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/030-Split_EDNS0_stuff_into_its_own_source_fi= le.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 -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 =3D cache.o rfc1035.o util.o option.o forward.o netwo= rk.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 -=20 - hdrs =3D 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 :=3D 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 -=20 - LOCAL_MODULE :=3D dnsmasq -=20 -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 *bu= ff); - size_t resize_packet(struct dns_header *header, size_t plen,=20 - unsigned char *pheader, size_t hlen); --size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -- 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 m= ysockaddr *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 *pse= udoheader, union mysockaddr *peer); - int add_resource_record(struct dns_header *header, char *limit, int *truncp, - int nameoffset, unsigned char **pp, unsigned long ttl,=20 - int *offset, unsigned short type, unsigned short class, char *format, ..= .); -@@ -1521,3 +1513,12 @@ size_t rrfilter(struct dns_header *header, size_t ple= n, int mode); - u16 *rrfilter_desc(int type); - int expand_workspace(unsigned char ***wkspc, int *szp, int new); -=20 -+/* edns0.c */ -+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -+ 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 m= ysockaddr *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 *pse= udoheader, 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. -+=20 -+ 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. -+ =20 -+ You should have received a copy of the GNU General Public License -+ along with this program. If not, see . -+*/ -+ -+#include "dnsmasq.h" -+ -+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, si= ze_t *len, unsigned char **p, int *is_sign) -+{ -+ /* See if packet has an RFC2671 pseudoheader, and if so return a pointer = to it.=20 -+ 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) */ -+ =20 -+ int i, arcount =3D ntohs(header->arcount); -+ unsigned char *ansp =3D (unsigned char *)(header+1); -+ unsigned short rdlen, type, class; -+ unsigned char *ret =3D NULL; -+ -+ if (is_sign) -+ { -+ *is_sign =3D 0; -+ -+ if (OPCODE(header) =3D=3D QUERY) -+ { -+ for (i =3D ntohs(header->qdcount); i !=3D 0; i--) -+ { -+ if (!(ansp =3D skip_name(ansp, header, plen, 4))) -+ return NULL; -+ =20 -+ GETSHORT(type, ansp);=20 -+ GETSHORT(class, ansp); -+ =20 -+ if (class =3D=3D C_IN && type =3D=3D T_TKEY) -+ *is_sign =3D 1; -+ } -+ } -+ } -+ else -+ { -+ if (!(ansp =3D skip_questions(header, plen))) -+ return NULL; -+ } -+ =20 -+ if (arcount =3D=3D 0) -+ return NULL; -+ =20 -+ if (!(ansp =3D skip_section(ansp, ntohs(header->ancount) + ntohs(header->= nscount), header, plen))) -+ return NULL;=20 -+ =20 -+ for (i =3D 0; i < arcount; i++) -+ { -+ unsigned char *save, *start =3D ansp; -+ if (!(ansp =3D skip_name(ansp, header, plen, 10))) -+ return NULL;=20 -+ -+ GETSHORT(type, ansp); -+ save =3D ansp; -+ GETSHORT(class, ansp); -+ ansp +=3D 4; /* TTL */ -+ GETSHORT(rdlen, ansp); -+ if (!ADD_RDLEN(header, ansp, plen, rdlen)) -+ return NULL; -+ if (type =3D=3D T_OPT) -+ { -+ if (len) -+ *len =3D ansp - start; -+ if (p) -+ *p =3D save; -+ ret =3D start; -+ } -+ else if (is_sign &&=20 -+ i =3D=3D arcount - 1 &&=20 -+ class =3D=3D C_ANY &&=20 -+ type =3D=3D T_TSIG) -+ *is_sign =3D 1; -+ } -+ =20 -+ return ret; -+} -+ -+struct macparm { -+ unsigned char *limit; -+ struct dns_header *header; -+ size_t plen; -+ union mysockaddr *l3; -+}; -+=20 -+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -+ unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int= set_do) -+{=20 -+ unsigned char *lenp, *datap, *p; -+ int rdlen, is_sign; -+ =20 -+ if (!(p =3D find_pseudoheader(header, plen, NULL, NULL, &is_sign))) -+ { -+ if (is_sign) -+ return plen; -+ -+ /* We are adding the pseudoheader */ -+ if (!(p =3D skip_questions(header, plen)) || -+ !(p =3D skip_section(p,=20 -+ ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arc= ount),=20 -+ header, plen))) -+ return plen; -+ *p++ =3D 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 =3D p; -+ PUTSHORT(0, p); /* RDLEN */ -+ rdlen =3D 0; -+ if (((ssize_t)optlen) > (limit - (p + 4))) -+ return plen; /* Too big */ -+ header->arcount =3D htons(ntohs(header->arcount) + 1); -+ datap =3D p; -+ } -+ else -+ { -+ int i; -+ unsigned short code, len, flags; -+ =20 -+ /* Must be at the end, if exists */ -+ if (ntohs(header->arcount) !=3D 1 || -+ is_sign || -+ (!(p =3D skip_name(p, header, plen, 10)))) -+ return plen; -+ =20 -+ p +=3D 6; /* skip UDP length and RCODE */ -+ GETSHORT(flags, p); -+ if (set_do) -+ { -+ p -=3D2; -+ PUTSHORT(flags | 0x8000, p); -+ } -+ -+ lenp =3D p; -+ GETSHORT(rdlen, p); -+ if (!CHECK_LEN(header, p, plen, rdlen)) -+ return plen; /* bad packet */ -+ datap =3D p; -+ -+ /* no option to add */ -+ if (optno =3D=3D 0) -+ return plen; -+ =20 -+ /* check if option already there */ -+ for (i =3D 0; i + 4 < rdlen; i +=3D len + 4) -+ { -+ GETSHORT(code, p); -+ GETSHORT(len, p); -+ if (code =3D=3D optno) -+ return plen; -+ p +=3D len; -+ } -+ =20 -+ if (((ssize_t)optlen) > (limit - (p + 4))) -+ return plen; /* Too big */ -+ } -+ =20 -+ if (optno !=3D 0) -+ { -+ PUTSHORT(optno, p); -+ PUTSHORT(optlen, p); -+ memcpy(p, opt, optlen); -+ p +=3D optlen; =20 -+ } -+ -+ PUTSHORT(p - datap, lenp); -+ return p - (unsigned char *)header; -+ =20 -+} -+ -+static int filter_mac(int family, char *addrp, char *mac, size_t maclen, vo= id *parmv) -+{ -+ struct macparm *parm =3D parmv; -+ int match =3D 0; -+ =20 -+ if (family =3D=3D parm->l3->sa.sa_family) -+ { -+ if (family =3D=3D AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, IN= ADDRSZ) =3D=3D 0) -+ match =3D 1; -+#ifdef HAVE_IPV6 -+ else -+ if (family =3D=3D AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6A= DDRSZ) =3D=3D 0) -+ match =3D 1; -+#endif -+ } -+=20 -+ if (!match) -+ return 1; /* continue */ -+ -+ parm->plen =3D add_pseudoheader(parm->header, parm->plen, parm->limit, PA= CKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); -+ =20 -+ return 0; /* done */ -+} =20 -+ =20 -+size_t add_mac(struct dns_header *header, size_t plen, char *limit, union m= ysockaddr *l3) -+{ -+ struct macparm parm; -+ =20 -+ parm.header =3D header; -+ parm.limit =3D (unsigned char *)limit; -+ parm.plen =3D plen; -+ parm.l3 =3D l3; -+ -+ iface_enumerate(AF_UNSPEC, &parm, filter_mac); -+ =20 -+ return parm.plen;=20 -+} -+ -+struct subnet_opt { -+ u16 family; -+ u8 source_netmask, scope_netmask; -+#ifdef HAVE_IPV6=20 -+ u8 addr[IN6ADDRSZ]; -+#else -+ u8 addr[INADDRSZ]; -+#endif -+}; -+ -+static void *get_addrp(union mysockaddr *addr, const short family)=20 -+{ -+#ifdef HAVE_IPV6 -+ if (family =3D=3D 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 *sou= rce) -+{ -+ /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ -+ =20 -+ int len; -+ void *addrp; -+ int sa_family =3D source->sa.sa_family; -+ -+#ifdef HAVE_IPV6 -+ if (source->sa.sa_family =3D=3D AF_INET6) -+ { -+ opt->source_netmask =3D daemon->add_subnet6->mask; -+ if (daemon->add_subnet6->addr_used)=20 -+ { -+ sa_family =3D daemon->add_subnet6->addr.sa.sa_family; -+ addrp =3D get_addrp(&daemon->add_subnet6->addr, sa_family); -+ }=20 -+ else=20 -+ addrp =3D &source->in6.sin6_addr; -+ } -+ else -+#endif -+ { -+ opt->source_netmask =3D daemon->add_subnet4->mask; -+ if (daemon->add_subnet4->addr_used) -+ { -+ sa_family =3D daemon->add_subnet4->addr.sa.sa_family; -+ addrp =3D get_addrp(&daemon->add_subnet4->addr, sa_family); -+ }=20 -+ else=20 -+ addrp =3D &source->in.sin_addr; -+ } -+ =20 -+ opt->scope_netmask =3D 0; -+ len =3D 0; -+ =20 -+ if (opt->source_netmask !=3D 0) -+ { -+#ifdef HAVE_IPV6 -+ opt->family =3D htons(sa_family =3D=3D AF_INET6 ? 2 : 1); -+#else -+ opt->family =3D htons(1); -+#endif -+ len =3D ((opt->source_netmask - 1) >> 3) + 1; -+ memcpy(opt->addr, addrp, len); -+ if (opt->source_netmask & 7) -+ opt->addr[len-1] &=3D 0xff << (8 - (opt->source_netmask & 7)); -+ } -+ -+ return len + 4; -+} -+=20 -+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 */ -+ =20 -+ int len; -+ struct subnet_opt opt; -+ =20 -+ len =3D calc_subnet_opt(&opt, source); -+ return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, E= DNS0_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 *pse= udoheader, 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; -+ =20 -+ calc_len =3D calc_subnet_opt(&opt, peer); -+ =20 -+ if (!(p =3D skip_name(pseudoheader, header, plen, 10))) -+ return 1; -+ =20 -+ p +=3D 8; /* skip UDP length and RCODE */ -+ =20 -+ GETSHORT(rdlen, p); -+ if (!CHECK_LEN(header, p, plen, rdlen)) -+ return 1; /* bad packet */ -+ =20 -+ /* check if option there */ -+ for (i =3D 0; i + 4 < rdlen; i +=3D len + 4) -+ { -+ GETSHORT(code, p); -+ GETSHORT(len, p); -+ if (code =3D=3D EDNS0_OPTION_CLIENT_SUBNET) -+ { -+ /* make sure this doesn't mismatch. */ -+ opt.scope_netmask =3D p[3]; -+ if (len !=3D calc_len || memcmp(p, &opt, len) !=3D 0) -+ return 0; -+ } -+ p +=3D len; -+ } -+ =20 -+ 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; - } -=20 --unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, si= ze_t *len, unsigned char **p, int *is_sign) --{ -- /* See if packet has an RFC2671 pseudoheader, and if so return a pointer = to it.=20 -- 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) */ -- =20 -- int i, arcount =3D ntohs(header->arcount); -- unsigned char *ansp =3D (unsigned char *)(header+1); -- unsigned short rdlen, type, class; -- unsigned char *ret =3D NULL; -- -- if (is_sign) -- { -- *is_sign =3D 0; -- -- if (OPCODE(header) =3D=3D QUERY) -- { -- for (i =3D ntohs(header->qdcount); i !=3D 0; i--) -- { -- if (!(ansp =3D skip_name(ansp, header, plen, 4))) -- return NULL; -- =20 -- GETSHORT(type, ansp);=20 -- GETSHORT(class, ansp); -- =20 -- if (class =3D=3D C_IN && type =3D=3D T_TKEY) -- *is_sign =3D 1; -- } -- } -- } -- else -- { -- if (!(ansp =3D skip_questions(header, plen))) -- return NULL; -- } -- =20 -- if (arcount =3D=3D 0) -- return NULL; -- =20 -- if (!(ansp =3D skip_section(ansp, ntohs(header->ancount) + ntohs(header->= nscount), header, plen))) -- return NULL;=20 -- =20 -- for (i =3D 0; i < arcount; i++) -- { -- unsigned char *save, *start =3D ansp; -- if (!(ansp =3D skip_name(ansp, header, plen, 10))) -- return NULL;=20 -- -- GETSHORT(type, ansp); -- save =3D ansp; -- GETSHORT(class, ansp); -- ansp +=3D 4; /* TTL */ -- GETSHORT(rdlen, ansp); -- if (!ADD_RDLEN(header, ansp, plen, rdlen)) -- return NULL; -- if (type =3D=3D T_OPT) -- { -- if (len) -- *len =3D ansp - start; -- if (p) -- *p =3D save; -- ret =3D start; -- } -- else if (is_sign &&=20 -- i =3D=3D arcount - 1 &&=20 -- class =3D=3D C_ANY &&=20 -- type =3D=3D T_TSIG) -- *is_sign =3D 1; -- } -- =20 -- return ret; --} -- --struct macparm { -- unsigned char *limit; -- struct dns_header *header; -- size_t plen; -- union mysockaddr *l3; --}; --=20 --size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -- unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int= set_do) --{=20 -- unsigned char *lenp, *datap, *p; -- int rdlen, is_sign; -- =20 -- if (!(p =3D find_pseudoheader(header, plen, NULL, NULL, &is_sign))) -- { -- if (is_sign) -- return plen; -- -- /* We are adding the pseudoheader */ -- if (!(p =3D skip_questions(header, plen)) || -- !(p =3D skip_section(p,=20 -- ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arc= ount),=20 -- header, plen))) -- return plen; -- *p++ =3D 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 =3D p; -- PUTSHORT(0, p); /* RDLEN */ -- rdlen =3D 0; -- if (((ssize_t)optlen) > (limit - (p + 4))) -- return plen; /* Too big */ -- header->arcount =3D htons(ntohs(header->arcount) + 1); -- datap =3D p; -- } -- else -- { -- int i; -- unsigned short code, len, flags; -- =20 -- /* Must be at the end, if exists */ -- if (ntohs(header->arcount) !=3D 1 || -- is_sign || -- (!(p =3D skip_name(p, header, plen, 10)))) -- return plen; -- =20 -- p +=3D 6; /* skip UDP length and RCODE */ -- GETSHORT(flags, p); -- if (set_do) -- { -- p -=3D2; -- PUTSHORT(flags | 0x8000, p); -- } -- -- lenp =3D p; -- GETSHORT(rdlen, p); -- if (!CHECK_LEN(header, p, plen, rdlen)) -- return plen; /* bad packet */ -- datap =3D p; -- -- /* no option to add */ -- if (optno =3D=3D 0) -- return plen; -- =20 -- /* check if option already there */ -- for (i =3D 0; i + 4 < rdlen; i +=3D len + 4) -- { -- GETSHORT(code, p); -- GETSHORT(len, p); -- if (code =3D=3D optno) -- return plen; -- p +=3D len; -- } -- =20 -- if (((ssize_t)optlen) > (limit - (p + 4))) -- return plen; /* Too big */ -- } -- =20 -- if (optno !=3D 0) -- { -- PUTSHORT(optno, p); -- PUTSHORT(optlen, p); -- memcpy(p, opt, optlen); -- p +=3D optlen; =20 -- } -- -- PUTSHORT(p - datap, lenp); -- return p - (unsigned char *)header; -- =20 --} -- --static int filter_mac(int family, char *addrp, char *mac, size_t maclen, vo= id *parmv) --{ -- struct macparm *parm =3D parmv; -- int match =3D 0; -- =20 -- if (family =3D=3D parm->l3->sa.sa_family) -- { -- if (family =3D=3D AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, IN= ADDRSZ) =3D=3D 0) -- match =3D 1; --#ifdef HAVE_IPV6 -- else -- if (family =3D=3D AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6A= DDRSZ) =3D=3D 0) -- match =3D 1; --#endif -- } --=20 -- if (!match) -- return 1; /* continue */ -- -- parm->plen =3D add_pseudoheader(parm->header, parm->plen, parm->limit, PA= CKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); -- =20 -- return 0; /* done */ --} =20 -- =20 --size_t add_mac(struct dns_header *header, size_t plen, char *limit, union m= ysockaddr *l3) --{ -- struct macparm parm; -- =20 -- parm.header =3D header; -- parm.limit =3D (unsigned char *)limit; -- parm.plen =3D plen; -- parm.l3 =3D l3; -- -- iface_enumerate(AF_UNSPEC, &parm, filter_mac); -- =20 -- return parm.plen;=20 --} -- --struct subnet_opt { -- u16 family; -- u8 source_netmask, scope_netmask; --#ifdef HAVE_IPV6=20 -- u8 addr[IN6ADDRSZ]; --#else -- u8 addr[INADDRSZ]; --#endif --}; -- --static void *get_addrp(union mysockaddr *addr, const short family)=20 --{ --#ifdef HAVE_IPV6 -- if (family =3D=3D 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 *sou= rce) --{ -- /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ -- =20 -- int len; -- void *addrp; -- int sa_family =3D source->sa.sa_family; -- --#ifdef HAVE_IPV6 -- if (source->sa.sa_family =3D=3D AF_INET6) -- { -- opt->source_netmask =3D daemon->add_subnet6->mask; -- if (daemon->add_subnet6->addr_used)=20 -- { -- sa_family =3D daemon->add_subnet6->addr.sa.sa_family; -- addrp =3D get_addrp(&daemon->add_subnet6->addr, sa_family); -- }=20 -- else=20 -- addrp =3D &source->in6.sin6_addr; -- } -- else --#endif -- { -- opt->source_netmask =3D daemon->add_subnet4->mask; -- if (daemon->add_subnet4->addr_used) -- { -- sa_family =3D daemon->add_subnet4->addr.sa.sa_family; -- addrp =3D get_addrp(&daemon->add_subnet4->addr, sa_family); -- }=20 -- else=20 -- addrp =3D &source->in.sin_addr; -- } -- =20 -- opt->scope_netmask =3D 0; -- len =3D 0; -- =20 -- if (opt->source_netmask !=3D 0) -- { --#ifdef HAVE_IPV6 -- opt->family =3D htons(sa_family =3D=3D AF_INET6 ? 2 : 1); --#else -- opt->family =3D htons(1); --#endif -- len =3D ((opt->source_netmask - 1) >> 3) + 1; -- memcpy(opt->addr, addrp, len); -- if (opt->source_netmask & 7) -- opt->addr[len-1] &=3D 0xff << (8 - (opt->source_netmask & 7)); -- } -- -- return len + 4; --} --=20 --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 */ -- =20 -- int len; -- struct subnet_opt opt; -- =20 -- len =3D calc_subnet_opt(&opt, source); -- return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, E= DNS0_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 *pse= udoheader, 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; -- =20 -- calc_len =3D calc_subnet_opt(&opt, peer); -- =20 -- if (!(p =3D skip_name(pseudoheader, header, plen, 10))) -- return 1; -- =20 -- p +=3D 8; /* skip UDP length and RCODE */ -- =20 -- GETSHORT(rdlen, p); -- if (!CHECK_LEN(header, p, plen, rdlen)) -- return 1; /* bad packet */ -- =20 -- /* check if option there */ -- for (i =3D 0; i + 4 < rdlen; i +=3D len + 4) -- { -- GETSHORT(code, p); -- GETSHORT(len, p); -- if (code =3D=3D EDNS0_OPTION_CLIENT_SUBNET) -- { -- /* make sure this doesn't mismatch. */ -- opt.scope_netmask =3D p[3]; -- if (len !=3D calc_len || memcmp(p, &opt, len) !=3D 0) -- return 0; -- } -- p +=3D len; -- } -- =20 -- return 1; --} -- - /* is addr in the non-globally-routed IP space? */=20 - int private_net(struct in_addr addr, int ban_localhost)=20 - { ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/031-Handle_extending_EDNS0_OPT_RR.patch b/sr= c/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 -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,=20 - struct bogus_addr *addr, time_t now); - int check_for_ignored_address(struct dns_header *header, size_t qlen, struc= t 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 *bu= ff); - size_t resize_packet(struct dns_header *header, size_t plen,=20 -@@ -1514,6 +1512,8 @@ u16 *rrfilter_desc(int type); - int expand_workspace(unsigned char ***wkspc, int *szp, int new); -=20 - /* 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 ch= ar *limit,=20 - 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 m= ysockaddr *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 -=20 - ret =3D add_do_bit(header, p - (unsigned char *)header, end); -=20 -- if (find_pseudoheader(header, ret, NULL, &p, NULL)) -+ if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL)) - PUTSHORT(edns_pktsz, p); -=20 - 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 @@ -=20 - #include "dnsmasq.h" -=20 --unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, si= ze_t *len, unsigned char **p, int *is_sign) -+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, si= ze_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.=20 - 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) */ - =20 - int i, arcount =3D ntohs(header->arcount); - unsigned char *ansp =3D (unsigned char *)(header+1); -@@ -76,8 +76,13 @@ unsigned char *find_pseudoheader(struct dns_header *heade= r, size_t plen, size_t - { - if (len) - *len =3D ansp - start; -+ - if (p) - *p =3D save; -+ =20 -+ if (is_last) -+ *is_last =3D (i =3D=3D arcount-1); -+ - ret =3D start; - } - else if (is_sign &&=20 -@@ -100,50 +105,31 @@ struct macparm { - size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 - unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int= set_do) - {=20 -- unsigned char *lenp, *datap, *p; -- int rdlen, is_sign; -+ unsigned char *lenp, *datap, *p, *udp_len, *buff =3D NULL; -+ int rdlen =3D 0, is_sign, is_last; -+ unsigned short flags =3D set_do ? 0x8000 : 0, rcode =3D 0; -+ -+ p =3D find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last); - =20 -- if (!(p =3D find_pseudoheader(header, plen, NULL, NULL, &is_sign))) -- { -- if (is_sign) -- return plen; -+ if (is_sign) -+ return plen; -=20 -- /* We are adding the pseudoheader */ -- if (!(p =3D skip_questions(header, plen)) || -- !(p =3D skip_section(p,=20 -- ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arc= ount),=20 -- header, plen))) -- return plen; -- *p++ =3D 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 =3D p; -- PUTSHORT(0, p); /* RDLEN */ -- rdlen =3D 0; -- if (((ssize_t)optlen) > (limit - (p + 4))) -- return plen; /* Too big */ -- header->arcount =3D htons(ntohs(header->arcount) + 1); -- datap =3D p; -- } -- else -+ if (p) - { -+ /* Existing header */ - int i; -- unsigned short code, len, flags; -- =20 -- /* Must be at the end, if exists */ -- if (ntohs(header->arcount) !=3D 1 || -- is_sign || -- (!(p =3D skip_name(p, header, plen, 10)))) -- return plen; -- =20 -- p +=3D 6; /* skip UDP length and RCODE */ -+ unsigned short code, len; -+ -+ p =3D udp_len; -+ GETSHORT(udp_sz, p); -+ GETSHORT(rcode, p); - GETSHORT(flags, p); -+ - if (set_do) - { - p -=3D2; -- PUTSHORT(flags | 0x8000, p); -+ flags |=3D 0x8000; -+ PUTSHORT(flags, p); - } -=20 - lenp =3D p; -@@ -165,22 +151,61 @@ size_t add_pseudoheader(struct dns_header *header, siz= e_t plen, unsigned char *l - return plen; - p +=3D len; - } -- =20 -- 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 p= acket */ -+ if (!is_last) -+ { -+ /* First, take a copy of the options. */ -+ if (rdlen !=3D 0 && (buff =3D whine_malloc(rdlen))) -+ memcpy(buff, datap, rdlen); =20 -+ =20 -+ /* now, delete OPT RR */ -+ plen =3D rrfilter(header, plen, 0); -+ =20 -+ /* Now, force addition of a new one */ -+ p =3D NULL; =20 -+ } -+ } -+ =20 -+ if (!p) -+ { -+ /* We are (re)adding the pseudoheader */ -+ if (!(p =3D skip_questions(header, plen)) || -+ !(p =3D skip_section(p,=20 -+ ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arc= ount),=20 -+ header, plen))) -+ return plen; -+ *p++ =3D 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 =3D p; -+ PUTSHORT(rdlen, p); /* RDLEN */ -+ datap =3D p; -+ /* Copy back any options */ -+ if (buff) -+ { -+ memcpy(p, buff, rdlen); -+ free(buff); -+ p +=3D rdlen; -+ } -+ header->arcount =3D htons(ntohs(header->arcount) + 1); - } - =20 -+ if (((ssize_t)optlen) > (limit - (p + 4))) -+ return plen; /* Too big */ -+ =20 -+ /* Add new option */ - if (optno !=3D 0) - { - PUTSHORT(optno, p); - PUTSHORT(optlen, p); - memcpy(p, opt, optlen); - p +=3D optlen; =20 -+ PUTSHORT(p - datap, lenp); - } -- -- PUTSHORT(p - datap, lenp); - return p - (unsigned char *)header; -- =20 - } -=20 - static int filter_mac(int family, char *addrp, char *mac, size_t maclen, vo= id *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 *ud= paddr, - blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); - plen =3D forward->stash_len; - =20 -- if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sig= n) -+ if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && != is_sign) - PUTSHORT(SAFE_PKTSZ, pheader); -=20 - if (forward->sentto->addr.sa.sa_family =3D=3D AF_INET)=20 -@@ -479,7 +479,7 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, - } - =20 - #ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID) && !do_bit) -+ if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PH= EADER)) - { - /* Difficult one here. If our client didn't send EDNS0, we will have se= t the UDP - packet size to 512. But that won't provide space for the RRSIGS in m= any cases. -@@ -489,7 +489,7 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, - the truncated bit? */ =20 - 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, t= ime_t now, struct server - } - #endif - =20 -- if ((pheader =3D find_pseudoheader(header, n, &plen, &sizep, &is_sign))) -+ if ((pheader =3D find_pseudoheader(header, n, &plen, &sizep, &is_sign, NU= LL))) - { - 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; - =20 - /* recreate query from reply */ -- pheader =3D find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sig= n); -+ pheader =3D find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sig= n, NULL); - if (!is_sign) - { - header->ancount =3D htons(0); -@@ -1313,7 +1313,7 @@ void receive_query(struct listener *listen, time_t now) - #endif - } - =20 -- if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL)) -+ if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL)) - {=20 - unsigned short flags; - =20 -@@ -1569,7 +1569,7 @@ unsigned char *tcp_request(int confd, time_t now, - =20 - do_bit =3D 0; -=20 -- if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL)) -+ if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NUL= L)) - {=20 - unsigned short flags; - =20 -@@ -1578,7 +1578,7 @@ unsigned char *tcp_request(int confd, time_t now, - GETSHORT(flags, pheader); - =20 - if (flags & 0x8000) -- do_bit =3D 1;/* do bit */=20 -+ do_bit =3D 1; /* do bit */=20 - } -=20 - #ifdef HAVE_AUTH ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/032-Truncate_DNS_replies_bigger_512_bytes_th= at_the_client_isnt_expecting.patch b/src/patches/dnsmasq/032-Truncate_DNS_rep= lies_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 -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 *pse= udoheader, union mysockaddr *peer) - { - /* Section 9.2, Check that subnet option in reply matches. */ -- -- -- int len, calc_len; -+ =20 -+ 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 *ud= paddr, - packet size to 512. But that won't provide space for the RRSIGS in m= any 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 stri= pping and set -- the truncated bit? */ =20 -+ known to be OK for this server. We check returned size after strippi= ng and set -+ the truncated bit if it's still too big. */ =20 - 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 =3D htons(forward->orig_id); - header->hb4 |=3D HB4_RA; /* recursion if available */ -+#ifdef HAVE_DNSSEC -+ /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and s= et 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 m= ark it so. The client then retries with TCP. */ -+ if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADE= R) && (nn > PACKETSZ)) -+ { -+ header->ancount =3D htons(0); -+ header->nscount =3D htons(0); -+ header->arcount =3D htons(0); -+ header->hb3 |=3D HB3_TC; -+ nn =3D resize_packet(header, nn, NULL, 0); -+ } -+#endif - send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVE= RBIND), daemon->packet, nn,=20 - &forward->source, &forward->dest, forward->iface); - } ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/033-Fix_build_failure_when_DNSSEC_code_omitt= ed.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 -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, siz= e_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 m= ysockaddr *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 *pse= udoheader, 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; - } -=20 -+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, vo= id *parmv) - { - struct macparm *parm =3D 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, E= DNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); - } -=20 --#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 *pse= udoheader, union mysockaddr *peer) - { - /* Section 9.2, Check that subnet option in reply matches. */ ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/034-Log_signature_algo_with_DNSKEY_and_DS_al= so_digest_with_DS.patch b/src/patches/dnsmasq/034-Log_signature_algo_with_DNS= KEY_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_dige= st_with_DS.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 15379ea1f252d1f53c5d93ae970b22dedb233642 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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;=20 -+ /* for cache_insert of DNSKEY, DS */ - struct { - unsigned short class, type; - } dnssec; =20 -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_hea= der *header, size_t plen, ch - } - else - { -- a.addr.keytag =3D keytag; -+ a.addr.log.keytag =3D keytag; -+ a.addr.log.algo =3D algo; - if (verify_func(algo)) -- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keyta= g %u"); -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keyta= g %hu, algo %hu"); - else -- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keyta= g %u (not supported)"); -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keyta= g %hu, algo %hu (not supported)"); - =20 - recp1->addr.key.keylen =3D rdlen - 4; - recp1->addr.key.keydata =3D key; -@@ -1241,11 +1242,13 @@ int dnssec_validate_ds(time_t now, struct dns_header= *header, size_t plen, char - } - else - { -- a.addr.keytag =3D keytag; -+ a.addr.log.keytag =3D keytag; -+ a.addr.log.algo =3D algo; -+ a.addr.log.digest =3D 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, a= lgo %hu, digest %hu"); - else -- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (no= t supported)"); -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, a= lgo %hu, digest %hu (not supported)"); - =20 - crecp->addr.ds.digest =3D digest; - crecp->addr.ds.keydata =3D key; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/035-More_EDNS0_packet_size_tweaks.patch b/sr= c/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 -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 =3D PACKETSZ; -=20 -- daemon->packet_buff_sz =3D daemon->edns_pktsz > DNSMASQ_PACKETSZ ?=20 -- daemon->edns_pktsz : DNSMASQ_PACKETSZ; -+ /* Min buffer size: we check after adding each record, so there must be=20 -+ 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 minimu= m. */=20 -+ daemon->packet_buff_sz =3D daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ; - daemon->packet =3D safe_malloc(daemon->packet_buff_sz); - =20 - daemon->addrbuff =3D 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 -=20 --/* Min buffer size: we check after adding each record, so there must be=20 -- 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))) -=20 -@@ -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 =20 -=20 - #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 =3D start; - int forwarded =3D 0; -- =20 -+ size_t edns0_len; -+ - /* If a query is retried, use the log_id for the retry when logging t= he answer. */ - forward->log_id =3D daemon->log_id; - =20 - if (option_bool(OPT_ADD_MAC)) - { -- size_t new =3D add_mac(header, plen, ((char *) header) + daemon->packet_= buff_sz, &forward->source); -+ size_t new =3D add_mac(header, plen, ((char *) header) + PACKETSZ, &forw= ard->source); - if (new !=3D plen) - { - plen =3D new; -@@ -405,7 +406,7 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, -=20 - if (option_bool(OPT_CLIENT_SUBNET)) - { -- size_t new =3D add_source_addr(header, plen, ((char *) header) + daemon-= >packet_buff_sz, &forward->source);=20 -+ size_t new =3D add_source_addr(header, plen, ((char *) header) + PACKETS= Z, &forward->source);=20 - if (new !=3D plen) - { - plen =3D new; -@@ -416,7 +417,7 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, - #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID)) - { -- size_t new =3D add_do_bit(header, plen, ((char *) header) + daemon->pack= et_buff_sz); -+ size_t new =3D add_do_bit(header, plen, ((char *) header) + PACKETSZ); - =20 - if (new !=3D plen) - forward->flags |=3D FREC_ADDED_PHEADER; -@@ -430,6 +431,10 @@ static int forward_query(int udpfd, union mysockaddr *u= dpaddr, -=20 - } - #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 |=3D FREC_HAS_EXTRADATA; - =20 - while (1) - {=20 -@@ -769,9 +774,12 @@ void reply_query(int fd, int family, time_t now) - check_for_ignored_address(header, n, daemon->ignore_addr)) - return; -=20 -+ /* Note: if we send extra options in the EDNS0 header, we can't recreate -+ the query from the reply. */ - if (RCODE(header) =3D=3D REFUSED && - !option_bool(OPT_ORDER) && -- forward->forwardall =3D=3D 0) -+ forward->forwardall =3D=3D 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 =3D=3D STAT_NEED_KEY) - { - new->flags |=3D FREC_DNSKEY_QUERY;=20 -- nn =3D dnssec_generate_query(header, ((char *) header) + daemon->packe= t_buff_sz, -+ nn =3D dnssec_generate_query(header, ((char *) header) + server->edns_= pktsz, - daemon->keyname, forward->class, T_DNSKEY, &server->addr, server= ->edns_pktsz); - } - else=20 - { - new->flags |=3D FREC_DS_QUERY; -- nn =3D dnssec_generate_query(header,((char *) header) + daemon->packet= _buff_sz, -+ nn =3D dnssec_generate_query(header,((char *) header) + server->edns_p= ktsz, - daemon->keyname, forward->class, T_DS, &server->addr, server->ed= ns_pktsz); - } - if ((hash =3D hash_questions(header, nn, daemon->namebuff))) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/036-Cache_access_to_the_kernels_ARP_table.pa= tch 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 -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 =3D cache.o rfc1035.o util.o option.o forward.o netwo= rk.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 -=20 - hdrs =3D 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 :=3D 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 -=20 - LOCAL_MODULE :=3D dnsmasq -=20 -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. -+=20 -+ 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. -+ =20 -+ You should have received a copy of the GNU General Public License -+ along with this program. If not, see . -+*/ -+ -+#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];=20 -+ struct all_addr addr; -+ struct arp_record *next; -+}; -+ -+static struct arp_record *arps =3D NULL, *old =3D NULL; -+ -+static int filter_mac(int family, char *addrp, char *mac, size_t maclen, vo= id *parmv) -+{ -+ int match =3D 0; -+ struct arp_record *arp; -+ -+ if (maclen > DHCP_CHADDR_MAX) -+ return 1; -+ -+ /* Look for existing entry */ -+ for (arp =3D arps; arp; arp =3D arp->next) -+ { -+ if (family !=3D arp->family || arp->status =3D=3D ARP_NEW) -+ continue; -+ =20 -+ if (family =3D=3D AF_INET) -+ { -+ if (arp->addr.addr.addr4.s_addr !=3D ((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 !=3D ARP_EMPTY && arp->hwlen =3D=3D maclen && memcmp(= arp->hwaddr, mac, maclen) =3D=3D 0) -+ arp->status =3D ARP_FOUND; -+ else -+ { -+ /* existing address, MAC changed or arrived new. */ -+ arp->status =3D ARP_NEW; -+ arp->hwlen =3D maclen; -+ arp->family =3D family; -+ memcpy(arp->hwaddr, mac, maclen); -+ } -+ =20 -+ break; -+ } -+ -+ if (!arp) -+ { -+ /* New entry */ -+ if (old) -+ { -+ arp =3D old; -+ old =3D old->next; -+ } -+ else if (!(arp =3D whine_malloc(sizeof(struct arp_record)))) -+ return 1; -+ =20 -+ arp->next =3D arps; -+ arps =3D arp; -+ arp->status =3D ARP_NEW; -+ arp->hwlen =3D maclen; -+ arp->family =3D family; -+ memcpy(arp->hwaddr, mac, maclen); -+ if (family =3D=3D AF_INET) -+ arp->addr.addr.addr4.s_addr =3D ((struct in_addr *)addrp)->s_addr; -+#ifdef HAVE_IPV6 -+ else -+ memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ); -+#endif -+ } -+ =20 -+ 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 =3D 0; -+ -+ again: -+ =20 -+ for (arp =3D arps; arp; arp =3D arp->next) -+ { -+ if (addr->sa.sa_family =3D=3D arp->family) -+ { -+ if (arp->addr.addr.addr4.s_addr !=3D 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 -+ =20 -+ /* Only accept poitive entries unless in lazy mode. */ -+ if (arp->status !=3D ARP_EMPTY || lazy || updated) -+ { -+ if (mac && arp->hwlen !=3D 0) -+ memcpy(mac, arp->hwaddr, arp->hwlen); -+ return arp->hwlen; -+ } -+ } -+ -+ /* Not found, try the kernel */ -+ if (!updated) -+ { -+ updated =3D 1; -+ =20 -+ /* Mark all non-negative entries */ -+ for (arp =3D arps, up =3D &arps; arp; arp =3D arp->next) -+ if (arp->status !=3D ARP_EMPTY) -+ arp->status =3D ARP_FREE; -+ =20 -+ iface_enumerate(AF_UNSPEC, NULL, filter_mac); -+ =20 -+ /* Remove all unconfirmed entries to old list, announce new ones. */ -+ for (arp =3D arps, up =3D &arps; arp; arp =3D arp->next) -+ if (arp->status =3D=3D ARP_FREE) -+ { -+ *up =3D arp->next; -+ arp->next =3D old; -+ old =3D arp; -+ } -+ else -+ { -+ up =3D &arp->next; -+ if (arp->status =3D=3D ARP_NEW) -+ { -+ char a[ADDRSTRLEN], m[ADDRSTRLEN]; -+ union mysockaddr pa; -+ pa.sa.sa_family =3D arp->family; -+ pa.in.sin_addr.s_addr =3D 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 =3D old; -+ old =3D old->next; -+ } -+ else -+ arp =3D whine_malloc(sizeof(struct arp_record)); -+ =20 -+ if (arp) -+ { =20 -+ arp->next =3D arps; -+ arps =3D arp; -+ arp->status =3D ARP_EMPTY; -+ arp->family =3D addr->sa.sa_family; -+ =20 -+ if (addr->sa.sa_family =3D=3D AF_INET) -+ arp->addr.addr.addr4.s_addr =3D addr->in.sin_addr.s_addr; -+#ifdef HAVE_IPV6 -+ else -+ memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ); -+#endif -+ } -+ =20 -+ 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; - }; -=20 --struct mac_param { -- struct in6_addr *target; -- unsigned char *mac; -- unsigned int maclen; --}; -- -=20 - static int complete_context6(struct in6_addr *local, int prefix, - int scope, int if_index, int flags,=20 - 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 macle= n, void *parm);=20 -=20 - 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. */ - =20 - struct neigh_packet neigh; -- struct sockaddr_in6 addr; -- struct mac_param mac_param; -- int i; -+ union mysockaddr addr; -+ int i, maclen; -=20 - neigh.type =3D ND_NEIGHBOR_SOLICIT; - neigh.code =3D 0; -@@ -277,55 +269,31 @@ void get_client_mac(struct in6_addr *client, int iface= , unsigned char *mac, unsi - =20 - memset(&addr, 0, sizeof(addr)); - #ifdef HAVE_SOCKADDR_SA_LEN -- addr.sin6_len =3D sizeof(struct sockaddr_in6); -+ addr.in6.sin6_len =3D sizeof(struct sockaddr_in6); - #endif -- addr.sin6_family =3D AF_INET6; -- addr.sin6_port =3D htons(IPPROTO_ICMPV6); -- addr.sin6_addr =3D *client; -- addr.sin6_scope_id =3D iface; -- =20 -- mac_param.target =3D client; -- mac_param.maclen =3D 0; -- mac_param.mac =3D mac; -+ addr.in6.sin6_family =3D AF_INET6; -+ addr.in6.sin6_port =3D htons(IPPROTO_ICMPV6); -+ addr.in6.sin6_addr =3D *client; -+ addr.in6.sin6_scope_id =3D iface; - =20 - for (i =3D 0; i < 5; i++) - { - struct timespec ts; - =20 -- iface_enumerate(AF_UNSPEC, &mac_param, find_mac); -- =20 -- if (mac_param.maclen !=3D 0) -+ if ((maclen =3D find_mac(&addr, mac, 0)) !=3D 0) - break; -- =20 -- sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)= &addr, sizeof(addr)); -+ =20 -+ sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(ad= dr)); - =20 - ts.tv_sec =3D 0; - ts.tv_nsec =3D 100000000; /* 100ms */ - nanosleep(&ts, NULL); - } -=20 -- *maclenp =3D mac_param.maclen; -+ *maclenp =3D maclen; - *mactypep =3D ARPHRD_ETHER; - } - =20 --static int find_mac(int family, char *addrp, char *mac, size_t maclen, void= *parmv) --{ -- struct mac_param *parm =3D parmv; -- =20 -- if (family =3D=3D AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in= 6_addr *)addrp)) -- { -- if (maclen <=3D DHCP_CHADDR_MAX) -- { -- parm->maclen =3D maclen; -- memcpy(parm->mac, mac, maclen); -- } -- =20 -- return 0; /* found, abort */ -- } -- =20 -- return 1; --} -- - static int complete_context6(struct in6_addr *local, int prefix, - int scope, int if_index, int flags, unsigned int preferred,=20 - 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 *pse= udoheader, 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 pl= en, char *limit) - return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0= , NULL, 0, 1); - } -=20 --static int filter_mac(int family, char *addrp, char *mac, size_t maclen, vo= id *parmv) --{ -- struct macparm *parm =3D parmv; -- int match =3D 0; -- =20 -- if (family =3D=3D parm->l3->sa.sa_family) -- { -- if (family =3D=3D AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, IN= ADDRSZ) =3D=3D 0) -- match =3D 1; --#ifdef HAVE_IPV6 -- else -- if (family =3D=3D AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6A= DDRSZ) =3D=3D 0) -- match =3D 1; --#endif -- } --=20 -- if (!match) -- return 1; /* continue */ -- -- parm->plen =3D add_pseudoheader(parm->header, parm->plen, parm->limit, PA= CKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); -- =20 -- return 0; /* done */ --} =20 -- =20 - size_t add_mac(struct dns_header *header, size_t plen, char *limit, union m= ysockaddr *l3) - { -- struct macparm parm; -- =20 -- parm.header =3D header; -- parm.limit =3D (unsigned char *)limit; -- parm.plen =3D plen; -- parm.l3 =3D l3; -+ int maclen; -+ unsigned char mac[DHCP_CHADDR_MAX]; -=20 -- iface_enumerate(AF_UNSPEC, &parm, filter_mac); -+ if ((maclen =3D find_mac(l3, mac, 1)) !=3D 0) -+ plen =3D add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_M= AC, mac, maclen, 0);=20 - =20 -- return parm.plen;=20 -+ return plen;=20 - } -=20 - struct subnet_opt { ---=20 -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_ve= rsion_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_a= nd_ARP_tracking_code.patch +++ /dev/null @@ -1,976 +0,0 @@ -From 33702ab1f829789183cbaf6b1c39eee7ff15d744 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 @@ -=20 - #include "dnsmasq.h" -=20 --#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 */ -=20 - struct arp_record { -- short hwlen, status; -+ unsigned short hwlen, status; - int family; - unsigned char hwaddr[DHCP_CHADDR_MAX];=20 - struct all_addr addr; - struct arp_record *next; - }; -=20 --static struct arp_record *arps =3D NULL, *old =3D NULL; -+static struct arp_record *arps =3D NULL, *old =3D NULL, *freelist =3D NULL; -+static time_t last =3D 0; -=20 - static int filter_mac(int family, char *addrp, char *mac, size_t maclen, vo= id *parmv) - { -- int match =3D 0; - struct arp_record *arp; -=20 -+ (void)parmv; -+ - if (maclen > DHCP_CHADDR_MAX) - return 1; -=20 -@@ -58,16 +63,18 @@ static int filter_mac(int family, char *addrp, char *mac= , size_t maclen, void *p - } - #endif -=20 -- if (arp->status !=3D ARP_EMPTY && arp->hwlen =3D=3D maclen && memcmp(= arp->hwaddr, mac, maclen) =3D=3D 0) -- arp->status =3D ARP_FOUND; -- else -+ if (arp->status =3D=3D ARP_EMPTY) - { -- /* existing address, MAC changed or arrived new. */ -+ /* existing address, was negative. */ - arp->status =3D ARP_NEW; - arp->hwlen =3D maclen; -- arp->family =3D family; - memcpy(arp->hwaddr, mac, maclen); - } -+ else if (arp->hwlen =3D=3D maclen && memcmp(arp->hwaddr, mac, maclen)= =3D=3D 0) -+ /* Existing entry matches - confirm. */ -+ arp->status =3D ARP_FOUND; -+ else -+ continue; - =20 - 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 =3D old; -- old =3D old->next; -+ arp =3D freelist; -+ freelist =3D freelist->next; - } - else if (!(arp =3D whine_malloc(sizeof(struct arp_record)))) - return 1; -@@ -101,81 +108,72 @@ static int filter_mac(int family, char *addrp, char *m= ac, size_t maclen, void *p - } -=20 - /* 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 n= ow) - { - struct arp_record *arp, **up; - int updated =3D 0; -=20 - again: - =20 -- for (arp =3D arps; arp; arp =3D arp->next) -- { -- if (addr->sa.sa_family =3D=3D arp->family) -- { -- if (arp->addr.addr.addr4.s_addr !=3D 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 =3D arps; arp; arp =3D arp->next) -+ { -+ if (addr->sa.sa_family =3D=3D arp->family) -+ { -+ if (arp->addr.addr.addr4.s_addr !=3D 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 -- =20 -- /* Only accept poitive entries unless in lazy mode. */ -- if (arp->status !=3D ARP_EMPTY || lazy || updated) -- { -- if (mac && arp->hwlen !=3D 0) -- memcpy(mac, arp->hwaddr, arp->hwlen); -- return arp->hwlen; -- } -- } -- -+=09 -+ /* Only accept poitive entries unless in lazy mode. */ -+ if (arp->status !=3D ARP_EMPTY || lazy || updated) -+ { -+ if (mac && arp->hwlen !=3D 0) -+ memcpy(mac, arp->hwaddr, arp->hwlen); -+ return arp->hwlen; -+ } -+ } -+ =20 - /* Not found, try the kernel */ - if (!updated) - { - updated =3D 1; -- =20 -+ last =3D now; -+ - /* Mark all non-negative entries */ - for (arp =3D arps, up =3D &arps; arp; arp =3D arp->next) - if (arp->status !=3D ARP_EMPTY) -- arp->status =3D ARP_FREE; -+ arp->status =3D ARP_MARK; - =20 - iface_enumerate(AF_UNSPEC, NULL, filter_mac); - =20 -- /* Remove all unconfirmed entries to old list, announce new ones. */ -+ /* Remove all unconfirmed entries to old list. */ - for (arp =3D arps, up =3D &arps; arp; arp =3D arp->next) -- if (arp->status =3D=3D ARP_FREE) -+ if (arp->status =3D=3D ARP_MARK) - { - *up =3D arp->next; - arp->next =3D old; - old =3D arp; - } - else -- { -- up =3D &arp->next; -- if (arp->status =3D=3D ARP_NEW) -- { -- char a[ADDRSTRLEN], m[ADDRSTRLEN]; -- union mysockaddr pa; -- pa.sa.sa_family =3D arp->family; -- pa.in.sin_addr.s_addr =3D 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 =3D &arp->next; -+ =20 - goto again; - } -=20 - /* record failure, so we don't consult the kernel each time - we're asked for this address */ -- if (old) -+ if (freelist) - { -- arp =3D old; -- old =3D old->next; -+ arp =3D freelist; -+ freelist =3D freelist->next; - } - else - arp =3D whine_malloc(sizeof(struct arp_record)); -@@ -198,4 +196,36 @@ int find_mac(union mysockaddr *addr, unsigned char *mac= , int lazy) - return 0; - } -=20 -+int do_arp_script_run(void) -+{ -+ struct arp_record *arp; -+ =20 -+ /* 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 =3D old; -+ old =3D arp->next; -+ arp->next =3D freelist; -+ freelist =3D arp; -+ return 1; -+ } -+ -+ for (arp =3D arps; arp; arp =3D arp->next) -+ if (arp->status =3D=3D 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 =3D ARP_FOUND; -+ return 1; -+ } -+ -+ return 0; -+} -+ -=20 -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 -=20 --#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); - =20 - 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, n= ow); - return; - } - =20 -@@ -250,7 +250,7 @@ void dhcp6_packet(time_t now) - } - } -=20 --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=20 -@@ -280,7 +280,7 @@ void get_client_mac(struct in6_addr *client, int iface, = unsigned char *mac, unsi - { - struct timespec ts; - =20 -- if ((maclen =3D find_mac(&addr, mac, 0)) !=3D 0) -+ if ((maclen =3D find_mac(&addr, mac, 0, now)) !=3D 0) - break; - =20 - sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(ad= dr)); -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 @@ -=20 - #define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignmen= t */ - #define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */ -+#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */ -+#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */ -=20 - 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->rela= y6) -+ before lease_init to allocate buffers it uses. -+ The script subsystrm relies on DHCP buffers, hence the last two -+ conditions below. */ =20 -+ if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 ||=20 -+ 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 ro= ot. */ - daemon->helperfd =3D -1; - #ifdef HAVE_SCRIPT=20 -- if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || d= aemon->luascript)) -- daemon->helperfd =3D create_helper(pipewrite, err_pipe[1], script_uid, = script_gid, max_fd); -+ if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_boo= l(OPT_ADD_MAC)) &&=20 -+ (daemon->lease_change_command || daemon->luascript)) -+ daemon->helperfd =3D create_helper(pipewrite, err_pipe[1], script_uid= , script_gid, max_fd); - #endif -=20 - if (!option_bool(OPT_DEBUG) && getuid() =3D=3D 0) =20 -@@ -914,9 +918,9 @@ int main (int argc, char **argv) - =20 - poll_listen(piperead, POLLIN); -=20 --#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));=20 -+ while (helper_buf_empty() && do_arp_script_run()); -=20 - # ifdef HAVE_TFTP - while (helper_buf_empty() && do_tftp_script_run()); -@@ -924,16 +928,17 @@ int main (int argc, char **argv) -=20 - 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)); -=20 - # ifdef HAVE_TFTP=20 - while (do_tftp_script_run()); - # endif -=20 --# endif - #endif -+ - =20 - /* 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 -=20 - /* extra flags for my_syslog, we use a couple of facilities since they are = known=20 - 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 -=20 - #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 -=20 - /* dnssec.c */ --size_t dnssec_generate_query(struct dns_header *header, char *end, char *na= me, 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 ple= n, 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 -=20 -@@ -1408,7 +1414,7 @@ struct dhcp_config *config_find_by_address6(struct dhc= p_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,= =20 -- unsigned int *maclenp, unsigned int *mactypep); -+ unsigned int *maclenp, unsigned int *mactypep, time_t now); - #endif - =20 - /* 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, cha= r *iface_name, =20 - 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,=20 -+ u32 scope_id, time_t now); -=20 - unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *a= rrival_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 ch= ar *limit,=20 - 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 m= ysockaddr *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 *li= mit); -+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -+ union mysockaddr *source, time_t now, int *check_subnet); - int check_source(struct dns_header *header, size_t plen, unsigned char *pse= udoheader, union mysockaddr *peer); -=20 - /* 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 n= ow); -+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 *k= ey, int keylen) - } - } -=20 --size_t dnssec_generate_query(struct dns_header *header, char *end, char *na= me, int class,=20 -+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end,= char *name, int class,=20 - 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 *heade= r, size_t plen, size_t - =20 - return ret; - } -- --struct macparm { -- unsigned char *limit; -- struct dns_header *header; -- size_t plen; -- union mysockaddr *l3; --}; - =20 - size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 - 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, siz= e_t plen, unsigned char *l - return p - (unsigned char *)header; - } -=20 --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 *li= mit) - { - return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0= , NULL, 0, 1); - } -=20 --size_t add_mac(struct dns_header *header, size_t plen, char *limit, union m= ysockaddr *l3) -+static unsigned char char64(unsigned char c) -+{ -+ return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"= [c & 0x3f]; -+} -+ -+static void encoder(unsigned char *in, char *out) -+{ -+ out[0] =3D char64(in[0]>>2); -+ out[1] =3D char64((in[0]<<4) | (in[1]>>4)); -+ out[2] =3D char64((in[1]<<2) | (in[2]>>6)); -+ out[3] =3D char64(in[2]); -+} -+ -+static size_t add_dns_client(struct dns_header *header, size_t plen, unsign= ed 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 =3D find_mac(l3, mac, 1, now)) =3D=3D 6) -+ { -+ encoder(mac, encode); -+ encoder(mac+3, encode+4); -+ =20 -+ plen =3D add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION= _NOMDEVICEID, (unsigned char *)encode, 8, 0);=20 -+ } -+ -+ if (daemon->dns_client_id) -+ plen =3D add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_N= OMCPEID,=20 -+ (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id= ), 0); -+ -+ return plen;=20 -+} -+ -=20 -- if ((maclen =3D find_mac(l3, mac, 1)) !=3D 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 =3D find_mac(l3, mac, 1, now)) !=3D 0) - plen =3D add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_M= AC, mac, maclen, 0);=20 -- =20 -+ =20 - return plen;=20 - } -=20 -@@ -296,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, un= ion mysockaddr *source) - return len + 4; - } - =20 --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, unsig= ned char *limit, union mysockaddr *source) - { - /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ - =20 -@@ -344,3 +372,23 @@ int check_source(struct dns_header *header, size_t plen= , unsigned char *pseudohe - =20 - return 1; - } -+ -+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned ch= ar *limit,=20 -+ union mysockaddr *source, time_t now, int *check_subnet) =20 -+{ -+ *check_subnet =3D 0; -+ -+ if (option_bool(OPT_ADD_MAC)) -+ plen =3D add_mac(header, plen, limit, source, now); -+ =20 -+ if (option_bool(OPT_DNS_CLIENT)) -+ plen =3D add_dns_client(header, plen, limit, source, now); -+ =20 -+ if (option_bool(OPT_CLIENT_SUBNET)) -+ { -+ plen =3D add_source_addr(header, plen, limit, source);=20 -+ *check_subnet =3D 1; -+ } -+ =20 -+ 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 =3D start; -- int forwarded =3D 0; -+ int subnet, forwarded =3D 0; - size_t edns0_len; -=20 - /* If a query is retried, use the log_id for the retry when logging t= he answer. */ - forward->log_id =3D daemon->log_id; - =20 -- if (option_bool(OPT_ADD_MAC)) -- { -- size_t new =3D add_mac(header, plen, ((char *) header) + PACKETSZ, &forw= ard->source); -- if (new !=3D plen) -- { -- plen =3D new; -- forward->flags |=3D FREC_ADDED_PHEADER; -- } -- } -- -- if (option_bool(OPT_CLIENT_SUBNET)) -+ edns0_len =3D add_edns0_config(header, plen, ((unsigned char *)heade= r) + PACKETSZ, &forward->source, now, &subnet); -+ =20 -+ if (edns0_len !=3D plen) - { -- size_t new =3D add_source_addr(header, plen, ((char *) header) + PACKETS= Z, &forward->source);=20 -- if (new !=3D plen) -- { -- plen =3D new; -- forward->flags |=3D FREC_HAS_SUBNET | FREC_ADDED_PHEADER; -- } -+ plen =3D edns0_len; -+ forward->flags |=3D FREC_ADDED_PHEADER; -+ =20 -+ if (subnet) -+ forward->flags |=3D FREC_HAS_SUBNET; - } -- -+ =20 - #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID)) - { -- size_t new =3D add_do_bit(header, plen, ((char *) header) + PACKETSZ); -+ size_t new =3D add_do_bit(header, plen, ((unsigned char *) header) + PAC= KETSZ); - =20 - if (new !=3D plen) - forward->flags |=3D 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 =3D sizep; -- =20 - GETSHORT(udpsz, sizep); - if (udpsz > daemon->edns_pktsz) -- PUTSHORT(daemon->edns_pktsz, psave); -+ { -+ sizep -=3D 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 +=3D 2; /* skip RCODE */ -+ GETSHORT(flags, sizep); -+ flags &=3D ~0x8000; -+ sizep -=3D 2; -+ PUTSHORT(flags, sizep); -+ } -+#endif - } - } - } -@@ -674,14 +680,11 @@ static size_t process_reply(struct dns_header *header,= time_t now, struct server - } - =20 - #ifdef HAVE_DNSSEC -- if (bogusanswer && !(header->hb4 & HB4_CD))=20 -+ if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEB= UG)) - { -- if (!option_bool(OPT_DNSSEC_DEBUG)) -- { -- /* Bogus reply, turn into SERVFAIL */ -- SET_RCODE(header, SERVFAIL); -- munged =3D 1; -- } -+ /* Bogus reply, turn into SERVFAIL */ -+ SET_RCODE(header, SERVFAIL); -+ munged =3D 1; - } -=20 - if (option_bool(OPT_DNSSEC_VALID)) -@@ -802,7 +805,7 @@ void reply_query(int fd, int family, time_t now) - if (forward->flags |=3D FREC_AD_QUESTION) - header->hb4 |=3D 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 =3D=3D STAT_NEED_KEY) - { - new->flags |=3D FREC_DNSKEY_QUERY;=20 -- nn =3D dnssec_generate_query(header, ((char *) header) + server->edns_= pktsz, -+ nn =3D dnssec_generate_query(header, ((unsigned char *) header) + serv= er->edns_pktsz, - daemon->keyname, forward->class, T_DNSKEY, &server->addr, server= ->edns_pktsz); - } - else=20 - { - new->flags |=3D FREC_DS_QUERY; -- nn =3D dnssec_generate_query(header,((char *) header) + server->edns_p= ktsz, -+ nn =3D dnssec_generate_query(header,((unsigned char *) header) + serve= r->edns_pktsz, - daemon->keyname, forward->class, T_DS, &server->addr, server->ed= ns_pktsz); - } - if ((hash =3D hash_questions(header, nn, daemon->namebuff))) -@@ -1434,7 +1437,7 @@ static int tcp_key_recurse(time_t now, int status, str= uct dns_header *header, si - break; - } - =20 -- m =3D dnssec_generate_query(new_header, ((char *) new_header) + 65536= , keyname, class,=20 -+ m =3D dnssec_generate_query(new_header, ((unsigned char *) new_header= ) + 65536, keyname, class,=20 - new_status =3D=3D STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, serve= r->edns_pktsz); - =20 - *length =3D htons(m); -@@ -1548,8 +1551,6 @@ unsigned char *tcp_request(int confd, time_t now, - daemon->log_display_id =3D ++daemon->log_id; - daemon->log_source_addr =3D &peer_addr; - =20 -- check_subnet =3D 0; -- - /* save state of "cd" flag in query */ - if ((checking_disabled =3D header->hb4 & HB4_CD)) - no_cache_dnssec =3D 1; -@@ -1627,20 +1628,14 @@ unsigned char *tcp_request(int confd, time_t now, - struct all_addr *addrp =3D NULL; - int type =3D 0; - char *domain =3D NULL; -- =20 -- if (option_bool(OPT_ADD_MAC)) -- size =3D add_mac(header, size, ((char *) header) + 65536, &peer_addr); -- =09 -- if (option_bool(OPT_CLIENT_SUBNET)) -+ size_t new_size =3D add_edns0_config(header, size, ((unsigned char *= ) header) + 65536, &peer_addr, now, &check_subnet); -+ -+ if (size !=3D new_size) - { -- size_t new =3D add_source_addr(header, size, ((char *) header) + 65536,= &peer_addr); -- if (size !=3D new) -- { -- size =3D new; -- check_subnet =3D 1; -- } -+ added_pheader =3D 1; -+ size =3D new_size; - } -- -+ =20 - if (gotname) - flags =3D search_servers(now, &addrp, gotname, daemon->namebuff, &type, &= domain, &norebind); - =20 -@@ -1715,20 +1710,20 @@ unsigned char *tcp_request(int confd, time_t now, - } - =20 - #ifdef HAVE_DNSSEC -- added_pheader =3D 0; =20 - if (option_bool(OPT_DNSSEC_VALID)) - { -- size_t new_size =3D add_do_bit(header, size, ((char *) header) + 6= 5536); -+ new_size =3D add_do_bit(header, size, ((unsigned char *) header) += 65536); -+ =20 -+ if (size !=3D new_size) -+ { -+ added_pheader =3D 1; -+ size =3D new_size; -+ } - =20 - /* For debugging, set Checking Disabled, otherwise, have the upstr= eam check too, - this allows it to select auth servers when one is returning bad data. = */ - if (option_bool(OPT_DNSSEC_DEBUG)) - header->hb4 |=3D HB4_CD; -- =20 -- if (size !=3D new_size) -- added_pheader =3D 1; -- =20 -- size =3D 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 =3D "tftp"; - is6 =3D (data.flags !=3D AF_INET); - } -- else -+ else if (data.action =3D=3D ACTION_ARP) -+ { -+ action_str =3D "arp"; -+ is6 =3D (data.flags !=3D AF_INET); -+ } -+ else if (data.action =3D=3D ACTION_ARP_OLD) -+ { -+ action_str =3D "arp-old"; -+ is6 =3D (data.flags !=3D AF_INET); -+ data.action =3D ACTION_ARP; -+ } -+ else=20 - continue; -=20 - =09 -@@ -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 =3D=3D ACTION_ARP) -+ { -+ lua_getglobal(lua, "arp");=20 -+ if (lua_type(lua, -1) !=3D 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, g= id_t gid, long max_fd) - continue; - } - =20 -- if (data.action !=3D ACTION_TFTP) -+ if (data.action !=3D ACTION_TFTP && data.action !=3D 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 =3D=3D ACTION_OLD_HOSTNAME= ? hostname : NULL, &err); - if (data.action =3D=3D ACTION_OLD_HOSTNAME) - hostname =3D NULL; -- } -- -- my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL,= &err); -- =20 -+ =20 -+ my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &e= rr); -+ } - /* we need to have the event_fd around if exec fails */ - if ((i =3D fcntl(event_fd, F_GETFD)) !=3D -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, g= id_t gid, long max_fd) - if (err =3D=3D 0) - { - execl(daemon->lease_change_command,=20 -- p ? p+1 : daemon->lease_change_command, -- action_str, is6 ? daemon->packet : daemon->dhcp_buff,=20 -+ p ? p+1 : daemon->lease_change_command, action_str,=20 -+ (is6 && data.action !=3D ACTION_ARP) ? daemon->packet : daemon->dhcp_buff= ,=20 - daemon->addrbuff, hostname, (char*)NULL); - err =3D errno; - } -@@ -760,6 +786,30 @@ void queue_tftp(off_t file_len, char *filename, union m= ysockaddr *peer) - } - #endif -=20 -+void queue_arp(int action, unsigned char *mac, int maclen, int family, stru= ct all_addr *addr) -+{ -+ /* no script */ -+ if (daemon->helperfd =3D=3D -1) -+ return; -+ =20 -+ buff_alloc(sizeof(struct script_data)); -+ memset(buf, 0, sizeof(struct script_data)); -+ -+ buf->action =3D action; -+ buf->hwaddr_len =3D maclen; -+ buf->hwaddr_type =3D ARPHRD_ETHER;=20 -+ if ((buf->flags =3D family) =3D=3D AF_INET) -+ buf->addr =3D addr->addr.addr4; -+#ifdef HAVE_IPV6 -+ else -+ buf->addr6 =3D addr->addr.addr6; -+#endif -+ =20 -+ memcpy(buf->hwaddr, mac, maclen); -+ =20 -+ bytes_in_buf =3D sizeof(struct script_data); -+} -+ - int helper_buf_empty(void) - { - return bytes_in_buf =3D=3D 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 -=20 - #ifdef HAVE_GETOPT_LONG - static const struct option opts[] =3D =20 -@@ -281,6 +282,7 @@ static const struct myoption opts[] =3D - { "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 addr= ess to forwarded DNS queries."), NULL }, - { LOPT_ADD_SBNET, ARG_ONE, "[,]", gettext_noop("Add spe= cified IP subnet to forwarded DNS queries."), NULL }, -+ { LOPT_DNS_CLIENT_ID, ARG_ONE, "", gettext_noop("Add client id= entification to forwarded DNS queries."), NULL }, - { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validat= ion results from upstream nameservers."), NULL }, - { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocat= e sequential IP addresses to DHCP clients."), NULL }, - { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-trac= k mark from queries to upstream connections."), NULL }, -@@ -2150,6 +2153,12 @@ static int one_opt(int option, char *arg, char *errst= r, char *gen_err, int comma - } - break; - =20 -+ case LOPT_DNS_CLIENT_ID: /* --add-dns-client */ -+ set_option_bool(OPT_DNS_CLIENT); -+ if (arg) -+ daemon->dns_client_id =3D opt_string_alloc(arg); -+ break; -+ - case 'u': /* --user */ - daemon->username =3D 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. */ - =20 - 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; - }=20 -=20 --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,=20 -+ struct in6_addr *peer_address, u32 scope_id, time_t now) - { - /* ->local is same value for all relays on ->current chain */ - =20 -@@ -2068,7 +2069,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t= sz, struct in6_addr *peer - unsigned char mac[DHCP_CHADDR_MAX]; -=20 - 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); -=20 - /* source address =3D=3D relay address */ - from.addr.addr6 =3D relay->local.addr.addr6; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/038-Correct_logic_for_when_to_start_helper.p= atch 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 -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 ro= ot. */ - daemon->helperfd =3D -1; - #ifdef HAVE_SCRIPT=20 -- if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_boo= l(OPT_ADD_MAC)) &&=20 -+ if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_boo= l(OPT_DNS_CLIENT)) &&=20 - (daemon->lease_change_command || daemon->luascript)) - daemon->helperfd =3D create_helper(pipewrite, err_pipe[1], script_uid= , script_gid, max_fd); - #endif ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/039-Trivial_code_tweak.patch b/src/patches/d= nsmasq/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 -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 *h= eader, size_t plen, int dige - if (!CHECK_LEN(header, p, plen, rdlen)) - return 0; - =09 -- /* If we can prove that there's no NS record, return that information. */ -- if (nons && rdlen >=3D 2 && p[0] =3D=3D 0 && (p[2] & (0x80 >> T_NS)) !=3D= 0) -- *nons =3D 0; -- =09 - if (rdlen >=3D 2 && p[0] =3D=3D 0) - { -+ /* If we can prove that there's no NS record, return that information= . */ -+ if (nons && (p[2] & (0x80 >> T_NS)) !=3D 0) -+ *nons =3D 0; -+ =09 - /* A CNAME answer would also be valid, so if there's a CNAME is shoul= d=20 - have been returned. */ - if ((p[2] & (0x80 >> T_CNAME)) !=3D 0) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/040-Fix_datatype-sixe_botch_which_broke_DNSS= EC_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 -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) - } -=20 - /* 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 =3D=3D s2) - return SERIAL_EQ; -@@ -503,7 +503,7 @@ int setup_timestamp(void) - } -=20 - /* Check whether today/now is between date_start and date_end */ --static int check_date_range(unsigned long date_start, unsigned long date_en= d) -+static int check_date_range(u32 date_start, u32 date_end) - { - unsigned long curtime =3D time(0); - =20 -@@ -796,11 +796,11 @@ static int validate_rrset(time_t now, struct dns_heade= r *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 =3D NULL; -- int algo, labels, orig_ttl, key_tag; - u16 *rr_desc =3D rrfilter_desc(type); --=20 -+ u32 sig_expiration, sig_inception -+; - if (wildcard_out) - *wildcard_out =3D NULL; - =20 ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/041-Fix_botch_in_new_arp-cache_linked-list_c= ode_resulting_in_100percent_CPU_spin.patch b/src/patches/dnsmasq/041-Fix_botc= h_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_res= ulting_in_100percent_CPU_spin.patch +++ /dev/null @@ -1,56 +0,0 @@ -From d917275e481add809cd5c40650f339ae994ee35f Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 n= ow) - { -- struct arp_record *arp, **up; -+ struct arp_record *arp, *tmp, **up; - int updated =3D 0; -=20 - again: -@@ -155,16 +155,20 @@ int find_mac(union mysockaddr *addr, unsigned char *ma= c, int lazy, time_t now) - iface_enumerate(AF_UNSPEC, NULL, filter_mac); - =20 - /* Remove all unconfirmed entries to old list. */ -- for (arp =3D arps, up =3D &arps; arp; arp =3D arp->next) -- if (arp->status =3D=3D ARP_MARK) -- { -- *up =3D arp->next; -- arp->next =3D old; -- old =3D arp; -- } -- else -- up =3D &arp->next; -+ for (arp =3D arps, up =3D &arps; arp; arp =3D tmp) -+ { -+ tmp =3D arp->next; - =20 -+ if (arp->status =3D=3D ARP_MARK) -+ { -+ *up =3D arp->next; -+ arp->next =3D old; -+ old =3D arp; -+ } -+ else -+ up =3D &arp->next; -+ } -+ - goto again; - } -=20 ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/042-Handle_building_with_script_support_enab= led_and_DHCP_disabled.patch b/src/patches/dnsmasq/042-Handle_building_with_sc= ript_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 -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); -=20 - #ifdef HAVE_SCRIPT -+# ifdef HAVE_DHCP - while (helper_buf_empty() && do_script_run(now));=20 -+# endif -+ - while (helper_buf_empty() && do_arp_script_run()); -=20 - # 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)); -=20 - # ifdef HAVE_TFTP=20 -@@ -1312,7 +1318,7 @@ static void async_event(int pipe, time_t now) - if (daemon->tcp_pids[i] !=3D 0) - kill(daemon->tcp_pids[i], SIGALRM); - =09 --#if defined(HAVE_SCRIPT) -+#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP) - /* handle pending lease transitions */ - if (daemon->helperfd !=3D -1) - { ---=20 -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 -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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 - =20 - 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 . - */ -=20 --#define COPYRIGHT "Copyright (c) 2000-2015 Simon Kelley"=20 -+#define COPYRIGHT "Copyright (c) 2000-2016 Simon Kelley" -=20 - #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 -- and Copyright (c) 2012-2015 Simon Kelley -+ and Copyright (c) 2012-2016 Simon Kelley -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 - =20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 -=20 - 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 ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compi= lation_time.patch b/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_a= t_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 -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 -=20 -- while (do_arp_script_run(now)); -+ while (do_arp_script_run()); -=20 - # ifdef HAVE_TFTP=20 - while (do_tftp_script_run()); ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwardin= g_to_private_servers_for_a_domain.patch b/src/patches/dnsmasq/045-Inhibit_DNS= SEC_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_pr= ivate_servers_for_a_domain.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 5757371d43891e830abe19aacae5378a79c7851c Mon Sep 17 00:00:00 2001 -From: Simon Kelley -Date: Mon, 11 Jan 2016 22:50:00 +0000 -Subject: [PATCH] Inhibit DNSSEC validation when forwarding to private servers - for a domain. - -server=3D/example.com/ - -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 *ud= paddr, - } - =20 - #ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID)) -+ if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN)) - { - size_t new =3D add_do_bit(header, plen, ((unsigned char *) header) + PAC= KETSZ); - =20 -@@ -858,7 +858,8 @@ void reply_query(int fd, int family, time_t now) - no_cache_dnssec =3D 1; - =20 - #ifdef HAVE_DNSSEC -- if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FRE= C_CHECKING_DISABLED)) -+ if (server && !(server->flags & SERV_HAS_DOMAIN) &&=20 -+ option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABL= ED)) - { - int status =3D 0; -=20 ---=20 -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_Han= dle_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 -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 =3D daemon->ds; ds; ds =3D ds->next) -+ if (ds->name[0] =3D=3D 0) -+ break; -+ -+ if (!ds) -+ die(_("no root trust anchor provided for DNSSEC"), NULL, EC_BADCONF); - =20 - 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 *he= ader, size_t plen, char *key - */ - static int zone_status(char *name, int class, char *keyname, time_t now) - { -- int name_start =3D strlen(name); -+ int name_start =3D 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 =3D name; p; p =3D strchr(p, '.')) -+ { -+ if (*p =3D=3D '.') -+ p++; -+ -+ if (cache_find_by_name(NULL, p, now, F_DS)) -+ { -+ name_start =3D p - name; -+ break; -+ } -+ } - =20 -+ /* Now work away from the trust anchor */ - while (1) - { - strcpy(keyname, &name[name_start]); ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_host= s-file_read_fails.patch b/src/patches/dnsmasq/047-Fix_bad_cache-size_calculat= ion_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: =3D?utf8?q?Andr=3DC3=3DA9=3D20Gl=3DC3=3DBCpker?=3D -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=C3=83=C2=B6r=C3=83=C2= =B6k for - the patch. -=20 -+ Fix failure to correctly calculate cache-size when=20 -+ reading a hosts-file fails. Thanks to Andr=C3=83=C2=A9 Gl=C3=83=C2=BCp= ker=20 -+ for the patch. -+ - =09 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 -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, i= nt cache_size, struct cr - if (!f) - { - my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, s= trerror(errno)); -- return 0; -+ return cache_size; - } - =20 - eatspace(f); ---=20 -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 -Date: Tue, 12 Jan 2016 15:58:23 +0000 -Subject: [PATCH] Disable DNSSEC for server=3D/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= */ -=20 - 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 *ke= yname, time_t now) - break; - } - } -- =20 -+ - /* 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 l= en, - return 1; - } - =20 --static unsigned int search_servers(time_t now, struct all_addr **addrpp,=20 -- unsigned int qtype, char *qdomain, int *type, char **domain, int *= norebind) -+static unsigned int search_servers(time_t now, struct all_addr **addrpp, un= signed int qtype, -+ char *qdomain, int *type, char **domain, int *norebind) - =20 - { - /* 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 al= l_addr **addrpp, - =09 - if (domainlen >=3D matchlen) - { -- *type =3D serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_= REBIND); -+ *type =3D serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_= REBIND | SERV_DO_DNSSEC); - *domain =3D serv->domain; - matchlen =3D 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 =3D NULL; -- int type =3D 0, norebind =3D 0; -+ int type =3D SERV_DO_DNSSEC, norebind =3D 0; - struct all_addr *addrp =3D NULL; - unsigned int flags =3D 0; - struct server *start =3D NULL; - #ifdef HAVE_DNSSEC - void *hash =3D hash_questions(header, plen, daemon->namebuff); -+ int do_dnssec =3D 0; - #else - unsigned int crc =3D questions_crc(header, plen, daemon->namebuff); - void *hash =3D &crc; -@@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *u= dpaddr, - daemon->last_server =3D NULL; - } - type =3D forward->sentto->flags & SERV_TYPE; -+#ifdef HAVE_DNSSEC -+ do_dnssec =3D forward->sentto->flags & SERV_DO_DNSSEC; -+#endif -+ - if (!(start =3D forward->sentto->next)) - start =3D daemon->servers; /* at end of list, recycle */ - header->id =3D htons(forward->new_id); -@@ -324,6 +329,11 @@ static int forward_query(int udpfd, union mysockaddr *u= dpaddr, - if (gotname) - flags =3D search_servers(now, &addrp, gotname, daemon->namebuff, &type, &d= omain, &norebind); - =20 -+#ifdef HAVE_DNSSEC -+ do_dnssec =3D type & SERV_DO_DNSSEC; -+ type &=3D ~SERV_DO_DNSSEC; -+#endif =20 -+ - if (!flags && !(forward =3D get_new_frec(now, NULL, 0))) - /* table full - server failure. */ - flags =3D F_NEG; -@@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *ud= paddr, - } - =20 - #ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN)) -+ if (option_bool(OPT_DNSSEC_VALID) && do_dnssec) - { - size_t new =3D add_do_bit(header, plen, ((unsigned char *) header) + PAC= KETSZ); - =20 -@@ -858,7 +868,7 @@ void reply_query(int fd, int family, time_t now) - no_cache_dnssec =3D 1; - =20 - #ifdef HAVE_DNSSEC -- if (server && !(server->flags & SERV_HAS_DOMAIN) &&=20 -+ if (server && (server->flags & SERV_DO_DNSSEC) &&=20 - option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABL= ED)) - { - int status =3D 0; -@@ -1640,6 +1650,10 @@ unsigned char *tcp_request(int confd, time_t now, - if (gotname) - flags =3D search_servers(now, &addrp, gotname, daemon->namebuff, &type, &= domain, &norebind); - =20 -+#ifdef HAVE_DNSSEC -+ type &=3D ~SERV_DO_DNSSEC; -+#endif -+ =20 - if (type !=3D 0 || option_bool(OPT_ORDER) || !daemon->last_server) - last_server =3D daemon->servers; - else -@@ -1711,7 +1725,7 @@ unsigned char *tcp_request(int confd, time_t now, - } - =20 - #ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID)) -+ if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNS= SEC)) - { - new_size =3D add_do_bit(header, size, ((unsigned char *) header) += 65536); - =20 -@@ -1757,7 +1771,7 @@ unsigned char *tcp_request(int confd, time_t now, - #endif=20 -=20 - #ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled) -+ if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_se= rver->flags & SERV_DO_DNSSEC)) - { - int keycount =3D DNSSEC_WORK; /* Limit to number of DNSSEC questions, = to catch loops and avoid filling cache. */ - int status =3D tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->nam= ebuff, 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); - =20 -+#ifdef HAVE_DNSSEC -+ /* Disable DNSSEC validation when using server=3D/domain/.... servers -+ unless there's a configured trust anchor. */ -+ for (serv =3D daemon->servers; serv; serv =3D serv->next) -+ serv->flags |=3D SERV_DO_DNSSEC; -+#endif -+ - for (serv =3D daemon->servers; serv; serv =3D 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_R= ESOLV | SERV_NO_REBIND))) - { -- port =3D 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 =3D serv->domain; -+ -+ /* .example.com is valid */ -+ while (*domain =3D=3D '.') -+ domain++; -+ =20 -+ for (ds =3D daemon->ds; ds; ds =3D ds->next) -+ if (ds->name[0] !=3D 0 && hostname_isequal(domain, ds->name)) -+ break; -=20 -+ if (!ds) -+ serv->flags &=3D ~SERV_DO_DNSSEC; -+ } -+#endif -+ -+ port =3D prettyprint_addr(&serv->addr, daemon->namebuff); -+ =20 - /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */ - if (serv->addr.sa.sa_family =3D=3D AF_INET && - serv->addr.in.sin_addr.s_addr =3D=3D 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 =3D ""; -+#ifdef HAVE_DNSSEC -+ if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC)) -+ s3 =3D _("(no DNSSEC)"); -+#endif - if (!(serv->flags & SERV_HAS_DOMAIN)) - s1 =3D _("unqualified"), s2 =3D _("names"); - else if (strlen(serv->domain) =3D=3D 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=20 -- my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebu= ff, port, s1, s2); -+ my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->nam= ebuff, port, s1, s2, s3); - } - #ifdef HAVE_LOOP - else if (serv->flags & SERV_LOOP) ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/049-arp_c_tidy_up.patch b/src/patches/dnsmas= q/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 -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 - =09 -- /* Only accept poitive entries unless in lazy mode. */ -+ /* Only accept positive entries unless in lazy mode. */ - if (arp->status !=3D ARP_EMPTY || lazy || updated) - { - if (mac && arp->hwlen !=3D 0) -@@ -148,7 +148,7 @@ int find_mac(union mysockaddr *addr, unsigned char *mac,= int lazy, time_t now) - last =3D now; -=20 - /* Mark all non-negative entries */ -- for (arp =3D arps, up =3D &arps; arp; arp =3D arp->next) -+ for (arp =3D arps; arp; arp =3D arp->next) - if (arp->status !=3D ARP_EMPTY) - arp->status =3D ARP_MARK; - =20 ---=20 -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_al= low_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_p= rivate_DNS_servers.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 92be34a4077672f592d47e2991b3530305517a28 Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 givi= ng the flag - .B -S /internal.thekelleys.org.uk/192.168.1.1=20 - 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 //=20 - has the special meaning of "unqualified names only" ie names without any - dots in them. A non-standard port may be specified as=20 -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 al= l_addr **addrpp, unsigne - hostname_isequal(matchstart, serv->domain) && - (domainlen =3D=3D 0 || namelen =3D=3D domainlen || *(matchstart-1) =3D= =3D '.' )) - { -- if (serv->flags & SERV_NO_REBIND)=09 -+ if ((serv->flags & SERV_NO_REBIND) && norebind)=09 - *norebind =3D 1; - else - { -@@ -644,7 +644,7 @@ static size_t process_reply(struct dns_header *header, t= ime_t now, struct server - return resize_packet(header, n, pheader, plen); - =20 - /* Complain loudly if the upstream server is non-recursive. */ -- if (!(header->hb4 & HB4_RA) && RCODE(header) =3D=3D NOERROR && ntohs(head= er->ancount) =3D=3D 0 && -+ if (!(header->hb4 & HB4_RA) && RCODE(header) =3D=3D 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 =3D STAT_ABANDONED; - else - { -- int fd; -+ int fd, type; - struct frec *next =3D new->next; -+ char *domain; -+ =20 - *new =3D *forward; /* copy everything, then overwrite */ - new->next =3D next; - new->blocking_query =3D NULL; -+ -+ /* Find server to forward to. This will normally be the=20 -+ same as for the original query, but may be another if -+ servers for domains are involved. */ =20 -+ if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &dom= ain, NULL) =3D=3D 0) -+ { -+ struct server *start =3D server; -+ type &=3D ~SERV_DO_DNSSEC; -+ =20 -+ while (1) -+ { -+ if (type =3D=3D (start->flags & SERV_TYPE) && -+ (type !=3D SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain= )) && -+ !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) -+ { -+ server =3D start; -+ break; -+ } -+ =20 -+ if (!(start =3D start->next)) -+ start =3D daemon->servers; -+ if (start =3D=3D server) -+ break; -+ } -+ } - new->sentto =3D server; -+ - new->rfd4 =3D NULL; - #ifdef HAVE_IPV6 - new->rfd6 =3D 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_R= ESOLV | SERV_NO_REBIND))) - { - #ifdef HAVE_DNSSEC -- if (option_bool(OPT_DNSSEC_VALID) && (serv->flags & SERV_HAS_DOMAIN)) -- { -- struct ds_config *ds; -- char *domain =3D serv->domain; -- -- /* .example.com is valid */ -- while (*domain =3D=3D '.') -- domain++; -- =20 -- for (ds =3D daemon->ds; ds; ds =3D ds->next) -- if (ds->name[0] !=3D 0 && hostname_isequal(domain, ds->name)) -- break; -- -- if (!ds) -+ if (option_bool(OPT_DNSSEC_VALID)) -+ {=20 -+ if (serv->flags & SERV_HAS_DOMAIN) -+ { -+ struct ds_config *ds; -+ char *domain =3D serv->domain; -+ =20 -+ /* .example.com is valid */ -+ while (*domain =3D=3D '.') -+ domain++; -+ =20 -+ for (ds =3D daemon->ds; ds; ds =3D ds->next) -+ if (ds->name[0] !=3D 0 && hostname_isequal(domain, ds->name)) -+ break; -+ =20 -+ if (!ds) -+ serv->flags &=3D ~SERV_DO_DNSSEC; -+ } -+ else if (serv->flags & SERV_FOR_NODOTS)=20 - serv->flags &=3D ~SERV_DO_DNSSEC; - } - #endif ---=20 -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 -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 &=3D ~(HB3_QR | HB3_AA | HB3_TC); - header->hb4 &=3D ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD); -- if (forward->flags |=3D FREC_CHECKING_DISABLED) -+ if (forward->flags & FREC_CHECKING_DISABLED) - header->hb4 |=3D HB4_CD; -- if (forward->flags |=3D FREC_AD_QUESTION) -+ if (forward->flags & FREC_AD_QUESTION) - header->hb4 |=3D HB4_AD; - if (forward->flags & FREC_DO_QUESTION) - add_do_bit(header, nn, (unsigned char *)pheader + plen); ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch b/s= rc/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 -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 =3D arp; - arp->status =3D ARP_EMPTY; - arp->family =3D addr->sa.sa_family; -- =20 -+ arp->hwlen =3D 0; -+ - if (addr->sa.sa_family =3D=3D AF_INET) - arp->addr.addr.addr4.s_addr =3D addr->in.sin_addr.s_addr; - #ifdef HAVE_IPV6 ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_an= d_set_conntrack_on_DNSSEC_queries.patch b/src/patches/dnsmasq/053-Complete_DN= SSEC_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_c= onntrack_on_DNSSEC_queries.patch +++ /dev/null @@ -1,270 +0,0 @@ -From f344dbc62216570b6471c81e4e39fc99bf47af5f Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 =3D STAT_ABANDONED; - else - { -- int fd, type; -+ int fd, type =3D SERV_DO_DNSSEC; - struct frec *next =3D new->next; - char *domain; - =20 -@@ -936,7 +936,7 @@ void reply_query(int fd, int family, time_t now) - servers for domains are involved. */ =20 - if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &dom= ain, NULL) =3D=3D 0) - { -- struct server *start =3D server; -+ struct server *start =3D server, *new_server =3D NULL; - type &=3D ~SERV_DO_DNSSEC; - =20 - while (1) -@@ -945,8 +945,12 @@ void reply_query(int fd, int family, time_t now) - (type !=3D SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain= )) && - !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) - { -- server =3D start; -- break; -+ new_server =3D start; -+ if (server =3D=3D start) -+ { -+ new_server =3D NULL; -+ break; -+ } - } - =20 - if (!(start =3D start->next)) -@@ -954,7 +958,11 @@ void reply_query(int fd, int family, time_t now) - if (start =3D=3D server) - break; - } -+ =09 -+ if (new_server) -+ server =3D new_server; - } -+ - new->sentto =3D server; -=20 - new->rfd4 =3D NULL; -@@ -1010,6 +1018,15 @@ void reply_query(int fd, int family, time_t now) - =20 - if (fd !=3D -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,=20 - &server->addr.sa,=20 - sa_len(&server->addr))));=20 -@@ -1072,7 +1089,7 @@ void reply_query(int fd, int family, time_t now) - else - header->hb4 &=3D ~HB4_CD; - =20 -- if ((nn =3D process_reply(header, now, server, (size_t)n, check_rebin= d, no_cache_dnssec, cache_secure, bogusanswer,=20 -+ if ((nn =3D process_reply(header, now, forward->sentto, (size_t)n, ch= eck_rebind, no_cache_dnssec, cache_secure, bogusanswer,=20 - forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTI= ON,=20 - forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUB= NET, &forward->source))) - { -@@ -1433,20 +1450,27 @@ void receive_query(struct listener *listen, time_t n= ow) - } -=20 - #ifdef HAVE_DNSSEC -+/* Recurse up the key heirarchy */ - static int tcp_key_recurse(time_t now, int status, struct dns_header *heade= r, size_t n,=20 -- int class, char *name, char *keyname, struct server *server, int *key= count) -+ int class, char *name, char *keyname, struct server *server,=20 -+ int have_mark, unsigned int mark, int *keycount) - { -- /* Recurse up the key heirarchy */ - int new_status; - unsigned char *packet =3D NULL; -- size_t m;=20 - unsigned char *payload =3D NULL; - struct dns_header *new_header =3D NULL; - u16 *length =3D NULL; -- unsigned char c1, c2; -+ -+ (void)have_mark; -+ (void)mark; -=20 - while (1) - { -+ int type =3D SERV_DO_DNSSEC; -+ char *domain; -+ size_t m;=20 -+ unsigned char c1, c2; -+ =20 - /* limit the amount of work we do, to avoid cycling forever on loops = in the DNS */ - if (--(*keycount) =3D=3D 0) - new_status =3D STAT_ABANDONED; -@@ -1480,6 +1504,67 @@ static int tcp_key_recurse(time_t now, int status, st= ruct dns_header *header, si - new_status =3D=3D STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, serve= r->edns_pktsz); - =20 - *length =3D htons(m); -+ -+ /* Find server to forward to. This will normally be the=20 -+ same as for the original query, but may be another if -+ servers for domains are involved. */ =20 -+ if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL)= =3D=3D 0) -+ { -+ struct server *start =3D server, *new_server =3D NULL; -+ type &=3D ~SERV_DO_DNSSEC; -+ =20 -+ while (1) -+ { -+ if (type =3D=3D (start->flags & SERV_TYPE) && -+ (type !=3D SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) = && -+ !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) -+ { -+ new_server =3D start; -+ if (server =3D=3D start) -+ { -+ new_server =3D NULL; -+ break; -+ } -+ } -+ =20 -+ if (!(start =3D start->next)) -+ start =3D daemon->servers; -+ if (start =3D=3D server) -+ break; -+ } -+ =20 -+ -+ if (new_server) -+ { -+ server =3D new_server; -+ /* may need to make new connection. */ -+ if (server->tcpfd =3D=3D -1) -+ { -+ if ((server->tcpfd =3D socket(server->addr.sa.sa_family, SOCK_STREAM, 0= )) =3D=3D -1) -+ { -+ new_status =3D 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=09 -+ =20 -+ if (!local_bind(server->tcpfd, &server->source_addr, server->interface= , 1) || -+ connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) =3D= =3D -1) -+ { -+ close(server->tcpfd); -+ server->tcpfd =3D -1; -+ new_status =3D STAT_ABANDONED; -+ break; -+ } -+ -+ } -+ } -+ } -+ - =20 - 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, str= uct dns_header *header, si -=20 - m =3D (c1 << 8) | c2; - =20 -- new_status =3D tcp_key_recurse(now, new_status, new_header, m, class,= name, keyname, server, keycount); -+ new_status =3D tcp_key_recurse(now, new_status, new_header, m, class,= name, keyname, server, have_mark, mark, keycount); - =20 - if (new_status !=3D STAT_OK) - break; -@@ -1536,10 +1621,30 @@ unsigned char *tcp_request(int confd, time_t now, - socklen_t peer_len =3D sizeof(union mysockaddr); - int query_count =3D 0; - unsigned char *pheader; -+#ifdef HAVE_CONNTRACK -+ unsigned int mark =3D 0; -+ int have_mark =3D 0; -+#endif -=20 - if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) =3D=3D -= 1) - return packet; -- =20 -+ -+#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 =20 -+ if (local_addr->sa.sa_family =3D=3D AF_INET6) -+ local.addr.addr6 =3D local_addr->in6.sin6_addr; -+ else -+#endif -+ local.addr.addr4 =3D local_addr->in.sin_addr; -+ =20 -+ have_mark =3D get_incoming_mark(&peer_addr, &local, 1, &mark); -+ } -+#endif=09 -+ - /* 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 =3D 0; - struct all_addr *addrp =3D NULL; -- int type =3D 0; -+ int type =3D SERV_DO_DNSSEC; - char *domain =3D NULL; - size_t new_size =3D add_edns0_config(header, size, ((unsigned char *= ) header) + 65536, &peer_addr, now, &check_subnet); -=20 -@@ -1728,20 +1833,8 @@ unsigned char *tcp_request(int confd, time_t now, - =20 - #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 =20 -- if (local_addr->sa.sa_family =3D=3D AF_INET6) -- local.addr.addr6 =3D local_addr->in6.sin6_addr; -- else --#endif -- local.addr.addr4 =3D local_addr->in.sin_addr; -- =20 -- if (get_incoming_mark(&peer_addr, &local, 1, &mark)) -- setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsig= ned int)); -- } -+ if (have_mark) -+ setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(un= signed int)); - #endif=09 - =20 - 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_se= rver->flags & SERV_DO_DNSSEC)) - { - int keycount =3D DNSSEC_WORK; /* Limit to number of DNSSEC questions, = to catch loops and avoid filling cache. */ -- int status =3D tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->nam= ebuff, daemon->keyname, last_server, &keycount); -+ int status =3D tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->nam= ebuff, daemon->keyname,=20 -+ last_server, have_mark, mark, &keycount); - char *result, *domain =3D "result"; - =20 - if (status =3D=3D STAT_ABANDONED) ---=20 -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_ena= bled.patch +++ /dev/null @@ -1,58 +0,0 @@ -From f7443d76f7b4ff1c2eb05a0313619b0a4bb8787e Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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 *ud= paddr, - =20 - #ifdef HAVE_DNSSEC - do_dnssec =3D type & SERV_DO_DNSSEC; -- type &=3D ~SERV_DO_DNSSEC; --#endif =20 -+#endif -+ type &=3D ~SERV_DO_DNSSEC; =20 -=20 - if (!flags && !(forward =3D get_new_frec(now, NULL, 0))) - /* table full - server failure. */ -@@ -1461,9 +1461,6 @@ static int tcp_key_recurse(time_t now, int status, str= uct dns_header *header, si - struct dns_header *new_header =3D NULL; - u16 *length =3D NULL; -=20 -- (void)have_mark; -- (void)mark; -- - while (1) - { - int type =3D SERV_DO_DNSSEC; -@@ -1621,10 +1618,8 @@ unsigned char *tcp_request(int confd, time_t now, - socklen_t peer_len =3D sizeof(union mysockaddr); - int query_count =3D 0; - unsigned char *pheader; --#ifdef HAVE_CONNTRACK - unsigned int mark =3D 0; - int have_mark =3D 0; --#endif -=20 - if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) =3D=3D -= 1) - return packet; -@@ -1783,9 +1778,7 @@ unsigned char *tcp_request(int confd, time_t now, - if (gotname) - flags =3D search_servers(now, &addrp, gotname, daemon->namebuff, &type, &= domain, &norebind); - =20 --#ifdef HAVE_DNSSEC - type &=3D ~SERV_DO_DNSSEC; --#endif - =20 - if (type !=3D 0 || option_bool(OPT_ORDER) || !daemon->last_server) - last_server =3D daemon->servers; ---=20 -1.7.10.4 - diff --git a/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--do= main-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_configure= d.patch deleted file mode 100644 index 9eea14a..0000000 --- a/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-ne= eded_set_and_no_servers_configured.patch +++ /dev/null @@ -1,91 +0,0 @@ -From d05dd58de1113bb99060af2772247a45ceb3a1ad Mon Sep 17 00:00:00 2001 -From: Simon Kelley -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=C3=83=C2=A9 Gl=C3=83=C2=BCp= ker=20 - for the patch. -=20 -+ 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=20 -+ Allain Legacy for spotting the problem. -+ -+ Return REFUSED when running out of forwarding table slots, -+ not SERVFAIL. -+ - =09 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 -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 *ud= paddr, - (void)do_bit; -=20 - /* may be no servers available. */ -- if (!daemon->servers) -- forward =3D NULL; -- else if (forward || (hash && (forward =3D lookup_frec_by_sender(ntohs(hea= der->id), udpaddr, hash)))) -+ if (forward || (hash && (forward =3D 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 *ud= paddr, - #endif - type &=3D ~SERV_DO_DNSSEC; =20 -=20 -- if (!flags && !(forward =3D get_new_frec(now, NULL, 0))) -- /* table full - server failure. */ -- flags =3D F_NEG; -+ if (daemon->servers && !flags) -+ forward =3D get_new_frec(now, NULL, 0); -+ /* table full - flags =3D=3D 0, return REFUSED */ - =20 - if (forward) - { -@@ -1621,6 +1619,9 @@ unsigned char *tcp_request(int confd, time_t now, - unsigned int mark =3D 0; - int have_mark =3D 0; -=20 -+ (void)mark; -+ (void)have_mark; -+ - if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) =3D=3D -= 1) - return packet; -=20 -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 qle= n, - header->nscount =3D htons(0); - header->arcount =3D htons(0); - header->ancount =3D htons(0); /* no answers unless changed below */ -- if (flags =3D=3D F_NEG) -- SET_RCODE(header, SERVFAIL); /* couldn't get memory */ -- else if (flags =3D=3D F_NOERR) -+ if (flags =3D=3D F_NOERR) - SET_RCODE(header, NOERROR); /* empty domain */ - else if (flags =3D=3D F_NXDOMAIN) - SET_RCODE(header, NXDOMAIN); ---=20 -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 -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. -=20 -+ Add --max-port configuration. Thanks to Hans Dedecker for -+ the patch. -+=09 - =09 - version 2.75 - Fix reversion on 2.74 which caused 100% CPU use when a=20 -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 outbo= und queries: - when this option is given, the ports used will always to larger - than that specified. Useful for systems behind firewalls.=20 - .TP -+.B --max-port=3D -+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=3D - 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 @@ -=20 - #define NAMESERVER_PORT 53 - #define TFTP_PORT 69 -+#define MAX_PORT 65535u -=20 - #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"), N= ULL, EC_BADCONF); - #endif -- =20 -+ -+ if (daemon->max_port !=3D MAX_PORT && daemon->min_port =3D=3D 0) -+ daemon->min_port =3D 1024u; -+ -+ if (daemon->max_port < daemon->min_port) -+ die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF); -+ - now =3D dnsmasq_time(); -=20 - /* 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 =3D socket(family, SOCK_DGRAM, 0)) !=3D -1) - { - union mysockaddr addr; -- unsigned int ports_avail =3D 65536u - (unsigned short)daemon->min_por= t; -+ unsigned int ports_avail =3D ((unsigned short)daemon->max_port - (uns= igned short)daemon->min_port) + 1; - int tries =3D ports_avail < 30 ? 3 * ports_avail : 100; -=20 - memset(&addr, 0, sizeof(addr)); -@@ -1132,8 +1132,8 @@ int random_sock(int family) - { - unsigned short port =3D rand16(); - =20 -- if (daemon->min_port !=3D 0) -- port =3D htons(daemon->min_port + (port % ((unsigned short)ports_ava= il))); -+ if (daemon->min_port !=3D 0 || daemon->max_port !=3D MAX_PORT) -+ port =3D htons(daemon->min_port + (port % ((unsigned short)po= rts_avail))); - =20 - if (family =3D=3D AF_INET)=20 - { -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 -=20 - #ifdef HAVE_GETOPT_LONG -@@ -271,6 +272,7 @@ static const struct myoption opts[] =3D - { "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, "[=3D]", gettext_noop("Use alternative po= rts for DHCP."), NULL }, - { LOPT_NAPTR, ARG_DUP, ",", gettext_noop("Specify NAPTR DNS = record."), NULL }, - { LOPT_MINPORT, ARG_ONE, "", gettext_noop("Specify lowest port avai= lable for DNS query transmission."), NULL }, -+ { LOPT_MAXPORT, ARG_ONE, "", gettext_noop("Specify highest port ava= ilable for DNS query transmission."), NULL }, - { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully quali= fied domain names for DHCP clients."), NULL }, - { LOPT_GEN_NAMES, ARG_DUP, "[=3Dtag:]", gettext_noop("Generate hostn= ames based on MAC address for nameless clients."), NULL}, - { LOPT_PROXY, ARG_DUP, "[=3D]...", gettext_noop("Use these DHCP r= elays as full proxies."), NULL }, -@@ -2512,6 +2515,11 @@ static int one_opt(int option, char *arg, char *errst= r, char *gen_err, int comma - ret_err(gen_err); - break; -=20 -+ 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_op= ts) - daemon->soa_refresh =3D SOA_REFRESH; - daemon->soa_retry =3D SOA_RETRY; - daemon->soa_expiry =3D SOA_EXPIRY; -+ daemon->max_port =3D MAX_PORT; -=20 - add_txt("version.bind", "dnsmasq-" VERSION, 0 ); - add_txt("authors.bind", "Simon Kelley", 0); ---=20 -1.7.10.4 - --=20 2.7.0 --===============5376467388965487908==--