dnsmasq: 2.76test10 with latest patches (001-004)
Message ID | 1456507768-1796-1-git-send-email-matthias.fischer@ipfire.org |
---|---|
State | Accepted |
Commit | 3b9815eb87e83a1b24e85ce0eab14a962b62ccd0 |
Headers |
Return-Path: <development-bounces@lists.ipfire.org> Received: from mail01.ipfire.org (hedwig.ipfire.org [172.28.1.200]) by web02.ipfire.org (Postfix) with ESMTP id AC5A86270B for <patchwork@ipfire.org>; Fri, 26 Feb 2016 18:29:46 +0100 (CET) Received: from mail01.ipfire.org (localhost [IPv6:::1]) by mail01.ipfire.org (Postfix) with ESMTP id 4584A103F; Fri, 26 Feb 2016 18:29:45 +0100 (CET) Received: from Devel.localdomain (p5DD83428.dip0.t-ipconnect.de [93.216.52.40]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by mail01.ipfire.org (Postfix) with ESMTPSA id 1F3E6CBB for <development@lists.ipfire.org>; Fri, 26 Feb 2016 18:29:34 +0100 (CET) From: Matthias Fischer <matthias.fischer@ipfire.org> To: development@lists.ipfire.org Subject: [PATCH] dnsmasq: 2.76test10 with latest patches (001-004) Date: Fri, 26 Feb 2016 18:29:28 +0100 Message-Id: <1456507768-1796-1-git-send-email-matthias.fischer@ipfire.org> X-Mailer: git-send-email 2.7.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: development@lists.ipfire.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: IPFire development talk <development.lists.ipfire.org> List-Unsubscribe: <http://lists.ipfire.org/mailman/options/development>, <mailto:development-request@lists.ipfire.org?subject=unsubscribe> List-Archive: <http://lists.ipfire.org/pipermail/development/> List-Post: <mailto:development@lists.ipfire.org> List-Help: <mailto:development-request@lists.ipfire.org?subject=help> List-Subscribe: <http://lists.ipfire.org/mailman/listinfo/development>, <mailto:development-request@lists.ipfire.org?subject=subscribe> Errors-To: development-bounces@lists.ipfire.org Sender: "Development" <development-bounces@lists.ipfire.org> |
Message
Matthias Fischer
Feb. 27, 2016, 4:29 a.m. UTC
This is 'dnsmasq 2.76test10', based on current 'next', containing latest patches.
Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org>
---
lfs/dnsmasq | 39 +-
...TL_parameter_to_--host-record_and_--cname.patch | 265 +++
...01-include_0_0_0_0_8_in_DNS_rebind_checks.patch | 41 -
.../dnsmasq/002-Add_--dhcp-ttl_option.patch | 117 ++
...subnet_to_allow_arbitary_subnet_addresses.patch | 271 ---
src/patches/dnsmasq/003-Update_CHANGELOG.patch | 17 +
...h_zones_locally_when_localise_queries_set.patch | 34 -
.../dnsmasq/004-Add_--tftp-mtu_option.patch | 136 ++
.../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 -
34 files changed, 542 insertions(+), 6603 deletions(-)
create mode 100644 src/patches/dnsmasq/001-Add_TTL_parameter_to_--host-record_and_--cname.patch
delete mode 100644 src/patches/dnsmasq/001-include_0_0_0_0_8_in_DNS_rebind_checks.patch
create mode 100644 src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
delete mode 100644 src/patches/dnsmasq/002-enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch
create mode 100644 src/patches/dnsmasq/003-Update_CHANGELOG.patch
delete mode 100644 src/patches/dnsmasq/003-dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_queries_set.patch
create mode 100644 src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
delete mode 100644 src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp-option.patch
delete mode 100644 src/patches/dnsmasq/005-suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch
delete mode 100644 src/patches/dnsmasq/006-clarify_man_page_on_RDNSS_set_in_router_advertisement.patch
delete mode 100644 src/patches/dnsmasq/007-handle_signed_dangling_CNAME_replies_to_DS_queries.patch
delete mode 100644 src/patches/dnsmasq/008-DHCPv6_option_56_does_not_hold_an_address_list.patch
delete mode 100644 src/patches/dnsmasq/009-Respect_the_--no_resolv_flag_in_inotify_code.patch
delete mode 100644 src/patches/dnsmasq/010-Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch
delete mode 100644 src/patches/dnsmasq/011-Catch_errors_from_sendmsg_in_DHCP_code.patch
delete mode 100644 src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus-priv.patch
delete mode 100644 src/patches/dnsmasq/013-Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch
delete mode 100644 src/patches/dnsmasq/014-Handle_unknown_DS_hash_algos_correctly.patch
delete mode 100644 src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf-dir.patch
delete mode 100644 src/patches/dnsmasq/016-Major_rationalisation_of_DNSSEC_validation.patch
delete mode 100644 src/patches/dnsmasq/017-Abandon_caching_RRSIGs_and_returning_them_from_cache.patch
delete mode 100644 src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch
delete mode 100644 src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
delete mode 100644 src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
delete mode 100644 src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
delete mode 100644 src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
delete mode 100644 src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
delete mode 100644 src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
delete mode 100644 src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
delete mode 100644 src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
delete mode 100644 src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
delete mode 100644 src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
delete mode 100644 src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
Comments
Hi, I merged this patch and the one after. Please give this version a good test as it is a pre-release version. You can maintain a branch where you integrate all new changes, but I think it is not required to send every single one to the mailing list. It creates a bit of noise and I think that unfortunately nobody is testing every single one any ways. Which is sad. Can we have maybe one aggregated patch after every release of a Core Update? So we always have the latest version of dnsmasq in the updates? Best, -Michael On Fri, 2016-02-26 at 18:29 +0100, Matthias Fischer wrote: > This is 'dnsmasq 2.76test10', based on current 'next', containing > latest patches. > > Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org> > --- > lfs/dnsmasq | 39 +- > ...TL_parameter_to_--host-record_and_--cname.patch | 265 +++ > ...01-include_0_0_0_0_8_in_DNS_rebind_checks.patch | 41 - > .../dnsmasq/002-Add_--dhcp-ttl_option.patch | 117 ++ > ...subnet_to_allow_arbitary_subnet_addresses.patch | 271 --- > src/patches/dnsmasq/003-Update_CHANGELOG.patch | 17 + > ...h_zones_locally_when_localise_queries_set.patch | 34 - > .../dnsmasq/004-Add_--tftp-mtu_option.patch | 136 ++ > .../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 - > 34 files changed, 542 insertions(+), 6603 deletions(-) > create mode 100644 src/patches/dnsmasq/001-Add_TTL_parameter_to_ > --host-record_and_--cname.patch > delete mode 100644 src/patches/dnsmasq/001- > include_0_0_0_0_8_in_DNS_rebind_checks.patch > create mode 100644 src/patches/dnsmasq/002-Add_--dhcp- > ttl_option.patch > delete mode 100644 src/patches/dnsmasq/002- > enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch > create mode 100644 src/patches/dnsmasq/003-Update_CHANGELOG.patch > delete mode 100644 src/patches/dnsmasq/003- > dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que > ries_set.patch > create mode 100644 src/patches/dnsmasq/004-Add_--tftp- > mtu_option.patch > delete mode 100644 src/patches/dnsmasq/004- > fix_behaviour_of_empty_dhcp-option.patch > delete mode 100644 src/patches/dnsmasq/005- > suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch > delete mode 100644 src/patches/dnsmasq/006- > clarify_man_page_on_RDNSS_set_in_router_advertisement.patch > delete mode 100644 src/patches/dnsmasq/007- > handle_signed_dangling_CNAME_replies_to_DS_queries.patch > delete mode 100644 src/patches/dnsmasq/008- > DHCPv6_option_56_does_not_hold_an_address_list.patch > delete mode 100644 src/patches/dnsmasq/009-Respect_the_ > --no_resolv_flag_in_inotify_code.patch > delete mode 100644 src/patches/dnsmasq/010- > Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch > delete mode 100644 src/patches/dnsmasq/011- > Catch_errors_from_sendmsg_in_DHCP_code.patch > delete mode 100644 src/patches/dnsmasq/012- > Update_list_of_subnet_for_--bogus-priv.patch > delete mode 100644 src/patches/dnsmasq/013- > Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch > delete mode 100644 src/patches/dnsmasq/014- > Handle_unknown_DS_hash_algos_correctly.patch > delete mode 100644 src/patches/dnsmasq/015- > Fix_crash_at_start_up_with_conf-dir.patch > delete mode 100644 src/patches/dnsmasq/016- > Major_rationalisation_of_DNSSEC_validation.patch > delete mode 100644 src/patches/dnsmasq/017- > Abandon_caching_RRSIGs_and_returning_them_from_cache.patch > delete mode 100644 src/patches/dnsmasq/018- > Move_code_which_caches_DS_records_to_a_more_logical_place.patch > delete mode 100644 src/patches/dnsmasq/019-Generalise_RR- > filtering_code_for_use_with_EDNS0.patch > delete mode 100644 src/patches/dnsmasq/020- > DNSSEC_validation_tweak.patch > delete mode 100644 src/patches/dnsmasq/021- > Tweaks_to_EDNS0_handling_in_DNS_replies.patch > delete mode 100644 src/patches/dnsmasq/022-Tidy_up_DNSSEC_non- > existence_code_Check_zone_status_is_NSEC_proof_bad.patch > delete mode 100644 src/patches/dnsmasq/023- > Fix_brace_botch_in_dnssec_validate_ds.patch > delete mode 100644 src/patches/dnsmasq/024- > Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p > atch > delete mode 100644 src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > delete mode 100644 src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > delete mode 100644 src/patches/dnsmasq/027- > Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch > delete mode 100644 src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch > delete mode 100644 src/patches/dnsmasq/029- > NSEC3_check_RFC5155_para_8_2.patch > > diff --git a/lfs/dnsmasq b/lfs/dnsmasq > index 8058663..29d7895 100644 > --- a/lfs/dnsmasq > +++ b/lfs/dnsmasq > @@ -1,7 +1,7 @@ > #################################################################### > ########### > # > # > # IPFire.org - A linux based > firewall # > -# Copyright (C) 2015 Michael Tremer & Christian > Schmidt # > +# Copyright (C) 2016 Michael Tremer & Christian > Schmidt # > # > # > # 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 # > @@ -24,7 +24,7 @@ > > include Config > > -VER = 2.75 > +VER = 2.76test10 > > THISAPP = dnsmasq-$(VER) > DL_FILE = $(THISAPP).tar.xz > @@ -43,7 +43,7 @@ objects = $(DL_FILE) > > $(DL_FILE) = $(DL_FROM)/$(DL_FILE) > > -$(DL_FILE)_MD5 = 887236f1ddde6eb57cdb9d01916c9f72 > +$(DL_FILE)_MD5 = 4b51474ed6081b18c61407077f254cf7 > > install : $(TARGET) > > @@ -73,35 +73,10 @@ $(subst %,%_MD5,$(objects)) : > $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) > @$(PREBUILD) > @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf > $(DIR_DL)/$(DL_FILE) > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/001- > include_0_0_0_0_8_in_DNS_rebind_checks.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/002- > enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/003- > dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que > ries_set.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp- > option.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/005- > suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/006- > clarify_man_page_on_RDNSS_set_in_router_advertisement.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/007- > handle_signed_dangling_CNAME_replies_to_DS_queries.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/008- > DHCPv6_option_56_does_not_hold_an_address_list.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/009-Respect_the_ > --no_resolv_flag_in_inotify_code.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/010- > Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/011- > Catch_errors_from_sendmsg_in_DHCP_code.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus- > priv.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/013- > Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/014- > Handle_unknown_DS_hash_algos_correctly.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf- > dir.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/016- > Major_rationalisation_of_DNSSEC_validation.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/017- > Abandon_caching_RRSIGs_and_returning_them_from_cache.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/018- > Move_code_which_caches_DS_records_to_a_more_logical_place.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/019-Generalise_RR- > filtering_code_for_use_with_EDNS0.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/021- > Tweaks_to_EDNS0_handling_in_DNS_replies.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non- > existence_code_Check_zone_status_is_NSEC_proof_bad.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/023- > Fix_brace_botch_in_dnssec_validate_ds.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/024- > Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p > atch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by- > one_in_DNSSEC_hostname_cmp.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch > - cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host- > record_and_--cname.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/003-Update_CHANGELOG.patch > + cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch > cd $(DIR_APP) && patch -Np1 -i > $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease- > file.patch > > cd $(DIR_APP) && sed -i src/config.h \ > diff --git a/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host- > record_and_--cname.patch b/src/patches/dnsmasq/001- > Add_TTL_parameter_to_--host-record_and_--cname.patch > new file mode 100644 > index 0000000..86fbc9c > --- /dev/null > +++ b/src/patches/dnsmasq/001-Add_TTL_parameter_to_--host- > record_and_--cname.patch > @@ -0,0 +1,265 @@ > +From df3d54f776a3c9b60735b45c0b7fd88b66a2d5c4 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Wed, 24 Feb 2016 21:03:38 +0000 > +Subject: [PATCH] Add TTL parameter to --host-record and --cname. > + > +--- > + man/dnsmasq.8 | 12 ++++++++++-- > + src/cache.c | 7 +++++++ > + src/dnsmasq.h | 2 ++ > + src/option.c | 46 ++++++++++++++++++++++++++++++++++++++-------- > + src/rfc1035.c | 6 +++++- > + 5 files changed, 62 insertions(+), 11 deletions(-) > + > +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 > +index b782eaf..7bc1394 100644 > +--- a/man/dnsmasq.8 > ++++ b/man/dnsmasq.8 > +@@ -529,7 +529,7 @@ zone files: the port, weight and priority > numbers are in a different > + order. More than one SRV record for a given service/domain is > allowed, > + all that match are returned. > + .TP > +-.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6- > address>] > ++.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6- > address>][,<TTL>] > + Add A, AAAA and PTR records to the DNS. This adds one or more names > to > + the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name > may > + appear in more than one > +@@ -546,6 +546,10 @@ is in effect. Short and long names may appear > in the same > + .B host-record, > + eg. > + .B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100 > ++ > ++If the time-to-live is given, it overrides the default, which is > zero > ++or the value of --local-ttl. The value is a positive integer and > gives > ++the time-to-live in seconds. > + .TP > + .B \-Y, --txt-record=<name>[[,<text>],<text>] > + Return a TXT DNS record. The value of TXT record is a set of > strings, > +@@ -559,7 +563,7 @@ Return a PTR DNS record. > + .B --naptr- > record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<repla > cement>] > + Return an NAPTR DNS record, as specified in RFC3403. > + .TP > +-.B --cname=<cname>,<target> > ++.B --cname=<cname>,<target>[,<TTL>] > + Return a CNAME record which indicates that <cname> is really > + <target>. There are significant limitations on the target; it must > be a > + DNS name which is known to dnsmasq from /etc/hosts (or additional > +@@ -568,6 +572,10 @@ hosts files), from DHCP, from --interface-name > or from another > + If the target does not satisfy this > + criteria, the whole cname is ignored. The cname must be unique, but > it > + is permissable to have more than one cname pointing to the same > target. > ++ > ++If the time-to-live is given, it overrides the default, which is > zero > ++or the value of -local-ttl. The value is a positive integer and > gives > ++the time-to-live in seconds. > + .TP > + .B --dns-rr=<name>,<RR-number>,[<hex data>] > + Return an arbitrary DNS Resource Record. The number is the type of > the > +diff --git a/src/cache.c b/src/cache.c > +index a9eaa65..4ecd535 100644 > +--- a/src/cache.c > ++++ b/src/cache.c > +@@ -778,6 +778,7 @@ static void add_hosts_cname(struct crec *target) > + (crec = whine_malloc(sizeof(struct crec)))) > + { > + crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | > F_CNAME; > ++ crec->ttd = a->ttl; > + crec->name.namep = a->alias; > + crec->addr.cname.target.cache = target; > + crec->addr.cname.uid = target->uid; > +@@ -981,6 +982,7 @@ int read_hostsfile(char *filename, unsigned int > index, int cache_size, struct cr > + strcat(cache->name.sname, "."); > + strcat(cache->name.sname, domain_suffix); > + cache->flags = flags; > ++ cache->ttd = daemon->local_ttl; > + add_hosts_entry(cache, &addr, addrlen, index, > rhash, hashsz); > + name_count++; > + } > +@@ -988,6 +990,7 @@ int read_hostsfile(char *filename, unsigned int > index, int cache_size, struct cr > + { > + strcpy(cache->name.sname, canon); > + cache->flags = flags; > ++ cache->ttd = daemon->local_ttl; > + add_hosts_entry(cache, &addr, addrlen, index, > rhash, hashsz); > + name_count++; > + } > +@@ -1057,6 +1060,7 @@ void cache_reload(void) > + ((cache = whine_malloc(sizeof(struct crec))))) > + { > + cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL > | F_CONFIG; > ++ cache->ttd = a->ttl; > + cache->name.namep = a->alias; > + cache->addr.cname.target.int_name = intr; > + cache->addr.cname.uid = SRC_INTERFACE; > +@@ -1071,6 +1075,7 @@ void cache_reload(void) > + (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds- > >digestlen))) > + { > + cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | > F_NAMEP; > ++ cache->ttd = daemon->local_ttl; > + cache->name.namep = ds->name; > + cache->addr.ds.keylen = ds->digestlen; > + cache->addr.ds.algo = ds->algo; > +@@ -1095,6 +1100,7 @@ void cache_reload(void) > + (cache = whine_malloc(sizeof(struct crec)))) > + { > + cache->name.namep = nl->name; > ++ cache->ttd = hr->ttl; > + cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | > F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG; > + add_hosts_entry(cache, (struct all_addr *)&hr->addr, > INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); > + } > +@@ -1103,6 +1109,7 @@ void cache_reload(void) > + (cache = whine_malloc(sizeof(struct crec)))) > + { > + cache->name.namep = nl->name; > ++ cache->ttd = hr->ttl; > + cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | > F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG; > + add_hosts_entry(cache, (struct all_addr *)&hr->addr6, > IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); > + } > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 6d1c5ae..6344df5 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -308,6 +308,7 @@ struct ptr_record { > + }; > + > + struct cname { > ++ int ttl; > + char *alias, *target; > + struct cname *next; > + }; > +@@ -344,6 +345,7 @@ struct auth_zone { > + > + > + struct host_record { > ++ int ttl; > + struct name_list { > + char *name; > + struct name_list *next; > +diff --git a/src/option.c b/src/option.c > +index c98bdc9..7c5e6bc 100644 > +--- a/src/option.c > ++++ b/src/option.c > +@@ -448,20 +448,20 @@ static struct { > + { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate > hostnames based on MAC address for nameless clients."), NULL}, > + { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these > DHCP relays as full proxies."), NULL }, > + { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", > gettext_noop("Relay DHCP requests to a remote server"), NULL}, > +- { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify > alias name for LOCAL DNS name."), NULL }, > ++ { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", > gettext_noop("Specify alias name for LOCAL DNS name."), NULL }, > + { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", > gettext_noop("Prompt to send to PXE clients."), NULL }, > + { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service > for PXE menu."), NULL }, > + { LOPT_TEST, 0, NULL, gettext_noop("Check configuration > syntax."), NULL }, > + { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add > requestor's MAC address to forwarded DNS queries."), NULL }, > + { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", > gettext_noop("Add specified IP subnet to forwarded DNS queries."), > NULL }, > +- { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client > identification to forwarded DNS queries."), NULL }, > ++ { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client > identification to forwarded DNS queries."), NULL }, > + { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC > validation results from upstream nameservers."), NULL }, > + { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to > allocate sequential IP addresses to DHCP clients."), NULL }, > + { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy > connection-track mark from queries to upstream connections."), NULL > }, > + { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP > clients to do their own DDNS updates."), NULL }, > + { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements > for interfaces doing DHCPv6"), NULL }, > + { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", > gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, > +- { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", > gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, > ++ { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", > gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, > + { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", > gettext_noop("Specify arbitrary DNS resource record"), NULL }, > + { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to > interfaces in use - check for new interfaces"), NULL }, > + { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", > gettext_noop("Export local names to global DNS"), NULL }, > +@@ -3692,12 +3692,15 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > + case LOPT_CNAME: /* --cname */ > + { > + struct cname *new; > +- char *alias; > +- char *target; > ++ char *alias, *target, *ttls; > ++ int ttl = -1; > + > + if (!(comma = split(arg))) > + ret_err(gen_err); > + > ++ if ((ttls = split(comma)) && !atoi_check(ttls, &ttl)) > ++ ret_err(_("bad TTL")); > ++ > + alias = canonicalise_opt(arg); > + target = canonicalise_opt(comma); > + > +@@ -3713,6 +3716,7 @@ static int one_opt(int option, char *arg, char > *errstr, char *gen_err, int comma > + daemon->cnames = new; > + new->alias = alias; > + new->target = target; > ++ new->ttl = ttl; > + } > + > + break; > +@@ -3913,14 +3917,22 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > + { > + struct host_record *new = opt_malloc(sizeof(struct > host_record)); > + memset(new, 0, sizeof(struct host_record)); > +- > ++ new->ttl = -1; > ++ > + if (!arg || !(comma = split(arg))) > + ret_err(_("Bad host-record")); > + > + while (arg) > + { > + struct all_addr addr; > +- if (inet_pton(AF_INET, arg, &addr)) > ++ char *dig; > ++ > ++ for (dig = arg; *dig != 0; dig++) > ++ if (*dig < '0' || *dig > '9') > ++ break; > ++ if (*dig == 0) > ++ new->ttl = atoi(arg); > ++ else if (inet_pton(AF_INET, arg, &addr)) > + new->addr = addr.addr.addr4; > + #ifdef HAVE_IPV6 > + else if (inet_pton(AF_INET6, arg, &addr)) > +@@ -4601,7 +4613,25 @@ void read_opts(int argc, char **argv, char > *compile_opts) > + } > + } > + } > +- > ++ > ++ if (daemon->host_records) > ++ { > ++ struct host_record *hr; > ++ > ++ for (hr = daemon->host_records; hr; hr = hr->next) > ++ if (hr->ttl == -1) > ++ hr->ttl = daemon->local_ttl; > ++ } > ++ > ++ if (daemon->cnames) > ++ { > ++ struct cname *cn; > ++ > ++ for (cn = daemon->cnames; cn; cn = cn->next) > ++ if (cn->ttl == -1) > ++ cn->ttl = daemon->local_ttl; > ++ } > ++ > + if (daemon->if_addrs) > + { > + struct iname *tmp; > +diff --git a/src/rfc1035.c b/src/rfc1035.c > +index 9c0ddb5..3535a71 100644 > +--- a/src/rfc1035.c > ++++ b/src/rfc1035.c > +@@ -1169,9 +1169,13 @@ static unsigned long crec_ttl(struct crec > *crecp, time_t now) > + /* Return 0 ttl for DHCP entries, which might change > + before the lease expires. */ > + > +- if (crecp->flags & (F_IMMORTAL | F_DHCP)) > ++ if (crecp->flags & F_DHCP) > + return daemon->local_ttl; > + > ++ /* Immortal entries other than DHCP are local, and hold TTL in > TTD field. */ > ++ if (crecp->flags & F_IMMORTAL) > ++ return crecp->ttd; > ++ > + /* Return the Max TTL value if it is lower then the actual TTL */ > + if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < > daemon->max_ttl)) > + return crecp->ttd - now; > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/001- > include_0_0_0_0_8_in_DNS_rebind_checks.patch > b/src/patches/dnsmasq/001- > include_0_0_0_0_8_in_DNS_rebind_checks.patch > deleted file mode 100644 > index 8a2557a..0000000 > --- a/src/patches/dnsmasq/001- > include_0_0_0_0_8_in_DNS_rebind_checks.patch > +++ /dev/null > @@ -1,41 +0,0 @@ > -From d2aa7dfbb6d1088dcbea9fecc61b9293b320eb95 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Mon, 3 Aug 2015 21:52:12 +0100 > -Subject: [PATCH] Include 0.0.0.0/8 in DNS rebind checks. > - > ---- > - CHANGELOG | 7 +++++++ > - src/rfc1035.c | 3 ++- > - 2 files changed, 9 insertions(+), 1 deletion(-) > - > -diff --git a/CHANGELOG b/CHANGELOG > -index 901da47..3f4026d 100644 > ---- a/CHANGELOG > -+++ b/CHANGELOG > -@@ -1,3 +1,10 @@ > -+version 2.76 > -+ Include 0.0.0.0/8 in DNS rebind checks. This range > -+ translates to hosts on the local network, or, at > -+ least, 0.0.0.0 accesses the local host, so could > -+ be targets for DNS rebinding. See RFC 5735 section 3 > -+ for details. Thanks to Stephen Röttger for the bug > report. > -+ > - version 2.75 > - Fix reversion on 2.74 which caused 100% CPU use when a > - dhcp-script is configured. Thanks to Adrian Davey for > -diff --git a/src/rfc1035.c b/src/rfc1035.c > -index 56647b0..29e9e65 100644 > ---- a/src/rfc1035.c > -+++ b/src/rfc1035.c > -@@ -728,7 +728,8 @@ int private_net(struct in_addr addr, int > ban_localhost) > - in_addr_t ip_addr = ntohl(addr.s_addr); > - > - return > -- (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* > 127.0.0.0/8 (loopback) */ || > -+ (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* > 127.0.0.0/8 (loopback) */ || > -+ ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. > "here" network */ || > - ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 > (private) */ || > - ((ip_addr & 0xFF000000) == 0x0A000000) /* > 10.0.0.0/8 (private) */ || > - ((ip_addr & 0xFFF00000) == 0xAC100000) /* > 172.16.0.0/12 (private) */ || > --- > -1.7.10.4 > diff --git a/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch > b/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch > new file mode 100644 > index 0000000..45e3b9b > --- /dev/null > +++ b/src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch > @@ -0,0 +1,117 @@ > +From 832e47beab95c2918b5264f0504f2fe6fe523e4c Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Wed, 24 Feb 2016 21:24:45 +0000 > +Subject: [PATCH] Add --dhcp-ttl option. > + > +--- > + man/dnsmasq.8 | 5 ++++- > + src/dnsmasq.h | 2 +- > + src/option.c | 13 +++++++++++-- > + src/rfc1035.c | 2 +- > + 4 files changed, 17 insertions(+), 5 deletions(-) > + > +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 > +index 7bc1394..2bcce20 100644 > +--- a/man/dnsmasq.8 > ++++ b/man/dnsmasq.8 > +@@ -60,7 +60,7 @@ in the same way as for DHCP-derived names. Note > that this does not > + apply to domain names in cnames, PTR records, TXT records etc. > + .TP > + .B \-T, --local-ttl=<time> > +-When replying with information from /etc/hosts or the DHCP leases > ++When replying with information from /etc/hosts or configuration or > the DHCP leases > + file dnsmasq by default sets the time-to-live field to zero, > meaning > + that the requester should not itself cache the information. This is > + the correct thing to do in almost all situations. This option > allows a > +@@ -68,6 +68,9 @@ time-to-live (in seconds) to be given for these > replies. This will > + reduce the load on the server at the expense of clients using stale > + data under some circumstances. > + .TP > ++.B --dhcp-ttl=<time> > ++As for --local-ttl, but affects only replies with information from > DHCP leases. If both are given, --dhcp-ttl applies for DHCP > information, and --local-ttl for others. Setting this to zero > eliminates the effect of --local-ttl for DHCP. > ++.TP > + .B --neg-ttl=<time> > + Negative replies from upstream servers normally contain time-to- > live > + information in SOA records which dnsmasq uses for caching. If the > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 6344df5..9f73c3b 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -955,7 +955,7 @@ extern struct daemon { > + int max_logs; /* queue limit */ > + int cachesize, ftabsize; > + int port, query_port, min_port, max_port; > +- unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, > max_cache_ttl, auth_ttl; > ++ unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, > max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl; > + char *dns_client_id; > + struct hostsfile *addn_hosts; > + struct dhcp_context *dhcp, *dhcp6; > +diff --git a/src/option.c b/src/option.c > +index 7c5e6bc..3f6d162 100644 > +--- a/src/option.c > ++++ b/src/option.c > +@@ -157,6 +157,7 @@ struct myoption { > + #define LOPT_MAXPORT 345 > + #define LOPT_CPE_ID 346 > + #define LOPT_SCRIPT_ARP 347 > ++#define LOPT_DHCPTTL 348 > + > + #ifdef HAVE_GETOPT_LONG > + static const struct option opts[] = > +@@ -319,6 +320,7 @@ static const struct myoption opts[] = > + { "quiet-ra", 0, 0, LOPT_QUIET_RA }, > + { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT }, > + { "script-arp", 0, 0, LOPT_SCRIPT_ARP }, > ++ { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL }, > + { NULL, 0, 0, 0 } > + }; > + > +@@ -485,9 +487,10 @@ static struct { > + { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log > routine DHCP."), NULL }, > + { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not > log routine DHCPv6."), NULL }, > + { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log > RA."), NULL }, > +- { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, > gettext_noop("Accept queries only from directly-connected networks"), > NULL }, > +- { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect > and remove DNS forwarding loops"), NULL }, > ++ { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, > gettext_noop("Accept queries only from directly-connected > networks."), NULL }, > ++ { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect > and remove DNS forwarding loops."), NULL }, > + { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS > responses containing ipaddr."), NULL }, > ++ { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS > responses with DHCP-derived addresses."), NULL }, > + { 0, 0, NULL, NULL, NULL } > + }; > + > +@@ -2580,6 +2583,7 @@ static int one_opt(int option, char *arg, char > *errstr, char *gen_err, int comma > + case LOPT_MINCTTL: /* --min-cache-ttl */ > + case LOPT_MAXCTTL: /* --max-cache-ttl */ > + case LOPT_AUTHTTL: /* --auth-ttl */ > ++ case LOPT_DHCPTTL: /* --dhcp-ttl */ > + { > + int ttl; > + if (!atoi_check(arg, &ttl)) > +@@ -2598,6 +2602,11 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > + daemon->max_cache_ttl = (unsigned long)ttl; > + else if (option == LOPT_AUTHTTL) > + daemon->auth_ttl = (unsigned long)ttl; > ++ else if (option == LOPT_DHCPTTL) > ++ { > ++ daemon->dhcp_ttl = (unsigned long)ttl; > ++ daemon->use_dhcp_ttl = 1; > ++ } > + else > + daemon->local_ttl = (unsigned long)ttl; > + break; > +diff --git a/src/rfc1035.c b/src/rfc1035.c > +index 3535a71..8f1e3b4 100644 > +--- a/src/rfc1035.c > ++++ b/src/rfc1035.c > +@@ -1170,7 +1170,7 @@ static unsigned long crec_ttl(struct crec > *crecp, time_t now) > + before the lease expires. */ > + > + if (crecp->flags & F_DHCP) > +- return daemon->local_ttl; > ++ return daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon- > >local_ttl; > + > + /* Immortal entries other than DHCP are local, and hold TTL in > TTD field. */ > + if (crecp->flags & F_IMMORTAL) > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/002- > enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch > b/src/patches/dnsmasq/002- > enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch > deleted file mode 100644 > index 2d3d6e4..0000000 > --- a/src/patches/dnsmasq/002- > enhance_add_subnet_to_allow_arbitary_subnet_addresses.patch > +++ /dev/null > @@ -1,271 +0,0 @@ > -From a7369bef8abd241c3d85633fa9c870943f091e76 Mon Sep 17 00:00:00 > 2001 > -From: Ed Bardsley <ebardsley@google.com> > -Date: Wed, 5 Aug 2015 21:17:18 +0100 > -Subject: [PATCH] Enhance --add-subnet to allow arbitary subnet > addresses. > - > ---- > - CHANGELOG | 4 ++++ > - man/dnsmasq.8 | 32 ++++++++++++++++++++----------- > - src/dnsmasq.h | 13 ++++++++++--- > - src/option.c | 59 > ++++++++++++++++++++++++++++++++++++++++++++++++++++----- > - src/rfc1035.c | 39 +++++++++++++++++++++++++++++++------- > - 5 files changed, 121 insertions(+), 26 deletions(-) > - > -diff --git a/CHANGELOG b/CHANGELOG > -index 3f4026d..bbc2834 100644 > ---- a/CHANGELOG > -+++ b/CHANGELOG > -@@ -4,6 +4,10 @@ version 2.76 > - least, 0.0.0.0 accesses the local host, so could > - be targets for DNS rebinding. See RFC 5735 section 3 > - for details. Thanks to Stephen Röttger for the bug > report. > -+ > -+ Enhance --add-subnet to allow arbitrary subnet > addresses. > -+ Thanks to Ed Barsley for the patch. > -+ > - > - version 2.75 > - Fix reversion on 2.74 which caused 100% CPU use when a > -diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 > -index c8913b5..a23c898 100644 > ---- a/man/dnsmasq.8 > -+++ b/man/dnsmasq.8 > -@@ -604,17 +604,27 @@ experimental. Also note that exposing MAC > addresses in this way may > - have security and privacy implications. The warning about caching > - given for --add-subnet applies to --add-mac too. > - .TP > --.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>] > --Add the subnet address of the requestor to the DNS queries which > are > --forwarded upstream. The amount of the address forwarded depends on > the > --prefix length parameter: 32 (128 for IPv6) forwards the whole > address, > --zero forwards none of it but still marks the request so that no > --upstream nameserver will add client address information either. The > --default is zero for both IPv4 and IPv6. Note that upstream > nameservers > --may be configured to return different results based on this > --information, but the dnsmasq cache does not take account. If a > dnsmasq > --instance is configured such that different results may be > encountered, > --caching should be disabled. > -+.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 > address>/]<IPv6 prefix length>]] > -+Add a subnet address to the DNS queries which are forwarded > -+upstream. If an address is specified in the flag, it will be used, > -+otherwise, the address of the requestor will be used. The amount of > -+the address forwarded depends on the prefix length parameter: 32 > (128 > -+for IPv6) forwards the whole address, zero forwards none of it but > -+still marks the request so that no upstream nameserver will add > client > -+address information either. The default is zero for both IPv4 and > -+IPv6. Note that upstream nameservers may be configured to return > -+different results based on this information, but the dnsmasq cache > -+does not take account. If a dnsmasq instance is configured such > that > -+different results may be encountered, caching should be disabled. > -+ > -+For example, > -+.B --add-subnet=24,96 > -+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 > requestors, respectively. > -+.B --add-subnet=1.2.3.4/24 > -+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 > requestors. > -+.B --add-subnet=1.2.3.4/24,1.2.3.4/24 > -+will add 1.2.3.0/24 for both IPv4 and IPv6 requestors. > -+ > - .TP > - .B \-c, --cache-size=<cachesize> > - Set the size of dnsmasq's cache. The default is 150 names. Setting > the cache size to zero disables caching. > -diff --git a/src/dnsmasq.h b/src/dnsmasq.h > -index cf1a782..f42acdb 100644 > ---- a/src/dnsmasq.h > -+++ b/src/dnsmasq.h > -@@ -541,6 +541,13 @@ struct iname { > - struct iname *next; > - }; > - > -+/* subnet parameters from command line */ > -+struct mysubnet { > -+ union mysockaddr addr; > -+ int addr_used; > -+ int mask; > -+}; > -+ > - /* resolv-file parms from command-line */ > - struct resolvc { > - struct resolvc *next; > -@@ -935,9 +942,9 @@ extern struct daemon { > - struct auth_zone *auth_zones; > - struct interface_name *int_names; > - char *mxtarget; > -- int addr4_netmask; > -- int addr6_netmask; > -- char *lease_file; > -+ struct mysubnet *add_subnet4; > -+ struct mysubnet *add_subnet6; > -+ char *lease_file; > - char *username, *groupname, *scriptuser; > - char *luascript; > - char *authserver, *hostmaster; > -diff --git a/src/option.c b/src/option.c > -index ecc2619..746cd11 100644 > ---- a/src/option.c > -+++ b/src/option.c > -@@ -445,7 +445,7 @@ static struct { > - { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service > for PXE menu."), NULL }, > - { LOPT_TEST, 0, NULL, gettext_noop("Check configuration > syntax."), NULL }, > - { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's > MAC address to forwarded DNS queries."), NULL }, > -- { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", > gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), > NULL }, > -+ { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", > gettext_noop("Add specified IP subnet to forwarded DNS queries."), > NULL }, > - { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC > validation results from upstream nameservers."), NULL }, > - { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to > allocate sequential IP addresses to DHCP clients."), NULL }, > - { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy > connection-track mark from queries to upstream connections."), NULL > }, > -@@ -722,6 +722,20 @@ static void do_usage(void) > - > - #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0) > - > -+static char *parse_mysockaddr(char *arg, union mysockaddr *addr) > -+{ > -+ if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) > -+ addr->sa.sa_family = AF_INET; > -+#ifdef HAVE_IPV6 > -+ else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0) > -+ addr->sa.sa_family = AF_INET6; > -+#endif > -+ else > -+ return _("bad address"); > -+ > -+ return NULL; > -+} > -+ > - char *parse_server(char *arg, union mysockaddr *addr, union > mysockaddr *source_addr, char *interface, int *flags) > - { > - int source_port = 0, serv_port = NAMESERVER_PORT; > -@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char > *errstr, char *gen_err, int comma > - li = match_suffix->next; > - free(match_suffix->suffix); > - free(match_suffix); > -- } > -+ } > - break; > - } > - > -@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > - set_option_bool(OPT_CLIENT_SUBNET); > - if (arg) > - { > -+ char *err, *end; > - comma = split(arg); > -- if (!atoi_check(arg, &daemon->addr4_netmask) || > -- (comma && !atoi_check(comma, &daemon- > >addr6_netmask))) > -- ret_err(gen_err); > -+ > -+ struct mysubnet* new = opt_malloc(sizeof(struct > mysubnet)); > -+ if ((end = split_chr(arg, '/'))) > -+ { > -+ /* has subnet+len */ > -+ err = parse_mysockaddr(arg, &new->addr); > -+ if (err) > -+ ret_err(err); > -+ if (!atoi_check(end, &new->mask)) > -+ ret_err(gen_err); > -+ new->addr_used = 1; > -+ } > -+ else if (!atoi_check(arg, &new->mask)) > -+ ret_err(gen_err); > -+ > -+ daemon->add_subnet4 = new; > -+ > -+ new = opt_malloc(sizeof(struct mysubnet)); > -+ if (comma) > -+ { > -+ if ((end = split_chr(comma, '/'))) > -+ { > -+ /* has subnet+len */ > -+ err = parse_mysockaddr(comma, &new->addr); > -+ if (err) > -+ ret_err(err); > -+ if (!atoi_check(end, &new->mask)) > -+ ret_err(gen_err); > -+ new->addr_used = 1; > -+ } > -+ else > -+ { > -+ if (!atoi_check(comma, &new->mask)) > -+ ret_err(gen_err); > -+ } > -+ } > -+ daemon->add_subnet6 = new; > - } > - break; > - > -diff --git a/src/rfc1035.c b/src/rfc1035.c > -index 29e9e65..6a51b30 100644 > ---- a/src/rfc1035.c > -+++ b/src/rfc1035.c > -@@ -629,26 +629,47 @@ struct subnet_opt { > - #endif > - }; > - > -+static void *get_addrp(union mysockaddr *addr, const short family) > -+{ > -+#ifdef HAVE_IPV6 > -+ if (family == AF_INET6) > -+ return &addr->in6.sin6_addr; > -+#endif > -+ > -+ return &addr->in.sin_addr; > -+} > -+ > - static size_t calc_subnet_opt(struct subnet_opt *opt, union > mysockaddr *source) > - { > - /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subne > t-02 */ > - > - int len; > - void *addrp; > -+ int sa_family = source->sa.sa_family; > - > - #ifdef HAVE_IPV6 > - if (source->sa.sa_family == AF_INET6) > - { > -- opt->family = htons(2); > -- opt->source_netmask = daemon->addr6_netmask; > -- addrp = &source->in6.sin6_addr; > -+ opt->source_netmask = daemon->add_subnet6->mask; > -+ if (daemon->add_subnet6->addr_used) > -+ { > -+ sa_family = daemon->add_subnet6->addr.sa.sa_family; > -+ addrp = get_addrp(&daemon->add_subnet6->addr, sa_family); > -+ } > -+ else > -+ addrp = &source->in6.sin6_addr; > - } > - else > - #endif > - { > -- opt->family = htons(1); > -- opt->source_netmask = daemon->addr4_netmask; > -- addrp = &source->in.sin_addr; > -+ opt->source_netmask = daemon->add_subnet4->mask; > -+ if (daemon->add_subnet4->addr_used) > -+ { > -+ sa_family = daemon->add_subnet4->addr.sa.sa_family; > -+ addrp = get_addrp(&daemon->add_subnet4->addr, sa_family); > -+ } > -+ else > -+ addrp = &source->in.sin_addr; > - } > - > - opt->scope_netmask = 0; > -@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt > *opt, union mysockaddr *source) > - > - if (opt->source_netmask != 0) > - { > -+#ifdef HAVE_IPV6 > -+ opt->family = htons(sa_family == AF_INET6 ? 2 : 1); > -+#else > -+ opt->family = htons(1); > -+#endif > - len = ((opt->source_netmask - 1) >> 3) + 1; > - memcpy(opt->addr, addrp, len); > - if (opt->source_netmask & 7) > -@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - > - return len; > - } > -- > --- > -1.7.10.4 > diff --git a/src/patches/dnsmasq/003-Update_CHANGELOG.patch > b/src/patches/dnsmasq/003-Update_CHANGELOG.patch > new file mode 100644 > index 0000000..f04f943 > --- /dev/null > +++ b/src/patches/dnsmasq/003-Update_CHANGELOG.patch > @@ -0,0 +1,17 @@ > +X-Git-Url: http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=blobdiff > _plain;f=CHANGELOG;h=6d9ba490488f80ef565f459cef3c110bdf31212c;hp=1435 > 4f2506a7fbf8360cd32c96e1d7ce1bfeb3f9;hb=e06e6e34bffd781b7cefa49b25fb8 > ae863654ca2;hpb=832e47beab95c2918b5264f0504f2fe6fe523e4c > + > +diff --git a/CHANGELOG b/CHANGELOG > +index 14354f2..6d9ba49 100644 > +--- a/CHANGELOG > ++++ b/CHANGELOG > +@@ -48,6 +48,10 @@ version 2.76 > + (ie xx::0 to xx::ffff:ffff:ffff:ffff) > + Thanks to Laurent Bendel for spotting this problem. > + > ++ Add support for a TTL parameter in --host-record and > ++ --cname. > ++ > ++ Add --dhcp-ttl option. > + > + version 2.75 > + Fix reversion on 2.74 which caused 100% CPU use when a > diff --git a/src/patches/dnsmasq/003- > dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que > ries_set.patch b/src/patches/dnsmasq/003- > dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que > ries_set.patch > deleted file mode 100644 > index cfbcdfb..0000000 > --- a/src/patches/dnsmasq/003- > dont_answer_non_auth_queries_for_auth_zones_locally_when_localise_que > ries_set.patch > +++ /dev/null > @@ -1,34 +0,0 @@ > -From 3a3965ac21b1b759eab8799b6edb09195b671306 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sun, 9 Aug 2015 17:45:06 +0100 > -Subject: [PATCH] Don't answer non-auth queries for auth zones > locally when > - --localise-queries set. > - > ---- > - src/forward.c | 4 ++-- > - 1 file changed, 2 insertions(+), 2 deletions(-) > - > -diff --git a/src/forward.c b/src/forward.c > -index 2731b90..b76a974 100644 > ---- a/src/forward.c > -+++ b/src/forward.c > -@@ -1365,7 +1365,7 @@ void receive_query(struct listener *listen, > time_t now) > - > - #ifdef HAVE_AUTH > - /* find queries for zones we're authoritative for, and answer > them directly */ > -- if (!auth_dns) > -+ if (!auth_dns && !option_bool(OPT_LOCALISE)) > - for (zone = daemon->auth_zones; zone; zone = zone->next) > - if (in_zone(zone, daemon->namebuff, NULL)) > - { > -@@ -1904,7 +1904,7 @@ unsigned char *tcp_request(int confd, time_t > now, > - > - #ifdef HAVE_AUTH > - /* find queries for zones we're authoritative for, and > answer them directly */ > -- if (!auth_dns) > -+ if (!auth_dns && !option_bool(OPT_LOCALISE)) > - for (zone = daemon->auth_zones; zone; zone = zone- > >next) > - if (in_zone(zone, daemon->namebuff, NULL)) > - { > --- > -1.7.10.4 > diff --git a/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch > b/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch > new file mode 100644 > index 0000000..c06705a > --- /dev/null > +++ b/src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch > @@ -0,0 +1,136 @@ > +From bec366b4041df72b559e713f1c924177676e6eb0 Mon Sep 17 00:00:00 > 2001 > +From: Simon Kelley <simon@thekelleys.org.uk> > +Date: Wed, 24 Feb 2016 22:03:26 +0000 > +Subject: [PATCH] Add --tftp-mtu option. > + > +--- > + CHANGELOG | 4 ++++ > + man/dnsmasq.8 | 4 ++++ > + src/dnsmasq.h | 2 +- > + src/option.c | 10 +++++++++- > + src/tftp.c | 14 ++++++++++++-- > + 5 files changed, 30 insertions(+), 4 deletions(-) > + > +diff --git a/CHANGELOG b/CHANGELOG > +index 6d9ba49..9218b8c 100644 > +--- a/CHANGELOG > ++++ b/CHANGELOG > +@@ -53,6 +53,10 @@ version 2.76 > + > + Add --dhcp-ttl option. > + > ++ Add --tftp-mtu option. Thanks to Patrick McLean for > the > ++ initial patch. > ++ > ++ > + version 2.75 > + Fix reversion on 2.74 which caused 100% CPU use when a > + dhcp-script is configured. Thanks to Adrian Davey for > +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 > +index 2bcce20..3cf48cd 100644 > +--- a/man/dnsmasq.8 > ++++ b/man/dnsmasq.8 > +@@ -1810,6 +1810,10 @@ require about (2*n) + 10 descriptors. If > + .B --tftp-port-range > + is given, that can affect the number of concurrent connections. > + .TP > ++.B --tftp-mtu=<mtu size> > ++Use size as the ceiling of the MTU supported by the intervening > network when > ++negotiating TFTP blocksize, overriding the MTU setting of the local > interface if it is larger. > ++.TP > + .B --tftp-no-blocksize > + Stop the TFTP server from negotiating the "blocksize" option with a > + client. Some buggy clients request this option but then behave > badly > +diff --git a/src/dnsmasq.h b/src/dnsmasq.h > +index 9f73c3b..280ad9d 100644 > +--- a/src/dnsmasq.h > ++++ b/src/dnsmasq.h > +@@ -975,7 +975,7 @@ extern struct daemon { > + struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, > *dhcp_gen_names; > + struct dhcp_netid_list *force_broadcast, *bootp_dynamic; > + struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, > *dynamic_dirs; > +- int dhcp_max, tftp_max; > ++ int dhcp_max, tftp_max, tftp_mtu; > + int dhcp_server_port, dhcp_client_port; > + int start_tftp_port, end_tftp_port; > + unsigned int min_leasetime; > +diff --git a/src/option.c b/src/option.c > +index 3f6d162..765965f 100644 > +--- a/src/option.c > ++++ b/src/option.c > +@@ -158,7 +158,8 @@ struct myoption { > + #define LOPT_CPE_ID 346 > + #define LOPT_SCRIPT_ARP 347 > + #define LOPT_DHCPTTL 348 > +- > ++#define LOPT_TFTP_MTU 349 > ++ > + #ifdef HAVE_GETOPT_LONG > + static const struct option opts[] = > + #else > +@@ -244,6 +245,7 @@ static const struct myoption opts[] = > + { "tftp-unique-root", 0, 0, LOPT_APREF }, > + { "tftp-root", 1, 0, LOPT_PREFIX }, > + { "tftp-max", 1, 0, LOPT_TFTP_MAX }, > ++ { "tftp-mtu", 1, 0, LOPT_TFTP_MTU }, > + { "tftp-lowercase", 0, 0, LOPT_TFTP_LC }, > + { "ptr-record", 1, 0, LOPT_PTR }, > + { "naptr-record", 1, 0, LOPT_NAPTR }, > +@@ -432,6 +434,7 @@ static struct { > + { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access > only to files owned by the user running dnsmasq."), NULL }, > + { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not > terminate the service if TFTP directories are inaccessible."), NULL > }, > + { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum > number of conncurrent TFTP transfers (defaults to %s)."), "#" }, > ++ { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU > to use for TFTP transfers."), NULL }, > + { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the > TFTP blocksize extension."), NULL }, > + { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP > filenames to lowercase"), NULL }, > + { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", > gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL > }, > +@@ -2625,6 +2628,11 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > + ret_err(gen_err); > + break; > + > ++ case LOPT_TFTP_MTU: /* --tftp-mtu */ > ++ if (!atoi_check(arg, &daemon->tftp_mtu)) > ++ ret_err(gen_err); > ++ break; > ++ > + case LOPT_PREFIX: /* --tftp-prefix */ > + comma = split(arg); > + if (comma) > +diff --git a/src/tftp.c b/src/tftp.c > +index 00ed2fc..dc4aa85 100644 > +--- a/src/tftp.c > ++++ b/src/tftp.c > +@@ -103,8 +103,10 @@ void tftp_request(struct listener *listen, > time_t now) > + if (listen->iface) > + { > + addr = listen->iface->addr; > +- mtu = listen->iface->mtu; > + name = listen->iface->name; > ++ mtu = listen->iface->mtu; > ++ if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu) > ++ mtu = daemon->tftp_mtu; > + } > + else > + { > +@@ -234,9 +236,17 @@ void tftp_request(struct listener *listen, > time_t now) > + > + strncpy(ifr.ifr_name, name, IF_NAMESIZE); > + if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1) > +- mtu = ifr.ifr_mtu; > ++ { > ++ mtu = ifr.ifr_mtu; > ++ if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu) > ++ mtu = daemon->tftp_mtu; > ++ } > + } > + > ++ /* Failed to get interface mtu - can use configured value. */ > ++ if (mtu == 0) > ++ mtu = daemon->tftp_mtu; > ++ > + if (name) > + { > + /* check for per-interface prefix */ > +-- > +1.7.10.4 > + > diff --git a/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp- > option.patch b/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp- > option.patch > deleted file mode 100644 > index 492ada9..0000000 > --- a/src/patches/dnsmasq/004-fix_behaviour_of_empty_dhcp- > option.patch > +++ /dev/null > @@ -1,38 +0,0 @@ > -From 5e3e464ac4022ee0b3794513abe510817e2cf3ca Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 25 Aug 2015 23:08:39 +0100 > -Subject: [PATCH] Fix behaviour of empty dhcp-option=option6:dns- > server, which > - should inhibit sending option. > - > ---- > - src/rfc3315.c | 9 +++++---- > - 1 file changed, 5 insertions(+), 4 deletions(-) > - > -diff --git a/src/rfc3315.c b/src/rfc3315.c > -index 2665d0d..3f1f9ee 100644 > ---- a/src/rfc3315.c > -+++ b/src/rfc3315.c > -@@ -1320,15 +1320,16 @@ static struct dhcp_netid *add_options(struct > state *state, int do_refresh) > - > - if (opt_cfg->opt == OPTION6_REFRESH_TIME) > - done_refresh = 1; > -+ > -+ if (opt_cfg->opt == OPTION6_DNS_SERVER) > -+ done_dns = 1; > - > -- if (opt_cfg->flags & DHOPT_ADDR6) > -+ /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */ > -+ if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == > OPTION6_DNS_SERVER) > - { > - int len, j; > - struct in6_addr *a; > - > -- if (opt_cfg->opt == OPTION6_DNS_SERVER) > -- done_dns = 1; > -- > - for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg- > >len, j = 0; > - j < opt_cfg->len; j += IN6ADDRSZ, a++) > - if ((IN6_IS_ADDR_ULA_ZERO(a) && > IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) || > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/005- > suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch > b/src/patches/dnsmasq/005- > suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch > deleted file mode 100644 > index c7cee60..0000000 > --- a/src/patches/dnsmasq/005- > suggest_solution_to_ENOMEM_error_with_IPv6_multicast.patch > +++ /dev/null > @@ -1,50 +0,0 @@ > -From 9cdcfe9f19ffd45bac4e5b459879bf7c50a287ed Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Wed, 26 Aug 2015 22:38:08 +0100 > -Subject: [PATCH] Suggest solution to ENOMEM error with IPv6 > multicast. > - > ---- > - src/network.c | 13 ++++++++++--- > - 1 file changed, 10 insertions(+), 3 deletions(-) > - > -diff --git a/src/network.c b/src/network.c > -index a1d90c8..819302f 100644 > ---- a/src/network.c > -+++ b/src/network.c > -@@ -1076,23 +1076,30 @@ void join_multicast(int dienow) > - > - if ((daemon->doing_dhcp6 || daemon->relay6) && > - setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, > IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) > -- err = 1; > -+ err = errno; > - > - inet_pton(AF_INET6, ALL_SERVERS, > &mreq.ipv6mr_multiaddr); > - > - if (daemon->doing_dhcp6 && > - setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, > IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) > -- err = 1; > -+ err = errno; > - > - inet_pton(AF_INET6, ALL_ROUTERS, > &mreq.ipv6mr_multiaddr); > - > - if (daemon->doing_ra && > - setsockopt(daemon->icmp6fd, IPPROTO_IPV6, > IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) > -- err = 1; > -+ err = errno; > - > - if (err) > - { > - char *s = _("interface %s failed to join DHCPv6 > multicast group: %s"); > -+ errno = err; > -+ > -+#ifdef HAVE_LINUX_NETWORK > -+ if (errno == ENOMEM) > -+ my_syslog(LOG_ERR, _("try increasing > /proc/sys/net/core/optmem_max")); > -+#endif > -+ > - if (dienow) > - die(s, iface->name, EC_BADNET); > - else > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/006- > clarify_man_page_on_RDNSS_set_in_router_advertisement.patch > b/src/patches/dnsmasq/006- > clarify_man_page_on_RDNSS_set_in_router_advertisement.patch > deleted file mode 100644 > index 19c76e6..0000000 > --- a/src/patches/dnsmasq/006- > clarify_man_page_on_RDNSS_set_in_router_advertisement.patch > +++ /dev/null > @@ -1,35 +0,0 @@ > -From 20fd11e11a9d09edcea94de135396ae1541fbbab Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Wed, 26 Aug 2015 22:48:13 +0100 > -Subject: [PATCH] Clarify man page on RDNSS set in router > advertisement. > - > ---- > - man/dnsmasq.8 | 6 +++--- > - 1 file changed, 3 insertions(+), 3 deletions(-) > - > -diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 > -index a23c898..d51b10f 100644 > ---- a/man/dnsmasq.8 > -+++ b/man/dnsmasq.8 > -@@ -1687,15 +1687,15 @@ creation are handled by a different > protocol. When DHCP is in use, > - only a subset of this is needed, and dnsmasq can handle it, using > - existing DHCP configuration to provide most data. When RA is > enabled, > - dnsmasq will advertise a prefix for each dhcp-range, with default > --router and recursive DNS server as the relevant link-local address > on > --the machine running dnsmasq. By default, he "managed address" bits > are set, and > -+router as the relevant link-local address on > -+the machine running dnsmasq. By default, the "managed address" bits > are set, and > - the "use SLAAC" bit is reset. This can be changed for individual > - subnets with the mode keywords described in > - .B --dhcp-range. > - RFC6106 DNS parameters are included in the advertisements. By > default, > - the relevant link-local address of the machine running dnsmasq is > sent > - as recursive DNS server. If provided, the DHCPv6 options dns-server > and > --domain-search are used for RDNSS and DNSSL. > -+domain-search are used for the DNS server (RDNSS) and the domain > serach list (DNSSL). > - .TP > - .B --ra-param=<interface>,[high|low],[[<ra-interval>],<router > lifetime>] > - Set non-default values for router advertisements sent via an > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/007- > handle_signed_dangling_CNAME_replies_to_DS_queries.patch > b/src/patches/dnsmasq/007- > handle_signed_dangling_CNAME_replies_to_DS_queries.patch > deleted file mode 100644 > index 832a22e..0000000 > --- a/src/patches/dnsmasq/007- > handle_signed_dangling_CNAME_replies_to_DS_queries.patch > +++ /dev/null > @@ -1,30 +0,0 @@ > -From 6de81f1250fd323c9155de065d5a9dc200a6f20b Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Wed, 9 Sep 2015 22:51:13 +0100 > -Subject: [PATCH] Handle signed dangling CNAME replies to DS queries. > - > ---- > - src/dnssec.c | 7 ++----- > - 1 file changed, 2 insertions(+), 5 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 4deda24..67ce486 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1232,11 +1232,8 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - > - /* If we return STAT_NO_SIG, name contains the name of the DS > query */ > - if (val == STAT_NO_SIG) > -- { > -- *keyname = 0; > -- return val; > -- } > -- > -+ return val; > -+ > - /* If the key needed to validate the DS is on the same domain as > the DS, we'll > - loop getting nowhere. Stop that now. This can happen of the DS > answer comes > - from the DS's zone, and not the parent zone. */ > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/008- > DHCPv6_option_56_does_not_hold_an_address_list.patch > b/src/patches/dnsmasq/008- > DHCPv6_option_56_does_not_hold_an_address_list.patch > deleted file mode 100644 > index fdccd0e..0000000 > --- a/src/patches/dnsmasq/008- > DHCPv6_option_56_does_not_hold_an_address_list.patch > +++ /dev/null > @@ -1,25 +0,0 @@ > -From 102208df695e886a3086754d32bf7f8c541fbe46 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Thu, 10 Sep 2015 21:50:00 +0100 > -Subject: [PATCH] DHCPv6 option 56 does not hold an address list. > (RFC 5908). > - > ---- > - src/dhcp-common.c | 2 +- > - 1 file changed, 1 insertion(+), 1 deletion(-) > - > -diff --git a/src/dhcp-common.c b/src/dhcp-common.c > -index bc48f41..8fc171a 100644 > ---- a/src/dhcp-common.c > -+++ b/src/dhcp-common.c > -@@ -599,7 +599,7 @@ static const struct opttab_t opttab6[] = { > - { "sntp-server", 31, OT_ADDR_LIST }, > - { "information-refresh-time", 32, OT_TIME }, > - { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME }, > -- { "ntp-server", 56, OT_ADDR_LIST }, > -+ { "ntp-server", 56, 0 }, > - { "bootfile-url", 59, OT_NAME }, > - { "bootfile-param", 60, OT_CSTRING }, > - { NULL, 0, 0 } > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/009-Respect_the_ > --no_resolv_flag_in_inotify_code.patch b/src/patches/dnsmasq/009- > Respect_the_--no_resolv_flag_in_inotify_code.patch > deleted file mode 100644 > index 2014fdb..0000000 > --- a/src/patches/dnsmasq/009-Respect_the_ > --no_resolv_flag_in_inotify_code.patch > +++ /dev/null > @@ -1,47 +0,0 @@ > -From 77607cbea0ad0f876dfb79c8b2c121ee400d57d0 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Thu, 10 Sep 2015 23:08:43 +0100 > -Subject: [PATCH] Respect the --no-resolv flag in inotify code. > - > ---- > - CHANGELOG | 7 ++++++- > - debian/changelog | 6 ++++++ > - src/inotify.c | 3 +++ > - 3 files changed, 15 insertions(+), 1 deletion(-) > - > -diff --git a/CHANGELOG b/CHANGELOG > -index bbc2834..d6e309f 100644 > ---- a/CHANGELOG > -+++ b/CHANGELOG > -@@ -7,8 +7,13 @@ version 2.76 > - > - Enhance --add-subnet to allow arbitrary subnet > addresses. > - Thanks to Ed Barsley for the patch. > -+ > -+ Respect the --no-resolv flag in inotify code. Fixes bug > -+ which caused dnsmasq to fail to start if a resolv-file > -+ was a dangling symbolic link, even of --no-resolv set. > -+ Thanks to Alexander Kurtz for spotting the problem. > -+ > - > -- > - version 2.75 > - Fix reversion on 2.74 which caused 100% CPU use when a > - dhcp-script is configured. Thanks to Adrian Davey for > -diff --git a/src/inotify.c b/src/inotify.c > -index 52d412f..ef05c58 100644 > ---- a/src/inotify.c > -+++ b/src/inotify.c > -@@ -90,6 +90,9 @@ void inotify_dnsmasq_init() > - > - if (daemon->inotifyfd == -1) > - die(_("failed to create inotify: %s"), NULL, EC_MISC); > -+ > -+ if (option_bool(OPT_NO_RESOLV)) > -+ return; > - > - for (res = daemon->resolv_files; res; res = res->next) > - { > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/010- > Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch > b/src/patches/dnsmasq/010- > Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch > deleted file mode 100644 > index 281697f..0000000 > --- a/src/patches/dnsmasq/010- > Rationalise_5e3e464ac4022ee0b3794513abe510817e2cf3ca.patch > +++ /dev/null > @@ -1,26 +0,0 @@ > -From 27b78d990b7cd901866ad6f1a17b9d633a95fdce Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sat, 26 Sep 2015 21:40:45 +0100 > -Subject: [PATCH] Rationalise > 5e3e464ac4022ee0b3794513abe510817e2cf3ca > - > ---- > - src/rfc3315.c | 3 +-- > - 1 file changed, 1 insertion(+), 2 deletions(-) > - > -diff --git a/src/rfc3315.c b/src/rfc3315.c > -index 3f1f9ee..3ed8623 100644 > ---- a/src/rfc3315.c > -+++ b/src/rfc3315.c > -@@ -1324,8 +1324,7 @@ static struct dhcp_netid *add_options(struct > state *state, int do_refresh) > - if (opt_cfg->opt == OPTION6_DNS_SERVER) > - done_dns = 1; > - > -- /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */ > -- if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == > OPTION6_DNS_SERVER) > -+ if (opt_cfg->flags & DHOPT_ADDR6) > - { > - int len, j; > - struct in6_addr *a; > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/011- > Catch_errors_from_sendmsg_in_DHCP_code.patch > b/src/patches/dnsmasq/011- > Catch_errors_from_sendmsg_in_DHCP_code.patch > deleted file mode 100644 > index 631495f..0000000 > --- a/src/patches/dnsmasq/011- > Catch_errors_from_sendmsg_in_DHCP_code.patch > +++ /dev/null > @@ -1,32 +0,0 @@ > -From 98079ea89851da1df4966dfdfa1852a98da02912 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 13 Oct 2015 20:30:32 +0100 > -Subject: [PATCH] Catch errors from sendmsg in DHCP code. Logs, > eg, iptables > - DROPS of dest 255.255.255.255 > - > ---- > - src/dhcp.c | 7 ++++++- > - 1 file changed, 6 insertions(+), 1 deletion(-) > - > -diff --git a/src/dhcp.c b/src/dhcp.c > -index e6fceb1..1c85e42 100644 > ---- a/src/dhcp.c > -+++ b/src/dhcp.c > -@@ -452,8 +452,13 @@ void dhcp_packet(time_t now, int pxe_fd) > - #endif > - > - while(retry_send(sendmsg(fd, &msg, 0))); > -+ > -+ /* This can fail when, eg, iptables DROPS destination > 255.255.255.255 */ > -+ if (errno != 0) > -+ my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet > to %s: %s"), > -+ inet_ntoa(dest.sin_addr), strerror(errno)); > - } > -- > -+ > - /* check against secondary interface addresses */ > - static int check_listen_addrs(struct in_addr local, int if_index, > char *label, > - struct in_addr netmask, struct > in_addr broadcast, void *vparam) > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/012-Update_list_of_subnet_for_ > --bogus-priv.patch b/src/patches/dnsmasq/012- > Update_list_of_subnet_for_--bogus-priv.patch > deleted file mode 100644 > index 3ba98fc..0000000 > --- a/src/patches/dnsmasq/012-Update_list_of_subnet_for_--bogus- > priv.patch > +++ /dev/null > @@ -1,48 +0,0 @@ > -From 90477fb79420a34124b66ebd808c578817a30e4c Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 20 Oct 2015 21:21:32 +0100 > -Subject: [PATCH] Update list of subnet for --bogus-priv > - > -RFC6303 specifies & recommends following zones not be forwarded > -to globally facing servers. > -+------------------------------+-----------------------+ > -| Zone | Description | > -+------------------------------+-----------------------+ > -| 0.IN-ADDR.ARPA | IPv4 "THIS" NETWORK | > -| 127.IN-ADDR.ARPA | IPv4 Loopback NETWORK | > -| 254.169.IN-ADDR.ARPA | IPv4 LINK LOCAL | > -| 2.0.192.IN-ADDR.ARPA | IPv4 TEST-NET-1 | > -| 100.51.198.IN-ADDR.ARPA | IPv4 TEST-NET-2 | > -| 113.0.203.IN-ADDR.ARPA | IPv4 TEST-NET-3 | > -| 255.255.255.255.IN-ADDR.ARPA | IPv4 BROADCAST | > -+------------------------------+-----------------------+ > - > -Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.u > k> > ---- > - src/rfc1035.c | 8 ++++++-- > - 1 file changed, 6 insertions(+), 2 deletions(-) > - > -diff --git a/src/rfc1035.c b/src/rfc1035.c > -index 6a51b30..4eb1772 100644 > ---- a/src/rfc1035.c > -+++ b/src/rfc1035.c > -@@ -756,10 +756,14 @@ int private_net(struct in_addr addr, int > ban_localhost) > - return > - (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* > 127.0.0.0/8 (loopback) */ || > - ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. > "here" network */ || > -- ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 > (private) */ || > - ((ip_addr & 0xFF000000) == 0x0A000000) /* > 10.0.0.0/8 (private) */ || > - ((ip_addr & 0xFFF00000) == 0xAC100000) /* > 172.16.0.0/12 (private) */ || > -- ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 > (zeroconf) */ ; > -+ ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 > (private) */ || > -+ ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 > (zeroconf) */ || > -+ ((ip_addr & 0xFFFFFF00) == 0xC0000200) /* > 192.0.2.0/24 (test-net) */ || > -+ ((ip_addr & 0xFFFFFF00) == 0xC6336400) /* > 198.51.100.0/24(test-net) */ || > -+ ((ip_addr & 0xFFFFFF00) == 0xCB007100) /* 203.0.113.0/24 > (test-net) */ || > -+ ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 > (broadcast)*/ ; > - } > - > - static unsigned char *do_doctor(unsigned char *p, int count, struct > dns_header *header, size_t qlen, char *name, int *doctored) > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/013- > Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch > b/src/patches/dnsmasq/013- > Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch > deleted file mode 100644 > index 736cf38..0000000 > --- a/src/patches/dnsmasq/013- > Fix_crash_when_empty_address_from_DNS_overlays_A_record_from.patch > +++ /dev/null > @@ -1,43 +0,0 @@ > -From 41a8d9e99be9f2cc8b02051dd322cb45e0faac87 Mon Sep 17 00:00:00 > 2001 > -From: =?utf8?q?Edwin=20T=C3=B6r=C3=B6k?= <edwin+ml-cerowrt@etorok.ne > t> > -Date: Sat, 14 Nov 2015 17:45:48 +0000 > -Subject: [PATCH] Fix crash when empty address from DNS overlays A > record from > - hosts. > - > ---- > - CHANGELOG | 5 +++++ > - src/cache.c | 2 +- > - 2 files changed, 6 insertions(+), 1 deletion(-) > - > -diff --git a/CHANGELOG b/CHANGELOG > -index d6e309f..93c73d0 100644 > ---- a/CHANGELOG > -+++ b/CHANGELOG > -@@ -13,6 +13,11 @@ version 2.76 > - was a dangling symbolic link, even of --no-resolv set. > - Thanks to Alexander Kurtz for spotting the problem. > - > -+ Fix crash when an A or AAAA record is defined locally, > -+ in a hosts file, and an upstream server sends a reply > -+ that the same name is empty. Thanks to Edwin Török > for > -+ the patch. > -+ > - > - version 2.75 > - Fix reversion on 2.74 which caused 100% CPU use when a > -diff --git a/src/cache.c b/src/cache.c > -index 178d654..1b76b67 100644 > ---- a/src/cache.c > -+++ b/src/cache.c > -@@ -481,7 +481,7 @@ struct crec *cache_insert(char *name, struct > all_addr *addr, > - existing record is for an A or AAAA and > - the record we're trying to insert is the same, > - just drop the insert, but don't error the whole process. > */ > -- if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD)) > -+ if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && > addr) > - { > - if ((flags & F_IPV4) && (new->flags & F_IPV4) && > - new->addr.addr.addr.addr4.s_addr == addr- > >addr.addr4.s_addr) > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/014- > Handle_unknown_DS_hash_algos_correctly.patch > b/src/patches/dnsmasq/014- > Handle_unknown_DS_hash_algos_correctly.patch > deleted file mode 100644 > index 8b17431..0000000 > --- a/src/patches/dnsmasq/014- > Handle_unknown_DS_hash_algos_correctly.patch > +++ /dev/null > @@ -1,39 +0,0 @@ > -From 67ab3285b5d9a1b1e20e034cf272867fdab8a0f9 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Fri, 20 Nov 2015 23:20:47 +0000 > -Subject: [PATCH] Handle unknown DS hash algos correctly. > - > -When we can validate a DS RRset, but don't speak the hash algo it > -contains, treat that the same as an NSEC/3 proving that the DS > -doesn't exist. 4025 5.2 > ---- > - src/dnssec.c | 13 +++++++++++++ > - 1 file changed, 13 insertions(+) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 67ce486..b4dc14e 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1005,6 +1005,19 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - if (crecp->flags & F_NEG) > - return STAT_INSECURE_DS; > - > -+ /* 4035 5.2 > -+ If the validator does not support any of the algorithms listed > in an > -+ authenticated DS RRset, then the resolver has no supported > -+ authentication path leading from the parent to the child. The > -+ resolver should treat this case as it would the case of an > -+ authenticated NSEC RRset proving that no DS RRset exists, */ > -+ for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, > name, now, F_DS)) > -+ if (hash_find(ds_digest_name(recp1->addr.ds.digest))) > -+ break; > -+ > -+ if (!recp1) > -+ return STAT_INSECURE_DS; > -+ > - /* NOTE, we need to find ONE DNSKEY which matches the DS */ > - for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j > --) > - { > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf- > dir.patch b/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf- > dir.patch > deleted file mode 100644 > index a9102c1..0000000 > --- a/src/patches/dnsmasq/015-Fix_crash_at_start_up_with_conf- > dir.patch > +++ /dev/null > @@ -1,38 +0,0 @@ > -From 0007ee90646a5a78a96ee729932e89d31c69513a Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sat, 21 Nov 2015 21:47:41 +0000 > -Subject: [PATCH] Fix crash at start up with conf-dir=/path,* > - > -Thanks to Brian Carpenter and American Fuzzy Lop for finding the > bug. > ---- > - src/option.c | 14 ++++++++++---- > - 1 file changed, 10 insertions(+), 4 deletions(-) > - > -diff --git a/src/option.c b/src/option.c > -index 746cd11..71beb98 100644 > ---- a/src/option.c > -+++ b/src/option.c > -@@ -1515,10 +1515,16 @@ static int one_opt(int option, char *arg, > char *errstr, char *gen_err, int comma > - li = opt_malloc(sizeof(struct list)); > - if (*arg == '*') > - { > -- li->next = match_suffix; > -- match_suffix = li; > -- /* Have to copy: buffer is overwritten */ > -- li->suffix = opt_string_alloc(arg+1); > -+ /* "*" with no suffix is a no-op */ > -+ if (arg[1] == 0) > -+ free(li); > -+ else > -+ { > -+ li->next = match_suffix; > -+ match_suffix = li; > -+ /* Have to copy: buffer is overwritten */ > -+ li->suffix = opt_string_alloc(arg+1); > -+ } > - } > - else > - { > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/016- > Major_rationalisation_of_DNSSEC_validation.patch > b/src/patches/dnsmasq/016- > Major_rationalisation_of_DNSSEC_validation.patch > deleted file mode 100644 > index 7f25066..0000000 > --- a/src/patches/dnsmasq/016- > Major_rationalisation_of_DNSSEC_validation.patch > +++ /dev/null > @@ -1,2209 +0,0 @@ > -From 9a31b68b59adcac01016d4026d906b69c4216c01 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 15 Dec 2015 10:20:39 +0000 > -Subject: [PATCH] Major rationalisation of DNSSEC validation. > - > -Much gnarly special-case code removed and replaced with correct > -general implementaion. Checking of zone-status moved to DNSSEC code, > -where it should be, vastly simplifying query-forwarding code. > ---- > - src/dnsmasq.h | 19 +- > - src/dnssec.c | 926 ++++++++++++++++++++++++++++++-------------- > ------------- > - src/forward.c | 741 ++++++++++----------------------------------- > - 3 files changed, 653 insertions(+), 1033 deletions(-) > - > -diff --git a/src/dnsmasq.h b/src/dnsmasq.h > -index f42acdb..023a1cf 100644 > ---- a/src/dnsmasq.h > -+++ b/src/dnsmasq.h > -@@ -586,12 +586,8 @@ struct hostsfile { > - #define STAT_NEED_KEY 5 > - #define STAT_TRUNCATED 6 > - #define STAT_SECURE_WILDCARD 7 > --#define STAT_NO_SIG 8 > --#define STAT_NO_DS 9 > --#define STAT_NO_NS 10 > --#define STAT_NEED_DS_NEG 11 > --#define STAT_CHASE_CNAME 12 > --#define STAT_INSECURE_DS 13 > -+#define STAT_OK 8 > -+#define STAT_ABANDONED 9 > - > - #define FREC_NOREBIND 1 > - #define FREC_CHECKING_DISABLED 2 > -@@ -601,8 +597,7 @@ struct hostsfile { > - #define FREC_AD_QUESTION 32 > - #define FREC_DO_QUESTION 64 > - #define FREC_ADDED_PHEADER 128 > --#define FREC_CHECK_NOSIGN 256 > --#define FREC_TEST_PKTSZ 512 > -+#define FREC_TEST_PKTSZ 256 > - > - #ifdef HAVE_DNSSEC > - #define HASH_SIZE 20 /* SHA-1 digest size */ > -@@ -626,9 +621,7 @@ struct frec { > - #ifdef HAVE_DNSSEC > - int class, work_counter; > - struct blockdata *stash; /* Saved reply, whilst we validate */ > -- struct blockdata *orig_domain; /* domain of original query, > whilst > -- we're seeing is if in unsigned > domain */ > -- size_t stash_len, name_start, name_len; > -+ size_t stash_len; > - struct frec *dependent; /* Query awaiting internally-generated > DNSKEY or DS query */ > - struct frec *blocking_query; /* Query which is blocking us. */ > - #endif > -@@ -1162,8 +1155,8 @@ int in_zone(struct auth_zone *zone, char > *name, char **cut); > - size_t dnssec_generate_query(struct dns_header *header, char *end, > char *name, int class, int type, union mysockaddr *addr, int > edns_pktsz); > - int dnssec_validate_by_ds(time_t now, struct dns_header *header, > size_t n, char *name, char *keyname, int class); > - int dnssec_validate_ds(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int class); > --int dnssec_validate_reply(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int *class, int *neganswer, > int *nons); > --int dnssec_chase_cname(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname); > -+int dnssec_validate_reply(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int *class, > -+ int check_unsigned, int *neganswer, int > *nons); > - int dnskey_keytag(int alg, int flags, unsigned char *rdata, int > rdlen); > - size_t filter_rrsigs(struct dns_header *header, size_t plen); > - unsigned char* hash_questions(struct dns_header *header, size_t > plen, char *name); > -diff --git a/src/dnssec.c b/src/dnssec.c > -index b4dc14e..de7b335 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -65,8 +65,10 @@ static char *algo_digest_name(int algo) > - case 8: return "sha256"; > - case 10: return "sha512"; > - case 12: return "gosthash94"; > -+#ifndef NO_NETTLE_ECC > - case 13: return "sha256"; > - case 14: return "sha384"; > -+#endif > - default: return NULL; > - } > - } > -@@ -592,30 +594,30 @@ static int get_rdata(struct dns_header > *header, size_t plen, unsigned char *end, > - } > - } > - > --static int expand_workspace(unsigned char ***wkspc, int *sz, int > new) > -+static int expand_workspace(unsigned char ***wkspc, int *szp, int > new) > - { > - unsigned char **p; > -- int new_sz = *sz; > -- > -- if (new_sz > new) > -+ int old = *szp; > -+ > -+ if (old >= new+1) > - return 1; > - > - if (new >= 100) > - return 0; > - > -- new_sz += 5; > -+ new += 5; > - > -- if (!(p = whine_malloc((new_sz) * sizeof(unsigned char **)))) > -+ if (!(p = whine_malloc(new * sizeof(unsigned char **)))) > - return 0; > - > -- if (*wkspc) > -+ if (old != 0 && *wkspc) > - { > -- memcpy(p, *wkspc, *sz * sizeof(unsigned char **)); > -+ memcpy(p, *wkspc, old * sizeof(unsigned char **)); > - free(*wkspc); > - } > - > - *wkspc = p; > -- *sz = new_sz; > -+ *szp = new; > - > - return 1; > - } > -@@ -706,47 +708,28 @@ static void sort_rrset(struct dns_header > *header, size_t plen, u16 *rr_desc, int > - } while (swap); > - } > - > --/* Validate a single RRset (class, type, name) in the supplied DNS > reply > -- Return code: > -- STAT_SECURE if it validates. > -- STAT_SECURE_WILDCARD if it validates and is the result of > wildcard expansion. > -- (In this case *wildcard_out points to the "body" of the wildcard > within name.) > -- STAT_NO_SIG no RRsigs found. > -- STAT_INSECURE RRset empty. > -- STAT_BOGUS signature is wrong, bad packet. > -- STAT_NEED_KEY need DNSKEY to complete validation (name is > returned in keyname) > -- > -- if key is non-NULL, use that key, which has the algo and tag > given in the params of those names, > -- otherwise find the key in the cache. > -+static unsigned char **rrset = NULL, **sigs = NULL; > - > -- name is unchanged on exit. keyname is used as workspace and > trashed. > --*/ > --static int validate_rrset(time_t now, struct dns_header *header, > size_t plen, int class, int type, > -- char *name, char *keyname, char > **wildcard_out, struct blockdata *key, int keylen, int algo_in, int > keytag_in) > -+/* Get pointers to RRset menbers and signature(s) for same. > -+ Check signatures, and return keyname associated in keyname. */ > -+static int explore_rrset(struct dns_header *header, size_t plen, > int class, int type, > -+ char *name, char *keyname, int *sigcnt, > int *rrcnt) > - { > -- static unsigned char **rrset = NULL, **sigs = NULL; > -- static int rrset_sz = 0, sig_sz = 0; > -- > -+ static int rrset_sz = 0, sig_sz = 0; > - unsigned char *p; > -- int rrsetidx, sigidx, res, rdlen, j, name_labels; > -- struct crec *crecp = NULL; > -- int type_covered, algo, labels, orig_ttl, sig_expiration, > sig_inception, key_tag; > -- u16 *rr_desc = get_desc(type); > -- > -- if (wildcard_out) > -- *wildcard_out = NULL; > -- > -+ int rrsetidx, sigidx, j, rdlen, res; > -+ int name_labels = count_labels(name); /* For 4035 5.3.2 check */ > -+ int gotkey = 0; > -+ > - if (!(p = skip_questions(header, plen))) > - return STAT_BOGUS; > -- > -- name_labels = count_labels(name); /* For 4035 5.3.2 check */ > - > -- /* look for RRSIGs for this RRset and get pointers to each RR in > the set. */ > -+ /* look for RRSIGs for this RRset and get pointers to each RR in > the set. */ > - for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + > ntohs(header->nscount); > - j != 0; j--) > - { > - unsigned char *pstart, *pdata; > -- int stype, sclass; > -+ int stype, sclass, algo, type_covered, labels, > sig_expiration, sig_inception; > - > - pstart = p; > - > -@@ -762,14 +745,14 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - GETSHORT(rdlen, p); > - > - if (!CHECK_LEN(header, p, plen, rdlen)) > -- return STAT_BOGUS; > -+ return 0; > - > - if (res == 1 && sclass == class) > - { > - if (stype == type) > - { > - if (!expand_workspace(&rrset, &rrset_sz, rrsetidx)) > -- return STAT_BOGUS; > -+ return 0; > - > - rrset[rrsetidx++] = pstart; > - } > -@@ -777,14 +760,54 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - if (stype == T_RRSIG) > - { > - if (rdlen < 18) > -- return STAT_BOGUS; /* bad packet */ > -+ return 0; /* bad packet */ > - > - GETSHORT(type_covered, p); > -+ algo = *p++; > -+ labels = *p++; > -+ p += 4; /* orig_ttl */ > -+ GETLONG(sig_expiration, p); > -+ GETLONG(sig_inception, p); > -+ p += 2; /* key_tag */ > - > -- if (type_covered == type) > -+ if (gotkey) > -+ { > -+ /* If there's more than one SIG, ensure they all > have same keyname */ > -+ if (extract_name(header, plen, &p, keyname, 0, 0) > != 1) > -+ return 0; > -+ } > -+ else > -+ { > -+ gotkey = 1; > -+ > -+ if (!extract_name(header, plen, &p, keyname, 1, > 0)) > -+ return 0; > -+ > -+ /* RFC 4035 5.3.1 says that the Signer's Name > field MUST equal > -+ the name of the zone containing the RRset. We > can't tell that > -+ for certain, but we can check that the RRset > name is equal to > -+ or encloses the signers name, which should be > enough to stop > -+ an attacker using signatures made with the key > of an unrelated > -+ zone he controls. Note that the root key is > always allowed. */ > -+ if (*keyname != 0) > -+ { > -+ char *name_start; > -+ for (name_start = name; > !hostname_isequal(name_start, keyname); ) > -+ if ((name_start = strchr(name_start, '.'))) > -+ name_start++; /* chop a label off and try > again */ > -+ else > -+ return 0; > -+ } > -+ } > -+ > -+ /* Don't count signatures for algos we don't support > */ > -+ if (check_date_range(sig_inception, sig_expiration) > && > -+ labels <= name_labels && > -+ type_covered == type && > -+ algo_digest_name(algo)) > - { > - if (!expand_workspace(&sigs, &sig_sz, sigidx)) > -- return STAT_BOGUS; > -+ return 0; > - > - sigs[sigidx++] = pdata; > - } > -@@ -794,17 +817,45 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - } > - > - if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return STAT_BOGUS; > -+ return 0; > - } > - > -- /* RRset empty */ > -- if (rrsetidx == 0) > -- return STAT_INSECURE; > -+ *sigcnt = sigidx; > -+ *rrcnt = rrsetidx; > -+ > -+ return 1; > -+} > -+ > -+/* Validate a single RRset (class, type, name) in the supplied DNS > reply > -+ Return code: > -+ STAT_SECURE if it validates. > -+ STAT_SECURE_WILDCARD if it validates and is the result of > wildcard expansion. > -+ (In this case *wildcard_out points to the "body" of the wildcard > within name.) > -+ STAT_BOGUS signature is wrong, bad packet. > -+ STAT_NEED_KEY need DNSKEY to complete validation (name is > returned in keyname) > -+ STAT_NEED_DS need DS to complete validation (name is returned > in keyname) > -+ > -+ if key is non-NULL, use that key, which has the algo and tag > given in the params of those names, > -+ otherwise find the key in the cache. > - > -- /* no RRSIGs */ > -- if (sigidx == 0) > -- return STAT_NO_SIG; > -+ name is unchanged on exit. keyname is used as workspace and > trashed. > -+ > -+ Call explore_rrset first to find and count RRs and sigs. > -+*/ > -+static int validate_rrset(time_t now, struct dns_header *header, > size_t plen, int class, int type, int sigidx, int rrsetidx, > -+ char *name, char *keyname, char > **wildcard_out, struct blockdata *key, int keylen, int algo_in, int > keytag_in) > -+{ > -+ unsigned char *p; > -+ int rdlen, j, name_labels; > -+ struct crec *crecp = NULL; > -+ int algo, labels, orig_ttl, key_tag; > -+ u16 *rr_desc = get_desc(type); > -+ > -+ if (wildcard_out) > -+ *wildcard_out = NULL; > - > -+ name_labels = count_labels(name); /* For 4035 5.3.2 check */ > -+ > - /* Sort RRset records into canonical order. > - Note that at this point keyname and daemon->workspacename > buffs are > - unused, and used as workspace by the sort. */ > -@@ -828,44 +879,16 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - algo = *p++; > - labels = *p++; > - GETLONG(orig_ttl, p); > -- GETLONG(sig_expiration, p); > -- GETLONG(sig_inception, p); > -+ p += 8; /* sig_expiration, sig_inception already checked */ > - GETSHORT(key_tag, p); > - > - if (!extract_name(header, plen, &p, keyname, 1, 0)) > - return STAT_BOGUS; > - > -- /* RFC 4035 5.3.1 says that the Signer's Name field MUST > equal > -- the name of the zone containing the RRset. We can't tell > that > -- for certain, but we can check that the RRset name is > equal to > -- or encloses the signers name, which should be enough to > stop > -- an attacker using signatures made with the key of an > unrelated > -- zone he controls. Note that the root key is always > allowed. */ > -- if (*keyname != 0) > -- { > -- int failed = 0; > -- > -- for (name_start = name; !hostname_isequal(name_start, > keyname); ) > -- if ((name_start = strchr(name_start, '.'))) > -- name_start++; /* chop a label off and try again */ > -- else > -- { > -- failed = 1; > -- break; > -- } > -- > -- /* Bad sig, try another */ > -- if (failed) > -- continue; > -- } > -- > -- /* Other 5.3.1 checks */ > -- if (!check_date_range(sig_inception, sig_expiration) || > -- labels > name_labels || > -- !(hash = hash_find(algo_digest_name(algo))) || > -+ if (!(hash = hash_find(algo_digest_name(algo))) || > - !hash_init(hash, &ctx, &digest)) > - continue; > -- > -+ > - /* OK, we have the signature record, see if the relevant > DNSKEY is in the cache. */ > - if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, > F_DNSKEY))) > - return STAT_NEED_KEY; > -@@ -971,10 +994,11 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - /* The DNS packet is expected to contain the answer to a DNSKEY > query. > - Put all DNSKEYs in the answer which are valid into the cache. > - return codes: > -- STAT_SECURE At least one valid DNSKEY found and in > cache. > -- STAT_BOGUS No DNSKEYs found, which can be validated > with DS, > -- or self-sign for DNSKEY RRset is not valid, > bad packet. > -- STAT_NEED_DS DS records to validate a key not found, name > in keyname > -+ STAT_OK Done, key(s) in cache. > -+ STAT_BOGUS No DNSKEYs found, which can be > validated with DS, > -+ or self-sign for DNSKEY RRset is not > valid, bad packet. > -+ STAT_NEED_DS DS records to validate a key not found, > name in keyname > -+ STAT_NEED_DNSKEY DNSKEY records to validate a key not > found, name in keyname > - */ > - int dnssec_validate_by_ds(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int class) > - { > -@@ -1001,23 +1025,6 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - return STAT_NEED_DS; > - } > - > -- /* If we've cached that DS provably doesn't exist, result must be > INSECURE */ > -- if (crecp->flags & F_NEG) > -- return STAT_INSECURE_DS; > -- > -- /* 4035 5.2 > -- If the validator does not support any of the algorithms listed > in an > -- authenticated DS RRset, then the resolver has no supported > -- authentication path leading from the parent to the child. The > -- resolver should treat this case as it would the case of an > -- authenticated NSEC RRset proving that no DS RRset exists, */ > -- for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, > name, now, F_DS)) > -- if (hash_find(ds_digest_name(recp1->addr.ds.digest))) > -- break; > -- > -- if (!recp1) > -- return STAT_INSECURE_DS; > -- > - /* NOTE, we need to find ONE DNSKEY which matches the DS */ > - for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j > --) > - { > -@@ -1070,7 +1077,8 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - void *ctx; > - unsigned char *digest, *ds_digest; > - const struct nettle_hash *hash; > -- > -+ int sigcnt, rrcnt; > -+ > - if (recp1->addr.ds.algo == algo && > - recp1->addr.ds.keytag == keytag && > - recp1->uid == (unsigned int)class && > -@@ -1088,10 +1096,14 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - > - from_wire(name); > - > -- if (recp1->addr.ds.keylen == (int)hash->digest_size > && > -+ if (!(recp1->flags & F_NEG) && > -+ recp1->addr.ds.keylen == (int)hash->digest_size > && > - (ds_digest = blockdata_retrieve(recp1- > >addr.key.keydata, recp1->addr.ds.keylen, NULL)) && > - memcmp(ds_digest, digest, recp1->addr.ds.keylen) > == 0 && > -- validate_rrset(now, header, plen, class, > T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == > STAT_SECURE) > -+ explore_rrset(header, plen, class, T_DNSKEY, > name, keyname, &sigcnt, &rrcnt) && > -+ sigcnt != 0 && rrcnt != 0 && > -+ validate_rrset(now, header, plen, class, > T_DNSKEY, sigcnt, rrcnt, name, keyname, > -+ NULL, key, rdlen - 4, algo, > keytag) == STAT_SECURE) > - { > - valid = 1; > - break; > -@@ -1112,7 +1124,7 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - { > - /* Ensure we have type, class TTL and length */ > - if (!(rc = extract_name(header, plen, &p, name, 0, 10))) > -- return STAT_INSECURE; /* bad packet */ > -+ return STAT_BOGUS; /* bad packet */ > - > - GETSHORT(qtype, p); > - GETSHORT(qclass, p); > -@@ -1198,7 +1210,7 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - > - /* commit cache insert. */ > - cache_end_insert(); > -- return STAT_SECURE; > -+ return STAT_OK; > - } > - > - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY"); > -@@ -1207,12 +1219,14 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - > - /* The DNS packet is expected to contain the answer to a DS query > - Put all DSs in the answer which are valid into the cache. > -+ Also handles replies which prove that there's no DS at this > location, > -+ either because the zone is unsigned or this isn't a zone cut. > These are > -+ cached too. > - return codes: > -- STAT_SECURE At least one valid DS found and in cache. > -- STAT_NO_DS It's proved there's no DS here. > -- STAT_NO_NS It's proved there's no DS _or_ NS here. > -+ STAT_OK At least one valid DS found and in cache. > - STAT_BOGUS no DS in reply or not signed, fails validation, > bad packet. > - STAT_NEED_KEY DNSKEY records to validate a DS not found, name > in keyname > -+ STAT_NEED_DS DS record needed. > - */ > - > - int dnssec_validate_ds(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int class) > -@@ -1230,7 +1244,7 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - if (qtype != T_DS || qclass != class) > - val = STAT_BOGUS; > - else > -- val = dnssec_validate_reply(now, header, plen, name, keyname, > NULL, &neganswer, &nons); > -+ val = dnssec_validate_reply(now, header, plen, name, keyname, > NULL, 0, &neganswer, &nons); > - /* Note dnssec_validate_reply() will have cached positive answers > */ > - > - if (val == STAT_INSECURE) > -@@ -1242,22 +1256,21 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - > - if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) > - val = STAT_BOGUS; > -- > -- /* If we return STAT_NO_SIG, name contains the name of the DS > query */ > -- if (val == STAT_NO_SIG) > -- return val; > - > - /* If the key needed to validate the DS is on the same domain as > the DS, we'll > - loop getting nowhere. Stop that now. This can happen of the DS > answer comes > - from the DS's zone, and not the parent zone. */ > -- if (val == STAT_BOGUS || (val == STAT_NEED_KEY && > hostname_isequal(name, keyname))) > -+ if (val == STAT_BOGUS || (val == STAT_NEED_KEY && > hostname_isequal(name, keyname))) > - { > - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS"); > - return STAT_BOGUS; > - } > -+ > -+ if (val != STAT_SECURE) > -+ return val; > - > - /* By here, the answer is proved secure, and a positive answer > has been cached. */ > -- if (val == STAT_SECURE && neganswer) > -+ if (neganswer) > - { > - int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK; > - unsigned long ttl, minttl = ULONG_MAX; > -@@ -1317,15 +1330,14 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - > - cache_end_insert(); > - > -- log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no > delegation" : "no DS"); > -+ log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS"); > - } > -- > -- return nons ? STAT_NO_NS : STAT_NO_DS; > - } > - > -- return val; > -+ return STAT_OK; > - } > - > -+ > - /* 4034 6.1 */ > - static int hostname_cmp(const char *a, const char *b) > - { > -@@ -1452,7 +1464,7 @@ static int prove_non_existence_nsec(struct > dns_header *header, size_t plen, unsi > - int mask = 0x80 >> (type & 0x07); > - > - if (nons) > -- *nons = 0; > -+ *nons = 1; > - > - /* Find NSEC record that proves name doesn't exist */ > - for (i = 0; i < nsec_count; i++) > -@@ -1480,9 +1492,22 @@ static int prove_non_existence_nsec(struct > dns_header *header, size_t plen, unsi > - /* rdlen is now length of type map, and p points to it */ > - > - /* If we can prove that there's no NS record, return that > information. */ > -- if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> > T_NS)) == 0) > -- *nons = 1; > -+ if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> > T_NS)) != 0) > -+ *nons = 0; > - > -+ if (rdlen >= 2 && p[0] == 0) > -+ { > -+ /* A CNAME answer would also be valid, so if there's > a CNAME is should > -+ have been returned. */ > -+ if ((p[2] & (0x80 >> T_CNAME)) != 0) > -+ return STAT_BOGUS; > -+ > -+ /* If the SOA bit is set for a DS record, then we > have the > -+ DS from the wrong side of the delegation. */ > -+ if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0) > -+ return STAT_BOGUS; > -+ } > -+ > - while (rdlen >= 2) > - { > - if (!CHECK_LEN(header, p, plen, rdlen)) > -@@ -1586,7 +1611,7 @@ static int base32_decode(char *in, unsigned > char *out) > - static int check_nsec3_coverage(struct dns_header *header, size_t > plen, int digest_len, unsigned char *digest, int type, > - char *workspace1, char *workspace2, > unsigned char **nsecs, int nsec_count, int *nons) > - { > -- int i, hash_len, salt_len, base32_len, rdlen; > -+ int i, hash_len, salt_len, base32_len, rdlen, flags; > - unsigned char *p, *psave; > - > - for (i = 0; i < nsec_count; i++) > -@@ -1599,7 +1624,9 @@ static int check_nsec3_coverage(struct > dns_header *header, size_t plen, int dige > - p += 8; /* class, type, TTL */ > - GETSHORT(rdlen, p); > - psave = p; > -- p += 4; /* algo, flags, iterations */ > -+ p++; /* algo */ > -+ flags = *p++; /* flags */ > -+ p += 2; /* iterations */ > - salt_len = *p++; /* salt_len */ > - p += salt_len; /* salt */ > - hash_len = *p++; /* p now points to next hashed name */ > -@@ -1626,16 +1653,29 @@ static int check_nsec3_coverage(struct > dns_header *header, size_t plen, int dige > - return 0; > - > - /* If we can prove that there's no NS record, > return that information. */ > -- if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & > (0x80 >> T_NS)) == 0) > -- *nons = 1; > -+ if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & > (0x80 >> T_NS)) != 0) > -+ *nons = 0; > - > -+ if (rdlen >= 2 && p[0] == 0) > -+ { > -+ /* A CNAME answer would also be valid, so if > there's a CNAME is should > -+ have been returned. */ > -+ if ((p[2] & (0x80 >> T_CNAME)) != 0) > -+ return 0; > -+ > -+ /* If the SOA bit is set for a DS record, then > we have the > -+ DS from the wrong side of the delegation. */ > -+ if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != > 0) > -+ return 0; > -+ } > -+ > - while (rdlen >= 2) > - { > - if (p[0] == type >> 8) > - { > - /* Does the NSEC3 say our type exists? */ > - if (offset < p[1] && (p[offset+2] & mask) > != 0) > -- return STAT_BOGUS; > -+ return 0; > - > - break; /* finshed checking */ > - } > -@@ -1643,7 +1683,7 @@ static int check_nsec3_coverage(struct > dns_header *header, size_t plen, int dige > - rdlen -= p[1]; > - p += p[1]; > - } > -- > -+ > - return 1; > - } > - else if (rc < 0) > -@@ -1651,16 +1691,27 @@ static int check_nsec3_coverage(struct > dns_header *header, size_t plen, int dige > - /* Normal case, hash falls between NSEC3 name-hash > and next domain name-hash, > - wrap around case, name-hash falls between NSEC3 > name-hash and end */ > - if (memcmp(p, digest, digest_len) >= 0 || > memcmp(workspace2, p, digest_len) >= 0) > -- return 1; > -+ { > -+ if ((flags & 0x01) && nons) /* opt out */ > -+ *nons = 0; > -+ > -+ return 1; > -+ } > - } > - else > - { > - /* wrap around case, name falls between start and > next domain name */ > - if (memcmp(workspace2, p, digest_len) >= 0 && > memcmp(p, digest, digest_len) >= 0) > -- return 1; > -+ { > -+ if ((flags & 0x01) && nons) /* opt out */ > -+ *nons = 0; > -+ > -+ return 1; > -+ } > - } > - } > - } > -+ > - return 0; > - } > - > -@@ -1673,7 +1724,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - char *closest_encloser, *next_closest, *wildcard; > - > - if (nons) > -- *nons = 0; > -+ *nons = 1; > - > - /* Look though the NSEC3 records to find the first one with > - an algorithm we support (currently only algo == 1). > -@@ -1813,16 +1864,81 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - > - return STAT_SECURE; > - } > -- > --/* Validate all the RRsets in the answer and authority sections of > the reply (4035:3.2.3) */ > --/* Returns are the same as validate_rrset, plus the class if the > missing key is in *class */ > -+ > -+/* Check signing status of name. > -+ returns: > -+ STAT_SECURE zone is signed. > -+ STAT_INSECURE zone proved unsigned. > -+ STAT_NEED_DS require DS record of name returned in keyname. > -+ > -+ name returned unaltered. > -+*/ > -+static int zone_status(char *name, int class, char *keyname, time_t > now) > -+{ > -+ int name_start = strlen(name); > -+ struct crec *crecp; > -+ char *p; > -+ > -+ while (1) > -+ { > -+ strcpy(keyname, &name[name_start]); > -+ > -+ if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS))) > -+ return STAT_NEED_DS; > -+ else > -+ do > -+ { > -+ if (crecp->uid == (unsigned int)class) > -+ { > -+ /* F_DNSSECOK misused in DS cache records to non- > existance of NS record. > -+ F_NEG && !F_DNSSECOK implies that we've proved > there's no DS record here, > -+ but that's because there's no NS record either, > ie this isn't the start > -+ of a zone. We only prove that the DNS tree below > a node is unsigned when > -+ we prove that we're at a zone cut AND there's no > DS record. > -+ */ > -+ if (crecp->flags & F_NEG) > -+ { > -+ if (crecp->flags & F_DNSSECOK) > -+ return STAT_INSECURE; /* proved no DS here */ > -+ } > -+ else if (!ds_digest_name(crecp->addr.ds.digest) || > !algo_digest_name(crecp->addr.ds.algo)) > -+ return STAT_INSECURE; /* algo we can't use - > insecure */ > -+ } > -+ } > -+ while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DS))); > -+ > -+ if (name_start == 0) > -+ break; > -+ > -+ for (p = &name[name_start-2]; (*p != '.') && (p != name); p > --); > -+ > -+ if (p != name) > -+ p++; > -+ > -+ name_start = p - name; > -+ } > -+ > -+ return STAT_SECURE; > -+} > -+ > -+/* Validate all the RRsets in the answer and authority sections of > the reply (4035:3.2.3) > -+ Return code: > -+ STAT_SECURE if it validates. > -+ STAT_INSECURE at least one RRset not validated, because in > unsigned zone. > -+ STAT_BOGUS signature is wrong, bad packet, no validation > where there should be. > -+ STAT_NEED_KEY need DNSKEY to complete validation (name is > returned in keyname, class in *class) > -+ STAT_NEED_DS need DS to complete validation (name is returned > in keyname) > -+*/ > - int dnssec_validate_reply(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, > -- int *class, int *neganswer, int *nons) > -+ int *class, int check_unsigned, int > *neganswer, int *nons) > - { > -- unsigned char *ans_start, *qname, *p1, *p2, **nsecs; > -- int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype; > -- int i, j, rc, nsec_count, cname_count = CNAME_CHAIN; > -- int nsec_type = 0, have_answer = 0; > -+ static unsigned char **targets = NULL; > -+ static int target_sz = 0; > -+ > -+ unsigned char *ans_start, *p1, *p2, **nsecs; > -+ int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, > targetidx; > -+ int i, j, rc, nsec_count; > -+ int nsec_type; > - > - if (neganswer) > - *neganswer = 0; > -@@ -1833,70 +1949,51 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR) > - return STAT_INSECURE; > - > -- qname = p1 = (unsigned char *)(header+1); > -+ p1 = (unsigned char *)(header+1); > - > -+ /* Find all the targets we're looking for answers to. > -+ The zeroth array element is for the query, subsequent ones > -+ for CNAME targets, unless the query is for a CNAME. */ > -+ > -+ if (!expand_workspace(&targets, &target_sz, 0)) > -+ return STAT_BOGUS; > -+ > -+ targets[0] = p1; > -+ targetidx = 1; > -+ > - if (!extract_name(header, plen, &p1, name, 1, 4)) > - return STAT_BOGUS; > -- > -+ > - GETSHORT(qtype, p1); > - GETSHORT(qclass, p1); > - ans_start = p1; > -- > -- if (qtype == T_ANY) > -- have_answer = 1; > - > -- /* Can't validate an RRISG query */ > -+ /* Can't validate an RRSIG query */ > - if (qtype == T_RRSIG) > - return STAT_INSECURE; > -- > -- cname_loop: > -- for (j = ntohs(header->ancount); j != 0; j--) > -- { > -- /* leave pointer to missing name in qname */ > -- > -- if (!(rc = extract_name(header, plen, &p1, name, 0, 10))) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(type2, p1); > -- GETSHORT(class2, p1); > -- p1 += 4; /* TTL */ > -- GETSHORT(rdlen2, p1); > -- > -- if (rc == 1 && qclass == class2) > -- { > -- /* Do we have an answer for the question? */ > -- if (type2 == qtype) > -- { > -- have_answer = 1; > -- break; > -- } > -- else if (type2 == T_CNAME) > -- { > -- qname = p1; > -- > -- /* looped CNAMES */ > -- if (!cname_count-- || !extract_name(header, plen, > &p1, name, 1, 0)) > -- return STAT_BOGUS; > -- > -- p1 = ans_start; > -- goto cname_loop; > -- } > -- } > -- > -- if (!ADD_RDLEN(header, p1, plen, rdlen2)) > -- return STAT_BOGUS; > -- } > -- > -- if (neganswer && !have_answer) > -- *neganswer = 1; > - > -- /* No data, therefore no sigs */ > -- if (ntohs(header->ancount) + ntohs(header->nscount) == 0) > -- { > -- *keyname = 0; > -- return STAT_NO_SIG; > -- } > -- > -+ if (qtype != T_CNAME) > -+ for (j = ntohs(header->ancount); j != 0; j--) > -+ { > -+ if (!(p1 = skip_name(p1, header, plen, 10))) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ GETSHORT(type2, p1); > -+ p1 += 6; /* class, TTL */ > -+ GETSHORT(rdlen2, p1); > -+ > -+ if (type2 == T_CNAME) > -+ { > -+ if (!expand_workspace(&targets, &target_sz, targetidx)) > -+ return STAT_BOGUS; > -+ > -+ targets[targetidx++] = p1; /* pointer to target name */ > -+ } > -+ > -+ if (!ADD_RDLEN(header, p1, plen, rdlen2)) > -+ return STAT_BOGUS; > -+ } > -+ > - for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + > ntohs(header->nscount); i++) > - { > - if (!extract_name(header, plen, &p1, name, 1, 10)) > -@@ -1931,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - /* Not done, validate now */ > - if (j == i) > - { > -- int ttl, keytag, algo, digest, type_covered; > -+ int ttl, keytag, algo, digest, type_covered, sigcnt, > rrcnt; > - unsigned char *psave; > - struct all_addr a; > - struct blockdata *key; > -@@ -1939,143 +2036,186 @@ int dnssec_validate_reply(time_t now, > struct dns_header *header, size_t plen, ch > - char *wildname; > - int have_wildcard = 0; > - > -- rc = validate_rrset(now, header, plen, class1, type1, > name, keyname, &wildname, NULL, 0, 0, 0); > -- > -- if (rc == STAT_SECURE_WILDCARD) > -- { > -- have_wildcard = 1; > -- > -- /* An attacker replay a wildcard answer with a > different > -- answer and overlay a genuine RR. To prove this > -- hasn't happened, the answer must prove that > -- the gennuine record doesn't exist. Check that > here. */ > -- if (!nsec_type && !(nsec_type = > find_nsec_records(header, plen, &nsecs, &nsec_count, class1))) > -- return STAT_BOGUS; /* No NSECs or bad packet */ > -- > -- if (nsec_type == T_NSEC) > -- rc = prove_non_existence_nsec(header, plen, > nsecs, nsec_count, daemon->workspacename, keyname, name, type1, > NULL); > -- else > -- rc = prove_non_existence_nsec3(header, plen, > nsecs, nsec_count, daemon->workspacename, > -- keyname, name, > type1, wildname, NULL); > -- > -- if (rc != STAT_SECURE) > -- return rc; > -- } > -- else if (rc != STAT_SECURE) > -- { > -- if (class) > -- *class = class1; /* Class for DS or DNSKEY */ > -+ if (!explore_rrset(header, plen, class1, type1, name, > keyname, &sigcnt, &rrcnt)) > -+ return STAT_BOGUS; > - > -- if (rc == STAT_NO_SIG) > -+ /* No signatures for RRset. We can be configured to > assume this is OK and return a INSECURE result. */ > -+ if (sigcnt == 0) > -+ { > -+ if (check_unsigned) > - { > -- /* If we dropped off the end of a CNAME > chain, return > -- STAT_NO_SIG and the last name is keyname. > This is used for proving non-existence > -- if DS records in CNAME chains. */ > -- if (cname_count == CNAME_CHAIN || i < > ntohs(header->ancount)) > -- /* No CNAME chain, or no sig in answer > section, return empty name. */ > -- *keyname = 0; > -- else if (!extract_name(header, plen, &qname, > keyname, 1, 0)) > -- return STAT_BOGUS; > -+ rc = zone_status(name, class1, keyname, now); > -+ if (rc == STAT_SECURE) > -+ rc = STAT_BOGUS; > -+ if (class) > -+ *class = class1; /* Class for NEED_DS or > NEED_DNSKEY */ > - } > -- > -+ else > -+ rc = STAT_INSECURE; > -+ > - return rc; > - } > - > -- /* Cache RRsigs in answer section, and if we just > validated a DS RRset, cache it */ > -- cache_start_insert(); > -+ /* explore_rrset() gives us key name from sigs in > keyname. > -+ Can't overwrite name here. */ > -+ strcpy(daemon->workspacename, keyname); > -+ rc = zone_status(daemon->workspacename, class1, > keyname, now); > -+ if (rc != STAT_SECURE) > -+ { > -+ /* Zone is insecure, don't need to validate RRset > */ > -+ if (class) > -+ *class = class1; /* Class for NEED_DS or > NEED_DNSKEY */ > -+ return rc; > -+ } > -+ > -+ rc = validate_rrset(now, header, plen, class1, type1, > sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0); > - > -- for (p2 = ans_start, j = 0; j < ntohs(header- > >ancount); j++) > -+ if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == > STAT_NEED_DS) > - { > -- if (!(rc = extract_name(header, plen, &p2, name, > 0, 10))) > -- return STAT_BOGUS; /* bad packet */ > -+ if (class) > -+ *class = class1; /* Class for DS or DNSKEY */ > -+ return rc; > -+ } > -+ else > -+ { > -+ /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD > */ > -+ > -+ /* Note if we've validated either the answer to > the question > -+ or the target of a CNAME. Any not noted will > need NSEC or > -+ to be in unsigned space. */ > -+ > -+ for (j = 0; j <targetidx; j++) > -+ if ((p2 = targets[j])) > -+ { > -+ if (!(rc = extract_name(header, plen, &p2, > name, 0, 10))) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ if (class1 == qclass && rc == 1 && (type1 > == T_CNAME || type1 == qtype || qtype == T_ANY )) > -+ targets[j] = NULL; > -+ } > -+ > -+ if (rc == STAT_SECURE_WILDCARD) > -+ { > -+ have_wildcard = 1; > - > -- GETSHORT(type2, p2); > -- GETSHORT(class2, p2); > -- GETLONG(ttl, p2); > -- GETSHORT(rdlen2, p2); > -- > -- if (!CHECK_LEN(header, p2, plen, rdlen2)) > -- return STAT_BOGUS; /* bad packet */ > -- > -- if (class2 == class1 && rc == 1) > -- { > -- psave = p2; > -+ /* An attacker replay a wildcard answer with > a different > -+ answer and overlay a genuine RR. To prove > this > -+ hasn't happened, the answer must prove > that > -+ the gennuine record doesn't exist. Check > that here. */ > -+ if (!(nsec_type = find_nsec_records(header, > plen, &nsecs, &nsec_count, class1))) > -+ return STAT_BOGUS; /* No NSECs or bad > packet */ > -+ > -+ /* Note that we may not yet have validated > the NSEC/NSEC3 RRsets. Since the check > -+ below returns either SECURE or BOGUS, > that's not a problem. If the RRsets later fail > -+ we'll return BOGUS then. */ > - > -- if (type1 == T_DS && type2 == T_DS) > -- { > -- if (rdlen2 < 4) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(keytag, p2); > -- algo = *p2++; > -- digest = *p2++; > -- > -- /* Cache needs to known class for DNSSEC > stuff */ > -- a.addr.dnssec.class = class2; > -- > -- if ((key = blockdata_alloc((char*)p2, > rdlen2 - 4))) > -- { > -- if (!(crecp = cache_insert(name, &a, > now, ttl, F_FORWARD | F_DS | F_DNSSECOK))) > -- blockdata_free(key); > -- else > -- { > -- a.addr.keytag = keytag; > -- log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u"); > -- crecp->addr.ds.digest = digest; > -- crecp->addr.ds.keydata = key; > -- crecp->addr.ds.algo = algo; > -- crecp->addr.ds.keytag = keytag; > -- crecp->addr.ds.keylen = rdlen2 - > 4; > -- } > -- } > -- } > -- else if (type2 == T_RRSIG) > -- { > -- if (rdlen2 < 18) > -- return STAT_BOGUS; /* bad packet */ > -+ if (nsec_type == T_NSEC) > -+ rc = prove_non_existence_nsec(header, plen, > nsecs, nsec_count, daemon->workspacename, keyname, name, type1, > NULL); > -+ else > -+ rc = prove_non_existence_nsec3(header, > plen, nsecs, nsec_count, daemon->workspacename, > -+ keyname, > name, type1, wildname, NULL); > -+ > -+ if (rc == STAT_BOGUS) > -+ return rc; > -+ } > -+ > -+ /* Cache RRsigs in answer section, and if we just > validated a DS RRset, cache it */ > -+ /* Also note if the RRset is the answer to the > question, or the target of a CNAME */ > -+ cache_start_insert(); > -+ > -+ for (p2 = ans_start, j = 0; j < ntohs(header- > >ancount); j++) > -+ { > -+ if (!(rc = extract_name(header, plen, &p2, > name, 0, 10))) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ GETSHORT(type2, p2); > -+ GETSHORT(class2, p2); > -+ GETLONG(ttl, p2); > -+ GETSHORT(rdlen2, p2); > -+ > -+ if (!CHECK_LEN(header, p2, plen, rdlen2)) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ if (class2 == class1 && rc == 1) > -+ { > -+ psave = p2; > - > -- GETSHORT(type_covered, p2); > -- > -- if (type_covered == type1 && > -- (type_covered == T_A || type_covered > == T_AAAA || > -- type_covered == T_CNAME || > type_covered == T_DS || > -- type_covered == T_DNSKEY || > type_covered == T_PTR)) > -+ if (type1 == T_DS && type2 == T_DS) > - { > -- a.addr.dnssec.type = type_covered; > -- a.addr.dnssec.class = class1; > -+ if (rdlen2 < 4) > -+ return STAT_BOGUS; /* bad packet */ > - > -- algo = *p2++; > -- p2 += 13; /* labels, orig_ttl, > expiration, inception */ > - GETSHORT(keytag, p2); > -+ algo = *p2++; > -+ digest = *p2++; > -+ > -+ /* Cache needs to known class for > DNSSEC stuff */ > -+ a.addr.dnssec.class = class2; > - > -- /* We don't cache sigs for wildcard > answers, because to reproduce the > -- answer from the cache will require > one or more NSEC/NSEC3 records > -- which we don't cache. The lack of > the RRSIG ensures that a query for > -- this RRset asking for a secure > answer will always be forwarded. */ > -- if (!have_wildcard && (key = > blockdata_alloc((char*)psave, rdlen2))) > -+ if ((key = blockdata_alloc((char*)p2, > rdlen2 - 4))) > - { > -- if (!(crecp = cache_insert(name, > &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS))) > -+ if (!(crecp = cache_insert(name, > &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))) > - blockdata_free(key); > - else > - { > -- crecp->addr.sig.keydata = > key; > -- crecp->addr.sig.keylen = > rdlen2; > -- crecp->addr.sig.keytag = > keytag; > -- crecp->addr.sig.type_covered > = type_covered; > -- crecp->addr.sig.algo = algo; > -+ a.addr.keytag = keytag; > -+ log_query(F_NOEXTRA | > F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u"); > -+ crecp->addr.ds.digest = > digest; > -+ crecp->addr.ds.keydata = key; > -+ crecp->addr.ds.algo = algo; > -+ crecp->addr.ds.keytag = > keytag; > -+ crecp->addr.ds.keylen = > rdlen2 - 4; > -+ } > -+ } > -+ } > -+ else if (type2 == T_RRSIG) > -+ { > -+ if (rdlen2 < 18) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ GETSHORT(type_covered, p2); > -+ > -+ if (type_covered == type1 && > -+ (type_covered == T_A || > type_covered == T_AAAA || > -+ type_covered == T_CNAME || > type_covered == T_DS || > -+ type_covered == T_DNSKEY || > type_covered == T_PTR)) > -+ { > -+ a.addr.dnssec.type = > type_covered; > -+ a.addr.dnssec.class = class1; > -+ > -+ algo = *p2++; > -+ p2 += 13; /* labels, orig_ttl, > expiration, inception */ > -+ GETSHORT(keytag, p2); > -+ > -+ /* We don't cache sigs for > wildcard answers, because to reproduce the > -+ answer from the cache will > require one or more NSEC/NSEC3 records > -+ which we don't cache. The lack > of the RRSIG ensures that a query for > -+ this RRset asking for a secure > answer will always be forwarded. */ > -+ if (!have_wildcard && (key = > blockdata_alloc((char*)psave, rdlen2))) > -+ { > -+ if (!(crecp = > cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS))) > -+ blockdata_free(key); > -+ else > -+ { > -+ crecp->addr.sig.keydata = > key; > -+ crecp->addr.sig.keylen = > rdlen2; > -+ crecp->addr.sig.keytag = > keytag; > -+ crecp- > >addr.sig.type_covered = type_covered; > -+ crecp->addr.sig.algo = > algo; > -+ } > - } > - } > - } > -+ > -+ p2 = psave; > - } > - > -- p2 = psave; > -+ if (!ADD_RDLEN(header, p2, plen, rdlen2)) > -+ return STAT_BOGUS; /* bad packet */ > - } > - > -- if (!ADD_RDLEN(header, p2, plen, rdlen2)) > -- return STAT_BOGUS; /* bad packet */ > -+ cache_end_insert(); > - } > -- > -- cache_end_insert(); > - } > - } > - > -@@ -2083,143 +2223,49 @@ int dnssec_validate_reply(time_t now, > struct dns_header *header, size_t plen, ch > - return STAT_BOGUS; > - } > - > -- /* OK, all the RRsets validate, now see if we have a NODATA or > NXDOMAIN reply */ > -- if (have_answer) > -- return STAT_SECURE; > -- > -- /* NXDOMAIN or NODATA reply, prove that (name, class1, type1) > can't exist */ > -- /* First marshall the NSEC records, if we've not done it > previously */ > -- if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, > &nsecs, &nsec_count, qclass))) > -- { > -- /* No NSEC records. If we dropped off the end of a CNAME > chain, return > -- STAT_NO_SIG and the last name is keyname. This is used for > proving non-existence > -- if DS records in CNAME chains. */ > -- if (cname_count == CNAME_CHAIN) /* No CNAME chain, return > empty name. */ > -- *keyname = 0; > -- else if (!extract_name(header, plen, &qname, keyname, 1, 0)) > -- return STAT_BOGUS; > -- return STAT_NO_SIG; /* No NSECs, this is probably a dangling > CNAME pointing into > -- an unsigned zone. Return STAT_NO_SIG > to cause this to be proved. */ > -- } > -- > -- /* Get name of missing answer */ > -- if (!extract_name(header, plen, &qname, name, 1, 0)) > -- return STAT_BOGUS; > -- > -- if (nsec_type == T_NSEC) > -- return prove_non_existence_nsec(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, qtype, nons); > -- else > -- return prove_non_existence_nsec3(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons); > --} > -- > --/* Chase the CNAME chain in the packet until the first record which > _doesn't validate. > -- Needed for proving answer in unsigned space. > -- Return STAT_NEED_* > -- STAT_BOGUS - error > -- STAT_INSECURE - name of first non-secure record in name > --*/ > --int dnssec_chase_cname(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname) > --{ > -- unsigned char *p = (unsigned char *)(header+1); > -- int type, class, qclass, rdlen, j, rc; > -- int cname_count = CNAME_CHAIN; > -- char *wildname; > -- > -- /* Get question */ > -- if (!extract_name(header, plen, &p, name, 1, 4)) > -- return STAT_BOGUS; > -- > -- p +=2; /* type */ > -- GETSHORT(qclass, p); > -- > -- while (1) > -- { > -- for (j = ntohs(header->ancount); j != 0; j--) > -- { > -- if (!(rc = extract_name(header, plen, &p, name, 0, 10))) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(type, p); > -- GETSHORT(class, p); > -- p += 4; /* TTL */ > -- GETSHORT(rdlen, p); > -- > -- /* Not target, loop */ > -- if (rc == 2 || qclass != class) > -- { > -- if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return STAT_BOGUS; > -- continue; > -- } > -- > -- /* Got to end of CNAME chain. */ > -- if (type != T_CNAME) > -- return STAT_INSECURE; > -- > -- /* validate CNAME chain, return if insecure or need more > data */ > -- rc = validate_rrset(now, header, plen, class, type, name, > keyname, &wildname, NULL, 0, 0, 0); > -- > -- if (rc == STAT_SECURE_WILDCARD) > -- { > -- int nsec_type, nsec_count, i; > -- unsigned char **nsecs; > -- > -- /* An attacker can replay a wildcard answer with a > different > -- answer and overlay a genuine RR. To prove this > -- hasn't happened, the answer must prove that > -- the genuine record doesn't exist. Check that here. > */ > -- if (!(nsec_type = find_nsec_records(header, plen, > &nsecs, &nsec_count, class))) > -- return STAT_BOGUS; /* No NSECs or bad packet */ > -- > -- /* Note that we're called here because something > didn't validate in validate_reply, > -- so we can't assume that any NSEC records have been > validated. We do them by steam here */ > -- > -- for (i = 0; i < nsec_count; i++) > -- { > -- unsigned char *p1 = nsecs[i]; > -- > -- if (!extract_name(header, plen, &p1, daemon- > >workspacename, 1, 0)) > -- return STAT_BOGUS; > -- > -- rc = validate_rrset(now, header, plen, class, > nsec_type, daemon->workspacename, keyname, NULL, NULL, 0, 0, 0); > -+ /* OK, all the RRsets validate, now see if we have a missing > answer or CNAME target. */ > -+ for (j = 0; j <targetidx; j++) > -+ if ((p2 = targets[j])) > -+ { > -+ if (neganswer) > -+ *neganswer = 1; > - > -- /* NSECs can't be wildcards. */ > -- if (rc == STAT_SECURE_WILDCARD) > -- rc = STAT_BOGUS; > -+ if (!extract_name(header, plen, &p2, name, 1, 10)) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ /* NXDOMAIN or NODATA reply, unanswered question is (name, > qclass, qtype) */ > - > -- if (rc != STAT_SECURE) > -+ /* For anything other than a DS record, this situation is > OK if either > -+ the answer is in an unsigned zone, or there's a NSEC > records. */ > -+ if (!(nsec_type = find_nsec_records(header, plen, &nsecs, > &nsec_count, qclass))) > -+ { > -+ /* Empty DS without NSECS */ > -+ if (qtype == T_DS) > -+ return STAT_BOGUS; > -+ else > -+ { > -+ rc = zone_status(name, qclass, keyname, now); > -+ if (rc != STAT_SECURE) > -+ { > -+ if (class) > -+ *class = qclass; /* Class for NEED_DS or > NEED_DNSKEY */ > - return rc; > -- } > -- > -- if (nsec_type == T_NSEC) > -- rc = prove_non_existence_nsec(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, type, NULL); > -- else > -- rc = prove_non_existence_nsec3(header, plen, nsecs, > nsec_count, daemon->workspacename, > -- keyname, name, type, > wildname, NULL); > -- > -- if (rc != STAT_SECURE) > -- return rc; > -- } > -- > -- if (rc != STAT_SECURE) > -- { > -- if (rc == STAT_NO_SIG) > -- rc = STAT_INSECURE; > -- return rc; > -- } > -+ } > -+ > -+ return STAT_BOGUS; /* signed zone, no NSECs */ > -+ } > -+ } > - > -- /* Loop down CNAME chain/ */ > -- if (!cname_count-- || > -- !extract_name(header, plen, &p, name, 1, 0) || > -- !(p = skip_questions(header, plen))) > -- return STAT_BOGUS; > -- > -- break; > -- } > -+ if (nsec_type == T_NSEC) > -+ rc = prove_non_existence_nsec(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, qtype, nons); > -+ else > -+ rc = prove_non_existence_nsec3(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons); > - > -- /* End of CNAME chain */ > -- return STAT_INSECURE; > -- } > -+ if (rc != STAT_SECURE) > -+ return rc; > -+ } > -+ > -+ return STAT_SECURE; > - } > - > - > -diff --git a/src/forward.c b/src/forward.c > -index b76a974..dd22a62 100644 > ---- a/src/forward.c > -+++ b/src/forward.c > -@@ -23,15 +23,6 @@ static struct frec > *lookup_frec_by_sender(unsigned short id, > - static unsigned short get_id(void); > - static void free_frec(struct frec *f); > - > --#ifdef HAVE_DNSSEC > --static int tcp_key_recurse(time_t now, int status, struct > dns_header *header, size_t n, > -- int class, char *name, char *keyname, > struct server *server, int *keycount); > --static int do_check_sign(struct frec *forward, int status, time_t > now, char *name, char *keyname); > --static int send_check_sign(struct frec *forward, time_t now, struct > dns_header *header, size_t plen, > -- char *name, char *keyname); > --#endif > -- > -- > - /* Send a UDP packet with its source address set as "source" > - unless nowild is true, when we just send it with the kernel > default */ > - int send_from(int fd, int nowild, char *packet, size_t len, > -@@ -825,236 +816,142 @@ void reply_query(int fd, int family, time_t > now) > - #ifdef HAVE_DNSSEC > - if (server && option_bool(OPT_DNSSEC_VALID) && !(forward- > >flags & FREC_CHECKING_DISABLED)) > - { > -- int status; > -+ int status = 0; > - > - /* We've had a reply already, which we're validating. > Ignore this duplicate */ > - if (forward->blocking_query) > - return; > -- > -- if (header->hb3 & HB3_TC) > -- { > -- /* Truncated answer can't be validated. > -+ > -+ /* Truncated answer can't be validated. > - If this is an answer to a DNSSEC-generated query, > we still > - need to get the client to retry over TCP, so > return > - an answer with the TC bit set, even if the actual > answer fits. > - */ > -- status = STAT_TRUNCATED; > -- } > -- else if (forward->flags & FREC_DNSKEY_QUERY) > -- status = dnssec_validate_by_ds(now, header, n, daemon- > >namebuff, daemon->keyname, forward->class); > -- else if (forward->flags & FREC_DS_QUERY) > -- { > -- status = dnssec_validate_ds(now, header, n, daemon- > >namebuff, daemon->keyname, forward->class); > -- /* Provably no DS, everything below is insecure, even > if signatures are offered */ > -- if (status == STAT_NO_DS) > -- /* We only cache sigs when we've validated a reply. > -- Avoid caching a reply with sigs if there's a > vaildated break in the > -- DS chain, so we don't return replies from cache > missing sigs. */ > -- status = STAT_INSECURE_DS; > -- else if (status == STAT_NO_SIG) > -- { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- { > -- status = send_check_sign(forward, now, > header, n, daemon->namebuff, daemon->keyname); > -- if (status == STAT_INSECURE) > -- status = STAT_INSECURE_DS; > -- } > -- else > -- status = STAT_INSECURE_DS; > -- } > -- else if (status == STAT_NO_NS) > -- status = STAT_BOGUS; > -- } > -- else if (forward->flags & FREC_CHECK_NOSIGN) > -- { > -- status = dnssec_validate_ds(now, header, n, daemon- > >namebuff, daemon->keyname, forward->class); > -- if (status != STAT_NEED_KEY) > -- status = do_check_sign(forward, status, now, > daemon->namebuff, daemon->keyname); > -- } > -- else > -+ if (header->hb3 & HB3_TC) > -+ status = STAT_TRUNCATED; > -+ > -+ while (1) > - { > -- status = dnssec_validate_reply(now, header, n, > daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL); > -- if (status == STAT_NO_SIG) > -+ /* As soon as anything returns BOGUS, we stop and > unwind, to do otherwise > -+ would invite infinite loops, since the answers to > DNSKEY and DS queries > -+ will not be cached, so they'll be repeated. */ > -+ if (status != STAT_BOGUS && status != STAT_TRUNCATED > && status != STAT_ABANDONED) > - { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- status = send_check_sign(forward, now, header, > n, daemon->namebuff, daemon->keyname); > -+ if (forward->flags & FREC_DNSKEY_QUERY) > -+ status = dnssec_validate_by_ds(now, header, n, > daemon->namebuff, daemon->keyname, forward->class); > -+ else if (forward->flags & FREC_DS_QUERY) > -+ status = dnssec_validate_ds(now, header, n, > daemon->namebuff, daemon->keyname, forward->class); > - else > -- status = STAT_INSECURE; > -+ status = dnssec_validate_reply(now, header, n, > daemon->namebuff, daemon->keyname, &forward->class, > -+ option_bool(OPT_ > DNSSEC_NO_SIGN), NULL, NULL); > - } > -- } > -- /* Can't validate, as we're missing key data. Put this > -- answer aside, whilst we get that. */ > -- if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG > || status == STAT_NEED_KEY) > -- { > -- struct frec *new, *orig; > -- > -- /* Free any saved query */ > -- if (forward->stash) > -- blockdata_free(forward->stash); > -- > -- /* Now save reply pending receipt of key data */ > -- if (!(forward->stash = blockdata_alloc((char > *)header, n))) > -- return; > -- forward->stash_len = n; > - > -- anotherkey: > -- /* Find the original query that started it all.... */ > -- for (orig = forward; orig->dependent; orig = orig- > >dependent); > -- > -- if (--orig->work_counter == 0 || !(new = > get_new_frec(now, NULL, 1))) > -- status = STAT_INSECURE; > -- else > -+ /* Can't validate, as we're missing key data. Put > this > -+ answer aside, whilst we get that. */ > -+ if (status == STAT_NEED_DS || status == > STAT_NEED_KEY) > - { > -- int fd; > -- struct frec *next = new->next; > -- *new = *forward; /* copy everything, then > overwrite */ > -- new->next = next; > -- new->blocking_query = NULL; > -- new->sentto = server; > -- new->rfd4 = NULL; > -- new->orig_domain = NULL; > --#ifdef HAVE_IPV6 > -- new->rfd6 = NULL; > --#endif > -- new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY > | FREC_CHECK_NOSIGN); > -+ struct frec *new, *orig; > - > -- new->dependent = forward; /* to find query > awaiting new one. */ > -- forward->blocking_query = new; /* for garbage > cleaning */ > -- /* validate routines leave name of required > record in daemon->keyname */ > -- if (status == STAT_NEED_KEY) > -- { > -- new->flags |= FREC_DNSKEY_QUERY; > -- nn = dnssec_generate_query(header, ((char *) > header) + daemon->packet_buff_sz, > -- daemon->keyname, > forward->class, T_DNSKEY, &server->addr, server->edns_pktsz); > -- } > -- else > -- { > -- if (status == STAT_NEED_DS_NEG) > -- new->flags |= FREC_CHECK_NOSIGN; > -- else > -- new->flags |= FREC_DS_QUERY; > -- nn = dnssec_generate_query(header,((char *) > header) + daemon->packet_buff_sz, > -- daemon->keyname, > forward->class, T_DS, &server->addr, server->edns_pktsz); > -- } > -- if ((hash = hash_questions(header, nn, daemon- > >namebuff))) > -- memcpy(new->hash, hash, HASH_SIZE); > -- new->new_id = get_id(); > -- header->id = htons(new->new_id); > -- /* Save query for retransmission */ > -- if (!(new->stash = blockdata_alloc((char > *)header, nn))) > -+ /* Free any saved query */ > -+ if (forward->stash) > -+ blockdata_free(forward->stash); > -+ > -+ /* Now save reply pending receipt of key data */ > -+ if (!(forward->stash = blockdata_alloc((char > *)header, n))) > - return; > -- > -- new->stash_len = nn; > -+ forward->stash_len = n; > - > -- /* Don't resend this. */ > -- daemon->srv_save = NULL; > -+ /* Find the original query that started it > all.... */ > -+ for (orig = forward; orig->dependent; orig = > orig->dependent); > - > -- if (server->sfd) > -- fd = server->sfd->fd; > -+ if (--orig->work_counter == 0 || !(new = > get_new_frec(now, NULL, 1))) > -+ status = STAT_ABANDONED; > - else > - { > -- fd = -1; > -+ int fd; > -+ struct frec *next = new->next; > -+ *new = *forward; /* copy everything, then > overwrite */ > -+ new->next = next; > -+ new->blocking_query = NULL; > -+ new->sentto = server; > -+ new->rfd4 = NULL; > - #ifdef HAVE_IPV6 > -- if (server->addr.sa.sa_family == AF_INET6) > -+ new->rfd6 = NULL; > -+#endif > -+ new->flags &= ~(FREC_DNSKEY_QUERY | > FREC_DS_QUERY); > -+ > -+ new->dependent = forward; /* to find query > awaiting new one. */ > -+ forward->blocking_query = new; /* for garbage > cleaning */ > -+ /* validate routines leave name of required > record in daemon->keyname */ > -+ if (status == STAT_NEED_KEY) > -+ { > -+ new->flags |= FREC_DNSKEY_QUERY; > -+ nn = dnssec_generate_query(header, ((char > *) header) + daemon->packet_buff_sz, > -+ daemon- > >keyname, forward->class, T_DNSKEY, &server->addr, server- > >edns_pktsz); > -+ } > -+ else > - { > -- if (new->rfd6 || (new->rfd6 = > allocate_rfd(AF_INET6))) > -- fd = new->rfd6->fd; > -+ new->flags |= FREC_DS_QUERY; > -+ nn = dnssec_generate_query(header,((char > *) header) + daemon->packet_buff_sz, > -+ daemon- > >keyname, forward->class, T_DS, &server->addr, server->edns_pktsz); > - } > -+ if ((hash = hash_questions(header, nn, > daemon->namebuff))) > -+ memcpy(new->hash, hash, HASH_SIZE); > -+ new->new_id = get_id(); > -+ header->id = htons(new->new_id); > -+ /* Save query for retransmission */ > -+ new->stash = blockdata_alloc((char *)header, > nn); > -+ new->stash_len = nn; > -+ > -+ /* Don't resend this. */ > -+ daemon->srv_save = NULL; > -+ > -+ if (server->sfd) > -+ fd = server->sfd->fd; > - else > -+ { > -+ fd = -1; > -+#ifdef HAVE_IPV6 > -+ if (server->addr.sa.sa_family == > AF_INET6) > -+ { > -+ if (new->rfd6 || (new->rfd6 = > allocate_rfd(AF_INET6))) > -+ fd = new->rfd6->fd; > -+ } > -+ else > - #endif > -+ { > -+ if (new->rfd4 || (new->rfd4 = > allocate_rfd(AF_INET))) > -+ fd = new->rfd4->fd; > -+ } > -+ } > -+ > -+ if (fd != -1) > - { > -- if (new->rfd4 || (new->rfd4 = > allocate_rfd(AF_INET))) > -- fd = new->rfd4->fd; > -+ while (retry_send(sendto(fd, (char > *)header, nn, 0, > -+ &server- > >addr.sa, > -+ sa_len(&server- > >addr)))); > -+ server->queries++; > - } > -- } > -- > -- if (fd != -1) > -- { > -- while (retry_send(sendto(fd, (char *)header, > nn, 0, > -- &server->addr.sa, > -- sa_len(&server- > >addr)))); > -- server->queries++; > -- } > -- > -+ } > - return; > - } > -- } > - > -- /* Ok, we reached far enough up the chain-of-trust that > we can validate something. > -- Now wind back down, pulling back answers which > wouldn't previously validate > -- and validate them with the new data. Note that if an > answer needs multiple > -- keys to validate, we may find another key is needed, > in which case we set off > -- down another branch of the tree. Once we get to the > original answer > -- (FREC_DNSSEC_QUERY not set) and it validates, return > it to the original requestor. */ > -- while (forward->dependent) > -- { > -+ /* Validated original answer, all done. */ > -+ if (!forward->dependent) > -+ break; > -+ > -+ /* validated subsdiary query, (and cached result) > -+ pop that and return to the previous query we were > working on. */ > - struct frec *prev = forward->dependent; > - free_frec(forward); > - forward = prev; > - forward->blocking_query = NULL; /* already gone */ > - blockdata_retrieve(forward->stash, forward- > >stash_len, (void *)header); > - n = forward->stash_len; > -- > -- if (status == STAT_SECURE) > -- { > -- if (forward->flags & FREC_DNSKEY_QUERY) > -- status = dnssec_validate_by_ds(now, header, n, > daemon->namebuff, daemon->keyname, forward->class); > -- else if (forward->flags & FREC_DS_QUERY) > -- { > -- status = dnssec_validate_ds(now, header, n, > daemon->namebuff, daemon->keyname, forward->class); > -- /* Provably no DS, everything below is > insecure, even if signatures are offered */ > -- if (status == STAT_NO_DS) > -- /* We only cache sigs when we've validated > a reply. > -- Avoid caching a reply with sigs if > there's a vaildated break in the > -- DS chain, so we don't return replies > from cache missing sigs. */ > -- status = STAT_INSECURE_DS; > -- else if (status == STAT_NO_SIG) > -- { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- { > -- status = send_check_sign(forward, > now, header, n, daemon->namebuff, daemon->keyname); > -- if (status == STAT_INSECURE) > -- status = STAT_INSECURE_DS; > -- } > -- else > -- status = STAT_INSECURE_DS; > -- } > -- else if (status == STAT_NO_NS) > -- status = STAT_BOGUS; > -- } > -- else if (forward->flags & FREC_CHECK_NOSIGN) > -- { > -- status = dnssec_validate_ds(now, header, n, > daemon->namebuff, daemon->keyname, forward->class); > -- if (status != STAT_NEED_KEY) > -- status = do_check_sign(forward, status, > now, daemon->namebuff, daemon->keyname); > -- } > -- else > -- { > -- status = dnssec_validate_reply(now, header, > n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL); > -- if (status == STAT_NO_SIG) > -- { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- status = send_check_sign(forward, now, > header, n, daemon->namebuff, daemon->keyname); > -- else > -- status = STAT_INSECURE; > -- } > -- } > -- > -- if (status == STAT_NEED_DS || status == > STAT_NEED_DS_NEG || status == STAT_NEED_KEY) > -- goto anotherkey; > -- } > - } > -+ > - > - no_cache_dnssec = 0; > -- > -- if (status == STAT_INSECURE_DS) > -- { > -- /* We only cache sigs when we've validated a reply. > -- Avoid caching a reply with sigs if there's a > vaildated break in the > -- DS chain, so we don't return replies from cache > missing sigs. */ > -- status = STAT_INSECURE; > -- no_cache_dnssec = 1; > -- } > - > - if (status == STAT_TRUNCATED) > - header->hb3 |= HB3_TC; > -@@ -1062,7 +959,7 @@ void reply_query(int fd, int family, time_t > now) > - { > - char *result, *domain = "result"; > - > -- if (forward->work_counter == 0) > -+ if (status == STAT_ABANDONED) > - { > - result = "ABANDONED"; > - status = STAT_BOGUS; > -@@ -1072,7 +969,7 @@ void reply_query(int fd, int family, time_t > now) > - > - if (status == STAT_BOGUS && extract_request(header, > n, daemon->namebuff, NULL)) > - domain = daemon->namebuff; > -- > -+ > - log_query(F_KEYTAG | F_SECSTAT, domain, NULL, > result); > - } > - > -@@ -1415,315 +1312,49 @@ void receive_query(struct listener *listen, > time_t now) > - } > - > - #ifdef HAVE_DNSSEC > -- > --/* UDP: we've got an unsigned answer, return STAT_INSECURE if we > can prove there's no DS > -- and therefore the answer shouldn't be signed, or STAT_BOGUS if > it should be, or > -- STAT_NEED_DS_NEG and keyname if we need to do the query. */ > --static int send_check_sign(struct frec *forward, time_t now, struct > dns_header *header, size_t plen, > -- char *name, char *keyname) > --{ > -- int status = dnssec_chase_cname(now, header, plen, name, > keyname); > -- > -- if (status != STAT_INSECURE) > -- return status; > -- > -- /* Store the domain we're trying to check. */ > -- forward->name_start = strlen(name); > -- forward->name_len = forward->name_start + 1; > -- if (!(forward->orig_domain = blockdata_alloc(name, forward- > >name_len))) > -- return STAT_BOGUS; > -- > -- return do_check_sign(forward, 0, now, name, keyname); > --} > -- > --/* We either have a a reply (header non-NULL, or we need to start > by looking in the cache */ > --static int do_check_sign(struct frec *forward, int status, time_t > now, char *name, char *keyname) > --{ > -- /* get domain we're checking back from blockdata store, it's > stored on the original query. */ > -- while (forward->dependent && !forward->orig_domain) > -- forward = forward->dependent; > -- > -- blockdata_retrieve(forward->orig_domain, forward->name_len, > name); > -- > -- while (1) > -- { > -- char *p; > -- > -- if (status == 0) > -- { > -- struct crec *crecp; > -- > -- /* Haven't received answer, see if in cache */ > -- if (!(crecp = cache_find_by_name(NULL, &name[forward- > >name_start], now, F_DS))) > -- { > -- /* put name of DS record we're missing into keyname > */ > -- strcpy(keyname, &name[forward->name_start]); > -- /* and wait for reply to arrive */ > -- return STAT_NEED_DS_NEG; > -- } > -- > -- /* F_DNSSECOK misused in DS cache records to non- > existance of NS record */ > -- if (!(crecp->flags & F_NEG)) > -- status = STAT_SECURE; > -- else if (crecp->flags & F_DNSSECOK) > -- status = STAT_NO_DS; > -- else > -- status = STAT_NO_NS; > -- } > -- > -- /* Have entered non-signed part of DNS tree. */ > -- if (status == STAT_NO_DS) > -- return forward->dependent ? STAT_INSECURE_DS : > STAT_INSECURE; > -- > -- if (status == STAT_BOGUS) > -- return STAT_BOGUS; > -- > -- if (status == STAT_NO_SIG && *keyname != 0) > -- { > -- /* There is a validated CNAME chain that doesn't end in a > DS record. Start > -- the search again in that domain. */ > -- blockdata_free(forward->orig_domain); > -- forward->name_start = strlen(keyname); > -- forward->name_len = forward->name_start + 1; > -- if (!(forward->orig_domain = blockdata_alloc(keyname, > forward->name_len))) > -- return STAT_BOGUS; > -- > -- strcpy(name, keyname); > -- status = 0; /* force to cache when we iterate. */ > -- continue; > -- } > -- > -- /* There's a proven DS record, or we're within a zone, where > there doesn't need > -- to be a DS record. Add a name and try again. > -- If we've already tried the whole name, then fail */ > -- > -- if (forward->name_start == 0) > -- return STAT_BOGUS; > -- > -- for (p = &name[forward->name_start-2]; (*p != '.') && (p != > name); p--); > -- > -- if (p != name) > -- p++; > -- > -- forward->name_start = p - name; > -- status = 0; /* force to cache when we iterate. */ > -- } > --} > -- > --/* Move down from the root, until we find a signed non-existance of > a DS, in which case > -- an unsigned answer is OK, or we find a signed DS, in which case > there should be > -- a signature, and the answer is BOGUS */ > --static int tcp_check_for_unsigned_zone(time_t now, struct > dns_header *header, size_t plen, int class, char *name, > -- char *keyname, struct > server *server, int *keycount) > --{ > -- size_t m; > -- unsigned char *packet, *payload; > -- u16 *length; > -- int status, name_len; > -- struct blockdata *block; > -- > -- char *name_start; > -- > -- /* Get first insecure entry in CNAME chain */ > -- status = tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, > class, name, keyname, server, keycount); > -- if (status == STAT_BOGUS) > -- return STAT_BOGUS; > -- > -- if (!(packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + > sizeof(u16)))) > -- return STAT_BOGUS; > -- > -- payload = &packet[2]; > -- header = (struct dns_header *)payload; > -- length = (u16 *)packet; > -- > -- /* Stash the name away, since the buffer will be trashed when we > recurse */ > -- name_len = strlen(name) + 1; > -- name_start = name + name_len - 1; > -- > -- if (!(block = blockdata_alloc(name, name_len))) > -- { > -- free(packet); > -- return STAT_BOGUS; > -- } > -- > -- while (1) > -- { > -- unsigned char c1, c2; > -- struct crec *crecp; > -- > -- if (--(*keycount) == 0) > -- { > -- free(packet); > -- blockdata_free(block); > -- return STAT_BOGUS; > -- } > -- > -- while ((crecp = cache_find_by_name(NULL, name_start, now, > F_DS))) > -- { > -- if ((crecp->flags & F_NEG) && (crecp->flags & > F_DNSSECOK)) > -- { > -- /* Found a secure denial of DS - delegation is indeed > insecure */ > -- free(packet); > -- blockdata_free(block); > -- return STAT_INSECURE; > -- } > -- > -- /* Here, either there's a secure DS, or no NS and no DS, > and therefore no delegation. > -- Add another label and continue. */ > -- > -- if (name_start == name) > -- { > -- free(packet); > -- blockdata_free(block); > -- return STAT_BOGUS; /* run out of labels */ > -- } > -- > -- name_start -= 2; > -- while (*name_start != '.' && name_start != name) > -- name_start--; > -- if (name_start != name) > -- name_start++; > -- } > -- > -- /* Can't find it in the cache, have to send a query */ > -- > -- m = dnssec_generate_query(header, ((char *) header) + 65536, > name_start, class, T_DS, &server->addr, server->edns_pktsz); > -- > -- *length = htons(m); > -- > -- if (read_write(server->tcpfd, packet, m + sizeof(u16), 0) && > -- read_write(server->tcpfd, &c1, 1, 1) && > -- read_write(server->tcpfd, &c2, 1, 1) && > -- read_write(server->tcpfd, payload, (c1 << 8) | c2, 1)) > -- { > -- m = (c1 << 8) | c2; > -- > -- /* Note this trashes all three name workspaces */ > -- status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, > m, class, name, keyname, server, keycount); > -- > -- if (status == STAT_NO_DS) > -- { > -- /* Found a secure denial of DS - delegation is indeed > insecure */ > -- free(packet); > -- blockdata_free(block); > -- return STAT_INSECURE; > -- } > -- > -- if (status == STAT_NO_SIG && *keyname != 0) > -- { > -- /* There is a validated CNAME chain that doesn't end > in a DS record. Start > -- the search again in that domain. */ > -- blockdata_free(block); > -- name_len = strlen(keyname) + 1; > -- name_start = name + name_len - 1; > -- > -- if (!(block = blockdata_alloc(keyname, name_len))) > -- return STAT_BOGUS; > -- > -- strcpy(name, keyname); > -- continue; > -- } > -- > -- if (status == STAT_BOGUS) > -- { > -- free(packet); > -- blockdata_free(block); > -- return STAT_BOGUS; > -- } > -- > -- /* Here, either there's a secure DS, or no NS and no DS, > and therefore no delegation. > -- Add another label and continue. */ > -- > -- /* Get name we're checking back. */ > -- blockdata_retrieve(block, name_len, name); > -- > -- if (name_start == name) > -- { > -- free(packet); > -- blockdata_free(block); > -- return STAT_BOGUS; /* run out of labels */ > -- } > -- > -- name_start -= 2; > -- while (*name_start != '.' && name_start != name) > -- name_start--; > -- if (name_start != name) > -- name_start++; > -- } > -- else > -- { > -- /* IO failure */ > -- free(packet); > -- blockdata_free(block); > -- return STAT_BOGUS; /* run out of labels */ > -- } > -- } > --} > -- > - static int tcp_key_recurse(time_t now, int status, struct > dns_header *header, size_t n, > - int class, char *name, char *keyname, > struct server *server, int *keycount) > - { > - /* Recurse up the key heirarchy */ > - int new_status; > -+ unsigned char *packet = NULL; > -+ size_t m; > -+ unsigned char *payload = NULL; > -+ struct dns_header *new_header = NULL; > -+ u16 *length = NULL; > -+ unsigned char c1, c2; > - > -- /* limit the amount of work we do, to avoid cycling forever on > loops in the DNS */ > -- if (--(*keycount) == 0) > -- return STAT_INSECURE; > -- > -- if (status == STAT_NEED_KEY) > -- new_status = dnssec_validate_by_ds(now, header, n, name, > keyname, class); > -- else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG) > -+ while (1) > - { > -- new_status = dnssec_validate_ds(now, header, n, name, > keyname, class); > -- if (status == STAT_NEED_DS) > -+ /* limit the amount of work we do, to avoid cycling forever > on loops in the DNS */ > -+ if (--(*keycount) == 0) > -+ new_status = STAT_ABANDONED; > -+ else if (status == STAT_NEED_KEY) > -+ new_status = dnssec_validate_by_ds(now, header, n, name, > keyname, class); > -+ else if (status == STAT_NEED_DS) > -+ new_status = dnssec_validate_ds(now, header, n, name, > keyname, class); > -+ else > -+ new_status = dnssec_validate_reply(now, header, n, name, > keyname, &class, option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL); > -+ > -+ if (new_status != STAT_NEED_DS && new_status != > STAT_NEED_KEY) > -+ break; > -+ > -+ /* Can't validate because we need a key/DS whose name now in > keyname. > -+ Make query for same, and recurse to validate */ > -+ if (!packet) > - { > -- if (new_status == STAT_NO_DS) > -- new_status = STAT_INSECURE_DS; > -- if (new_status == STAT_NO_SIG) > -- { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- { > -- new_status = tcp_check_for_unsigned_zone(now, > header, n, class, name, keyname, server, keycount); > -- if (new_status == STAT_INSECURE) > -- new_status = STAT_INSECURE_DS; > -- } > -- else > -- new_status = STAT_INSECURE_DS; > -- } > -- else if (new_status == STAT_NO_NS) > -- new_status = STAT_BOGUS; > -+ packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + > sizeof(u16)); > -+ payload = &packet[2]; > -+ new_header = (struct dns_header *)payload; > -+ length = (u16 *)packet; > - } > -- } > -- else if (status == STAT_CHASE_CNAME) > -- new_status = dnssec_chase_cname(now, header, n, name, keyname); > -- else > -- { > -- new_status = dnssec_validate_reply(now, header, n, name, > keyname, &class, NULL, NULL); > - > -- if (new_status == STAT_NO_SIG) > -+ if (!packet) > - { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- new_status = tcp_check_for_unsigned_zone(now, header, > n, class, name, keyname, server, keycount); > -- else > -- new_status = STAT_INSECURE; > -+ new_status = STAT_ABANDONED; > -+ break; > - } > -- } > -- > -- /* Can't validate because we need a key/DS whose name now in > keyname. > -- Make query for same, and recurse to validate */ > -- if (new_status == STAT_NEED_DS || new_status == STAT_NEED_KEY) > -- { > -- size_t m; > -- unsigned char *packet = whine_malloc(65536 + MAXDNAME + > RRFIXEDSZ + sizeof(u16)); > -- unsigned char *payload = &packet[2]; > -- struct dns_header *new_header = (struct dns_header *)payload; > -- u16 *length = (u16 *)packet; > -- unsigned char c1, c2; > -- > -- if (!packet) > -- return STAT_INSECURE; > -- > -- another_tcp_key: > -+ > - m = dnssec_generate_query(new_header, ((char *) new_header) + > 65536, keyname, class, > - new_status == STAT_NEED_KEY ? > T_DNSKEY : T_DS, &server->addr, server->edns_pktsz); > - > -@@ -1733,65 +1364,22 @@ static int tcp_key_recurse(time_t now, int > status, struct dns_header *header, si > - !read_write(server->tcpfd, &c1, 1, 1) || > - !read_write(server->tcpfd, &c2, 1, 1) || > - !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1)) > -- new_status = STAT_INSECURE; > -- else > - { > -- m = (c1 << 8) | c2; > -- > -- new_status = tcp_key_recurse(now, new_status, new_header, > m, class, name, keyname, server, keycount); > -- > -- if (new_status == STAT_SECURE) > -- { > -- /* Reached a validated record, now try again at this > level. > -- Note that we may get ANOTHER NEED_* if an answer > needs more than one key. > -- If so, go round again. */ > -- > -- if (status == STAT_NEED_KEY) > -- new_status = dnssec_validate_by_ds(now, header, n, > name, keyname, class); > -- else if (status == STAT_NEED_DS || status == > STAT_NEED_DS_NEG) > -- { > -- new_status = dnssec_validate_ds(now, header, n, > name, keyname, class); > -- if (status == STAT_NEED_DS) > -- { > -- if (new_status == STAT_NO_DS) > -- new_status = STAT_INSECURE_DS; > -- else if (new_status == STAT_NO_SIG) > -- { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- { > -- new_status = > tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, > server, keycount); > -- if (new_status == STAT_INSECURE) > -- new_status = STAT_INSECURE_DS; > -- } > -- else > -- new_status = STAT_INSECURE_DS; > -- } > -- else if (new_status == STAT_NO_NS) > -- new_status = STAT_BOGUS; > -- } > -- } > -- else if (status == STAT_CHASE_CNAME) > -- new_status = dnssec_chase_cname(now, header, n, > name, keyname); > -- else > -- { > -- new_status = dnssec_validate_reply(now, header, > n, name, keyname, &class, NULL, NULL); > -- > -- if (new_status == STAT_NO_SIG) > -- { > -- if (option_bool(OPT_DNSSEC_NO_SIGN)) > -- new_status = > tcp_check_for_unsigned_zone(now, header, n, class, name, keyname, > server, keycount); > -- else > -- new_status = STAT_INSECURE; > -- } > -- } > -- > -- if (new_status == STAT_NEED_DS || new_status == > STAT_NEED_KEY) > -- goto another_tcp_key; > -- } > -+ new_status = STAT_ABANDONED; > -+ break; > - } > -+ > -+ m = (c1 << 8) | c2; > - > -- free(packet); > -+ new_status = tcp_key_recurse(now, new_status, new_header, m, > class, name, keyname, server, keycount); > -+ > -+ if (new_status != STAT_OK) > -+ break; > - } > -+ > -+ if (packet) > -+ free(packet); > -+ > - return new_status; > - } > - #endif > -@@ -2075,19 +1663,10 @@ unsigned char *tcp_request(int confd, time_t > now, > - if (option_bool(OPT_DNSSEC_VALID) && > !checking_disabled) > - { > - int keycount = DNSSEC_WORK; /* Limit to > number of DNSSEC questions, to catch loops and avoid filling cache. > */ > -- int status = tcp_key_recurse(now, > STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, > last_server, &keycount); > -+ int status = tcp_key_recurse(now, > STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, > last_server, &keycount); > - char *result, *domain = "result"; > -- > -- if (status == STAT_INSECURE_DS) > -- { > -- /* We only cache sigs when we've > validated a reply. > -- Avoid caching a reply with sigs if > there's a vaildated break in the > -- DS chain, so we don't return > replies from cache missing sigs. */ > -- status = STAT_INSECURE; > -- no_cache_dnssec = 1; > -- } > - > -- if (keycount == 0) > -+ if (status == STAT_ABANDONED) > - { > - result = "ABANDONED"; > - status = STAT_BOGUS; > -@@ -2179,7 +1758,6 @@ static struct frec *allocate_frec(time_t now) > - f->dependent = NULL; > - f->blocking_query = NULL; > - f->stash = NULL; > -- f->orig_domain = NULL; > - #endif > - daemon->frec_list = f; > - } > -@@ -2248,12 +1826,6 @@ static void free_frec(struct frec *f) > - f->stash = NULL; > - } > - > -- if (f->orig_domain) > -- { > -- blockdata_free(f->orig_domain); > -- f->orig_domain = NULL; > -- } > -- > - /* Anything we're waiting on is pointless now, too */ > - if (f->blocking_query) > - free_frec(f->blocking_query); > -@@ -2281,14 +1853,23 @@ struct frec *get_new_frec(time_t now, int > *wait, int force) > - target = f; > - else > - { > -- if (difftime(now, f->time) >= 4*TIMEOUT) > -- { > -- free_frec(f); > -- target = f; > -- } > -- > -- if (!oldest || difftime(f->time, oldest->time) <= 0) > -- oldest = f; > -+#ifdef HAVE_DNSSEC > -+ /* Don't free DNSSEC sub-queries here, as we may end up > with > -+ dangling references to them. They'll go when their > "real" query > -+ is freed. */ > -+ if (!f->dependent) > -+#endif > -+ { > -+ if (difftime(now, f->time) >= 4*TIMEOUT) > -+ { > -+ free_frec(f); > -+ target = f; > -+ } > -+ > -+ > -+ if (!oldest || difftime(f->time, oldest->time) <= > 0) > -+ oldest = f; > -+ } > - } > - > - if (target) > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/017- > Abandon_caching_RRSIGs_and_returning_them_from_cache.patch > b/src/patches/dnsmasq/017- > Abandon_caching_RRSIGs_and_returning_them_from_cache.patch > deleted file mode 100644 > index 5ffaf97..0000000 > --- a/src/patches/dnsmasq/017- > Abandon_caching_RRSIGs_and_returning_them_from_cache.patch > +++ /dev/null > @@ -1,612 +0,0 @@ > -From 93be5b1e023b0c661e1ec2cd6d811a8ec9055c49 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 15 Dec 2015 12:04:40 +0000 > -Subject: [PATCH] Abandon caching RRSIGs and returning them from > cache. > - > -The list of exceptions to being able to locally answer > -cached data for validated records when DNSSEC data is requested > -was getting too long, so don't ever do that. This means > -that the cache no longer has to hold RRSIGS and allows > -us to lose lots of code. Note that cached validated > -answers are still returned as long as do=0 > ---- > - src/cache.c | 38 ++--------- > - src/dnsmasq.h | 10 +-- > - src/dnssec.c | 94 ++++----------------------- > - src/rfc1035.c | 197 ++++++-------------------------------------- > ------------- > - 4 files changed, 42 insertions(+), 297 deletions(-) > - > -diff --git a/src/cache.c b/src/cache.c > -index 1b76b67..51ba7cc 100644 > ---- a/src/cache.c > -+++ b/src/cache.c > -@@ -189,12 +189,7 @@ static void cache_hash(struct crec *crecp) > - static void cache_blockdata_free(struct crec *crecp) > - { > - if (crecp->flags & F_DNSKEY) > -- { > -- if (crecp->flags & F_DS) > -- blockdata_free(crecp->addr.sig.keydata); > -- else > -- blockdata_free(crecp->addr.key.keydata); > -- } > -+ blockdata_free(crecp->addr.key.keydata); > - else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG)) > - blockdata_free(crecp->addr.ds.keydata); > - } > -@@ -369,13 +364,8 @@ static struct crec *cache_scan_free(char *name, > struct all_addr *addr, time_t no > - } > - > - #ifdef HAVE_DNSSEC > -- /* Deletion has to be class-sensitive for DS, DNSKEY, > RRSIG, also > -- type-covered sensitive for RRSIG */ > -- if ((flags & (F_DNSKEY | F_DS)) && > -- (flags & (F_DNSKEY | F_DS)) == (crecp->flags & > (F_DNSKEY | F_DS)) && > -- crecp->uid == addr->addr.dnssec.class && > -- (!((flags & (F_DS | F_DNSKEY)) == (F_DS | > F_DNSKEY)) || > -- crecp->addr.sig.type_covered == addr- > >addr.dnssec.type)) > -+ /* Deletion has to be class-sensitive for DS and > DNSKEY */ > -+ if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && > crecp->uid == addr->addr.dnssec.class) > - { > - if (crecp->flags & F_CONFIG) > - return crecp; > -@@ -532,13 +522,9 @@ struct crec *cache_insert(char *name, struct > all_addr *addr, > - struct all_addr free_addr = new->addr.addr;; > - > - #ifdef HAVE_DNSSEC > -- /* For DNSSEC records, addr holds class and > type_covered for RRSIG */ > -+ /* For DNSSEC records, addr holds class. */ > - if (new->flags & (F_DS | F_DNSKEY)) > -- { > -- free_addr.addr.dnssec.class = new->uid; > -- if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | > F_DNSKEY)) > -- free_addr.addr.dnssec.type = new- > >addr.sig.type_covered; > -- } > -+ free_addr.addr.dnssec.class = new->uid; > - #endif > - > - free_avail = 1; /* Must be free space now. */ > -@@ -653,9 +639,6 @@ struct crec *cache_find_by_name(struct crec > *crecp, char *name, time_t now, unsi > - if (!is_expired(now, crecp) && > !is_outdated_cname_pointer(crecp)) > - { > - if ((crecp->flags & F_FORWARD) && > --#ifdef HAVE_DNSSEC > -- (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & > (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) && > --#endif > - (crecp->flags & prot) && > - hostname_isequal(cache_get_name(crecp), name)) > - { > -@@ -713,9 +696,6 @@ struct crec *cache_find_by_name(struct crec > *crecp, char *name, time_t now, unsi > - > - if (ans && > - (ans->flags & F_FORWARD) && > --#ifdef HAVE_DNSSEC > -- (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | > F_DS))) || (prot & F_NSIGMATCH)) && > --#endif > - (ans->flags & prot) && > - hostname_isequal(cache_get_name(ans), name)) > - return ans; > -@@ -1472,11 +1452,7 @@ void dump_cache(time_t now) > - #ifdef HAVE_DNSSEC > - else if (cache->flags & F_DS) > - { > -- if (cache->flags & F_DNSKEY) > -- /* RRSIG */ > -- sprintf(a, "%5u %3u %s", cache->addr.sig.keytag, > -- cache->addr.sig.algo, querystr("", cache- > >addr.sig.type_covered)); > -- else if (!(cache->flags & F_NEG)) > -+ if (!(cache->flags & F_NEG)) > - sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, > - cache->addr.ds.algo, cache- > >addr.ds.digest); > - } > -@@ -1502,8 +1478,6 @@ void dump_cache(time_t now) > - else if (cache->flags & F_CNAME) > - t = "C"; > - #ifdef HAVE_DNSSEC > -- else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | > F_DNSKEY)) > -- t = "G"; /* DNSKEY and DS set -> RRISG */ > - else if (cache->flags & F_DS) > - t = "S"; > - else if (cache->flags & F_DNSKEY) > -diff --git a/src/dnsmasq.h b/src/dnsmasq.h > -index 023a1cf..4344cae 100644 > ---- a/src/dnsmasq.h > -+++ b/src/dnsmasq.h > -@@ -398,14 +398,9 @@ struct crec { > - unsigned char algo; > - unsigned char digest; > - } ds; > -- struct { > -- struct blockdata *keydata; > -- unsigned short keylen, type_covered, keytag; > -- char algo; > -- } sig; > - } addr; > - time_t ttd; /* time to die */ > -- /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS > */ > -+ /* used as class if DNSKEY/DS, index to source for F_HOSTS */ > - unsigned int uid; > - unsigned short flags; > - union { > -@@ -445,8 +440,7 @@ struct crec { > - #define F_SECSTAT (1u<<24) > - #define F_NO_RR (1u<<25) > - #define F_IPSET (1u<<26) > --#define F_NSIGMATCH (1u<<27) > --#define F_NOEXTRA (1u<<28) > -+#define F_NOEXTRA (1u<<27) > - > - /* Values of uid in crecs with F_CONFIG bit set. */ > - #define SRC_INTERFACE 0 > -diff --git a/src/dnssec.c b/src/dnssec.c > -index de7b335..1ae03a6 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1004,7 +1004,7 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - { > - unsigned char *psave, *p = (unsigned char *)(header+1); > - struct crec *crecp, *recp1; > -- int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, > type_covered; > -+ int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag; > - struct blockdata *key; > - struct all_addr a; > - > -@@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - > - if (valid) > - { > -- /* DNSKEY RRset determined to be OK, now cache it and the > RRsigs that sign it. */ > -+ /* DNSKEY RRset determined to be OK, now cache it. */ > - cache_start_insert(); > - > - p = skip_questions(header, plen); > -@@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - if ((key = blockdata_alloc((char*)p, rdlen - 4))) > - { > - if (!(recp1 = cache_insert(name, &a, now, > ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK))) > -- blockdata_free(key); > -+ { > -+ blockdata_free(key); > -+ return STAT_BOGUS; > -+ } > - else > - { > - a.addr.keytag = keytag; > -@@ -1169,38 +1172,7 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - } > - } > - } > -- else if (qtype == T_RRSIG) > -- { > -- /* RRSIG, cache if covers DNSKEY RRset */ > -- if (rdlen < 18) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(type_covered, p); > -- > -- if (type_covered == T_DNSKEY) > -- { > -- a.addr.dnssec.class = class; > -- a.addr.dnssec.type = type_covered; > -- > -- algo = *p++; > -- p += 13; /* labels, orig_ttl, expiration, > inception */ > -- GETSHORT(keytag, p); > -- if ((key = blockdata_alloc((char*)psave, > rdlen))) > -- { > -- if (!(crecp = cache_insert(name, &a, now, > ttl, F_FORWARD | F_DNSKEY | F_DS))) > -- blockdata_free(key); > -- else > -- { > -- crecp->addr.sig.keydata = key; > -- crecp->addr.sig.keylen = rdlen; > -- crecp->addr.sig.keytag = keytag; > -- crecp->addr.sig.type_covered = > type_covered; > -- crecp->addr.sig.algo = algo; > -- } > -- } > -- } > -- } > -- > -+ > - p = psave; > - } > - > -@@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - cache_start_insert(); > - > - a.addr.dnssec.class = class; > -- cache_insert(name, &a, now, ttl, flags); > -+ if (!cache_insert(name, &a, now, ttl, flags)) > -+ return STAT_BOGUS; > - > - cache_end_insert(); > - > -@@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - /* Not done, validate now */ > - if (j == i) > - { > -- int ttl, keytag, algo, digest, type_covered, sigcnt, > rrcnt; > -+ int ttl, keytag, algo, digest, sigcnt, rrcnt; > - unsigned char *psave; > - struct all_addr a; > - struct blockdata *key; > - struct crec *crecp; > - char *wildname; > -- int have_wildcard = 0; > -- > -+ > - if (!explore_rrset(header, plen, class1, type1, name, > keyname, &sigcnt, &rrcnt)) > - return STAT_BOGUS; > - > -@@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - > - if (rc == STAT_SECURE_WILDCARD) > - { > -- have_wildcard = 1; > -- > - /* An attacker replay a wildcard answer with > a different > - answer and overlay a genuine RR. To prove > this > - hasn't happened, the answer must prove > that > -@@ -2119,7 +2089,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - return rc; > - } > - > -- /* Cache RRsigs in answer section, and if we just > validated a DS RRset, cache it */ > -+ /* If we just validated a DS RRset, cache it */ > - /* Also note if the RRset is the answer to the > question, or the target of a CNAME */ > - cache_start_insert(); > - > -@@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - } > - } > - } > -- else if (type2 == T_RRSIG) > -- { > -- if (rdlen2 < 18) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(type_covered, p2); > -- > -- if (type_covered == type1 && > -- (type_covered == T_A || > type_covered == T_AAAA || > -- type_covered == T_CNAME || > type_covered == T_DS || > -- type_covered == T_DNSKEY || > type_covered == T_PTR)) > -- { > -- a.addr.dnssec.type = > type_covered; > -- a.addr.dnssec.class = class1; > -- > -- algo = *p2++; > -- p2 += 13; /* labels, orig_ttl, > expiration, inception */ > -- GETSHORT(keytag, p2); > -- > -- /* We don't cache sigs for > wildcard answers, because to reproduce the > -- answer from the cache will > require one or more NSEC/NSEC3 records > -- which we don't cache. The lack > of the RRSIG ensures that a query for > -- this RRset asking for a secure > answer will always be forwarded. */ > -- if (!have_wildcard && (key = > blockdata_alloc((char*)psave, rdlen2))) > -- { > -- if (!(crecp = > cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS))) > -- blockdata_free(key); > -- else > -- { > -- crecp->addr.sig.keydata = > key; > -- crecp->addr.sig.keylen = > rdlen2; > -- crecp->addr.sig.keytag = > keytag; > -- crecp- > >addr.sig.type_covered = type_covered; > -- crecp->addr.sig.algo = > algo; > -- } > -- } > -- } > -- } > -- > -+ > - p2 = psave; > - } > - > -diff --git a/src/rfc1035.c b/src/rfc1035.c > -index 4eb1772..def8fa0 100644 > ---- a/src/rfc1035.c > -+++ b/src/rfc1035.c > -@@ -1275,11 +1275,9 @@ int check_for_local_domain(char *name, time_t > now) > - struct naptr *naptr; > - > - /* Note: the call to cache_find_by_name is intended to find any > record which matches > -- ie A, AAAA, CNAME, DS. Because RRSIG records are marked by > setting both F_DS and F_DNSKEY, > -- cache_find_by name ordinarily only returns records with an > exact match on those bits (ie > -- for the call below, only DS records). The F_NSIGMATCH bit > changes this behaviour */ > -+ ie A, AAAA, CNAME. */ > - > -- if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 > | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) && > -+ if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 > | F_CNAME |F_NO_RR)) && > - (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) > - return 1; > - > -@@ -1566,9 +1564,11 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - GETSHORT(flags, pheader); > - > - if ((sec_reqd = flags & 0x8000)) > -- *do_bit = 1;/* do bit */ > -+ { > -+ *do_bit = 1;/* do bit */ > -+ *ad_reqd = 1; > -+ } > - > -- *ad_reqd = 1; > - dryrun = 1; > - } > - > -@@ -1636,98 +1636,6 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - } > - } > - > --#ifdef HAVE_DNSSEC > -- if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || > qtype == T_DS)) > -- { > -- int gotone = 0; > -- struct blockdata *keydata; > -- > -- /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */ > -- if (sec_reqd) > -- { > -- crecp = NULL; > -- while ((crecp = cache_find_by_name(crecp, name, now, > F_DNSKEY | F_DS))) > -- if (crecp->uid == qclass && crecp- > >addr.sig.type_covered == qtype) > -- break; > -- } > -- > -- if (!sec_reqd || crecp) > -- { > -- if (qtype == T_DS) > -- { > -- crecp = NULL; > -- while ((crecp = cache_find_by_name(crecp, name, > now, F_DS))) > -- if (crecp->uid == qclass) > -- { > -- gotone = 1; > -- if (!dryrun) > -- { > -- if (crecp->flags & F_NEG) > -- { > -- if (crecp->flags & F_NXDOMAIN) > -- nxdomain = 1; > -- log_query(F_UPSTREAM, name, NULL, > "no DS"); > -- } > -- else if ((keydata = > blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, > NULL))) > -- { > > -- struct all_addr a; > -- a.addr.keytag = crecp- > >addr.ds.keytag; > -- log_query(F_KEYTAG | (crecp->flags > & F_CONFIG), name, &a, "DS keytag %u"); > -- if (add_resource_record(header, > limit, &trunc, nameoffset, &ansp, > -- crec_ttl(cr > ecp, now), &nameoffset, > -- T_DS, > qclass, "sbbt", > -- crecp- > >addr.ds.keytag, crecp->addr.ds.algo, > -- crecp- > >addr.ds.digest, crecp->addr.ds.keylen, keydata)) > -- anscount++; > -- > -- } > -- } > -- } > -- } > -- else /* DNSKEY */ > -- { > -- crecp = NULL; > -- while ((crecp = cache_find_by_name(crecp, name, > now, F_DNSKEY))) > -- if (crecp->uid == qclass) > -- { > -- gotone = 1; > -- if (!dryrun && (keydata = > blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, > NULL))) > -- { > > -- struct all_addr a; > -- a.addr.keytag = crecp- > >addr.key.keytag; > -- log_query(F_KEYTAG | (crecp->flags & > F_CONFIG), name, &a, "DNSKEY keytag %u"); > -- if (add_resource_record(header, limit, > &trunc, nameoffset, &ansp, > -- crec_ttl(crecp, > now), &nameoffset, > -- T_DNSKEY, > qclass, "sbbt", > -- crecp- > >addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, > keydata)) > -- anscount++; > -- } > -- } > -- } > -- } > -- > -- /* Now do RRSIGs */ > -- if (gotone) > -- { > -- ans = 1; > -- auth = 0; > -- if (!dryrun && sec_reqd) > -- { > -- crecp = NULL; > -- while ((crecp = cache_find_by_name(crecp, name, > now, F_DNSKEY | F_DS))) > -- if (crecp->uid == qclass && crecp- > >addr.sig.type_covered == qtype && > -- (keydata = blockdata_retrieve(crecp- > >addr.sig.keydata, crecp->addr.sig.keylen, NULL))) > -- { > -- add_resource_record(header, limit, &trunc, > nameoffset, &ansp, > -- crec_ttl(crecp, now), > &nameoffset, > -- T_RRSIG, qclass, "t", > crecp->addr.sig.keylen, keydata); > -- anscount++; > -- } > -- } > -- } > -- } > --#endif > -- > - if (qclass == C_IN) > - { > - struct txt_record *t; > -@@ -1736,6 +1644,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - if ((t->class == qtype || qtype == T_ANY) && > hostname_isequal(name, t->name)) > - { > - ans = 1; > -+ sec_data = 0; > - if (!dryrun) > - { > - log_query(F_CONFIG | F_RRNAME, name, NULL, > "<RR>"); > -@@ -1792,6 +1701,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - > - if (intr) > - { > -+ sec_data = 0; > - ans = 1; > - if (!dryrun) > - { > -@@ -1805,6 +1715,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - else if (ptr) > - { > - ans = 1; > -+ sec_data = 0; > - if (!dryrun) > - { > - log_query(F_CONFIG | F_RRNAME, name, NULL, > "<PTR>"); > -@@ -1819,38 +1730,8 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - } > - else if ((crecp = cache_find_by_addr(NULL, &addr, > now, is_arpa))) > - { > -- if (!(crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) && sec_reqd) > -- { > -- if (!option_bool(OPT_DNSSEC_VALID) || > ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))) > -- crecp = NULL; > --#ifdef HAVE_DNSSEC > -- else if (crecp->flags & F_DNSSECOK) > -- { > -- int gotsig = 0; > -- struct crec *rr_crec = NULL; > -- > -- while ((rr_crec = > cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY))) > -- { > -- if (rr_crec->addr.sig.type_covered == > T_PTR && rr_crec->uid == C_IN) > -- { > -- char *sigdata = > blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec- > >addr.sig.keylen, NULL); > -- gotsig = 1; > -- > -- if (!dryrun && > -- add_resource_record(header, > limit, &trunc, nameoffset, &ansp, > -- rr_crec- > >ttd - now, &nameoffset, > -- T_RRSIG, > C_IN, "t", crecp->addr.sig.keylen, sigdata)) > -- anscount++; > -- } > -- } > -- > -- if (!gotsig) > -- crecp = NULL; > -- } > --#endif > -- } > -- > -- if (crecp) > -+ /* Don't use cache when DNSSEC data required. */ > -+ if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) > - { > - do > - { > -@@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - > - if (!(crecp->flags & F_DNSSECOK)) > - sec_data = 0; > -- > -+ > -+ ans = 1; > -+ > - if (crecp->flags & F_NEG) > - { > -- ans = 1; > - auth = 0; > - if (crecp->flags & F_NXDOMAIN) > - nxdomain = 1; > - if (!dryrun) > - log_query(crecp->flags & > ~F_FORWARD, name, &addr, NULL); > - } > -- else if ((crecp->flags & (F_HOSTS | > F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID)) > -+ else > - { > -- ans = 1; > - if (!(crecp->flags & (F_HOSTS | > F_DHCP))) > - auth = 0; > - if (!dryrun) > -@@ -1892,6 +1773,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - else if (is_rev_synth(is_arpa, &addr, name)) > - { > - ans = 1; > -+ sec_data = 0; > - if (!dryrun) > - { > - log_query(F_CONFIG | F_REVERSE | is_arpa, > name, &addr, NULL); > -@@ -1908,6 +1790,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - { > - /* if not in cache, enabled and private IPV4 > address, return NXDOMAIN */ > - ans = 1; > -+ sec_data = 0; > - nxdomain = 1; > - if (!dryrun) > - log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG > | F_NXDOMAIN, > -@@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - if (i == 4) > - { > - ans = 1; > -+ sec_data = 0; > - if (!dryrun) > - { > - addr.addr.addr4.s_addr = htonl(a); > -@@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - continue; > - #endif > - ans = 1; > -+ sec_data = 0; > - if (!dryrun) > - { > - gotit = 1; > -@@ -2032,48 +1917,8 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - crecp = save; > - } > - > -- /* If the client asked for DNSSEC and we can't > provide RRSIGs, either > -- because we've not doing DNSSEC or the cached > answer is signed by negative, > -- don't answer from the cache, forward instead. > */ > -- if (!(crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) && sec_reqd) > -- { > -- if (!option_bool(OPT_DNSSEC_VALID) || > ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))) > -- crecp = NULL; > --#ifdef HAVE_DNSSEC > -- else if (crecp->flags & F_DNSSECOK) > -- { > -- /* We're returning validated data, need > to return the RRSIG too. */ > -- struct crec *rr_crec = NULL; > -- int sigtype = type; > -- /* The signature may have expired even > though the data is still in cache, > -- forward instead of answering from > cache if so. */ > -- int gotsig = 0; > -- > -- if (crecp->flags & F_CNAME) > -- sigtype = T_CNAME; > -- > -- while ((rr_crec = > cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY))) > -- { > -- if (rr_crec->addr.sig.type_covered == > sigtype && rr_crec->uid == C_IN) > -- { > -- char *sigdata = > blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec- > >addr.sig.keylen, NULL); > -- gotsig = 1; > -- > -- if (!dryrun && > -- add_resource_record(header, > limit, &trunc, nameoffset, &ansp, > -- rr_crec- > >ttd - now, &nameoffset, > -- T_RRSIG, > C_IN, "t", rr_crec->addr.sig.keylen, sigdata)) > -- anscount++; > -- } > -- } > -- > -- if (!gotsig) > -- crecp = NULL; > -- } > --#endif > -- } > -- > -- if (crecp) > -+ /* If the client asked for DNSSEC don't use > cached data. */ > -+ if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) > - do > - { > - /* don't answer wildcard queries with data > not from /etc/hosts > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/018- > Move_code_which_caches_DS_records_to_a_more_logical_place.patch > b/src/patches/dnsmasq/018- > Move_code_which_caches_DS_records_to_a_more_logical_place.patch > deleted file mode 100644 > index ff055f7..0000000 > --- a/src/patches/dnsmasq/018- > Move_code_which_caches_DS_records_to_a_more_logical_place.patch > +++ /dev/null > @@ -1,269 +0,0 @@ > -From d64c81fff7faf4392b688223ef3a617c5c07e7dc Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 15 Dec 2015 16:11:06 +0000 > -Subject: [PATCH] Move code which caches DS records to a more logical > place. > - > ---- > - src/dnssec.c | 179 +++++++++++++++++++++++++++++---------------- > ------------- > - 1 file changed, 90 insertions(+), 89 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 1ae03a6..359231f 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1204,7 +1204,10 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - int dnssec_validate_ds(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int class) > - { > - unsigned char *p = (unsigned char *)(header+1); > -- int qtype, qclass, val, i, neganswer, nons; > -+ int qtype, qclass, rc, i, neganswer, nons; > -+ int aclass, atype, rdlen; > -+ unsigned long ttl; > -+ struct all_addr a; > - > - if (ntohs(header->qdcount) != 1 || > - !(p = skip_name(p, header, plen, 4))) > -@@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - GETSHORT(qclass, p); > - > - if (qtype != T_DS || qclass != class) > -- val = STAT_BOGUS; > -+ rc = STAT_BOGUS; > - else > -- val = dnssec_validate_reply(now, header, plen, name, keyname, > NULL, 0, &neganswer, &nons); > -+ rc = dnssec_validate_reply(now, header, plen, name, keyname, > NULL, 0, &neganswer, &nons); > - /* Note dnssec_validate_reply() will have cached positive answers > */ > - > -- if (val == STAT_INSECURE) > -- val = STAT_BOGUS; > -- > -+ if (rc == STAT_INSECURE) > -+ rc = STAT_BOGUS; > -+ > - p = (unsigned char *)(header+1); > - extract_name(header, plen, &p, name, 1, 4); > - p += 4; /* qtype, qclass */ > - > -- if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) > -- val = STAT_BOGUS; > -- > - /* If the key needed to validate the DS is on the same domain as > the DS, we'll > - loop getting nowhere. Stop that now. This can happen of the DS > answer comes > - from the DS's zone, and not the parent zone. */ > -- if (val == STAT_BOGUS || (val == STAT_NEED_KEY && > hostname_isequal(name, keyname))) > -+ if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && > hostname_isequal(name, keyname))) > - { > - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS"); > - return STAT_BOGUS; > - } > - > -- if (val != STAT_SECURE) > -- return val; > -- > -- /* By here, the answer is proved secure, and a positive answer > has been cached. */ > -- if (neganswer) > -+ if (rc != STAT_SECURE) > -+ return rc; > -+ > -+ if (!neganswer) > - { > -- int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK; > -- unsigned long ttl, minttl = ULONG_MAX; > -- struct all_addr a; > -+ cache_start_insert(); > -+ > -+ for (i = 0; i < ntohs(header->ancount); i++) > -+ { > -+ if (!(rc = extract_name(header, plen, &p, name, 0, 10))) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ GETSHORT(atype, p); > -+ GETSHORT(aclass, p); > -+ GETLONG(ttl, p); > -+ GETSHORT(rdlen, p); > -+ > -+ if (!CHECK_LEN(header, p, plen, rdlen)) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ if (aclass == class && atype == T_DS && rc == 1) > -+ { > -+ int algo, digest, keytag; > -+ unsigned char *psave = p; > -+ struct blockdata *key; > -+ struct crec *crecp; > - > -+ if (rdlen < 4) > -+ return STAT_BOGUS; /* bad packet */ > -+ > -+ GETSHORT(keytag, p); > -+ algo = *p++; > -+ digest = *p++; > -+ > -+ /* Cache needs to known class for DNSSEC stuff */ > -+ a.addr.dnssec.class = class; > -+ > -+ if ((key = blockdata_alloc((char*)p, rdlen - 4))) > -+ { > -+ if (!(crecp = cache_insert(name, &a, now, ttl, > F_FORWARD | F_DS | F_DNSSECOK))) > -+ { > -+ blockdata_free(key); > -+ return STAT_BOGUS; > -+ } > -+ else > -+ { > -+ a.addr.keytag = keytag; > -+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, > name, &a, "DS keytag %u"); > -+ crecp->addr.ds.digest = digest; > -+ crecp->addr.ds.keydata = key; > -+ crecp->addr.ds.algo = algo; > -+ crecp->addr.ds.keytag = keytag; > -+ crecp->addr.ds.keylen = rdlen - 4; > -+ } > -+ } > -+ > -+ p = psave; > -+ > -+ if (!ADD_RDLEN(header, p, plen, rdlen)) > -+ return STAT_BOGUS; /* bad packet */ > -+ } > -+ > -+ cache_end_insert(); > -+ } > -+ } > -+ else > -+ { > -+ int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK; > -+ unsigned long minttl = ULONG_MAX; > -+ > -+ if (!(p = skip_section(p, ntohs(header->ancount), header, > plen))) > -+ return STAT_BOGUS; > -+ > - if (RCODE(header) == NXDOMAIN) > - flags |= F_NXDOMAIN; > - > -@@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - if (!(p = skip_name(p, header, plen, 0))) > - return STAT_BOGUS; > - > -- GETSHORT(qtype, p); > -- GETSHORT(qclass, p); > -+ GETSHORT(atype, p); > -+ GETSHORT(aclass, p); > - GETLONG(ttl, p); > - GETSHORT(rdlen, p); > -- > -+ > - if (!CHECK_LEN(header, p, plen, rdlen)) > - return STAT_BOGUS; /* bad packet */ > -- > -- if (qclass != class || qtype != T_SOA) > -+ > -+ if (aclass != class || atype != T_SOA) > - { > - p += rdlen; > - continue; > - } > -- > -+ > - if (ttl < minttl) > - minttl = ttl; > - > -@@ -1306,7 +1369,7 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS"); > - } > - } > -- > -+ > - return STAT_OK; > - } > - > -@@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - /* Not done, validate now */ > - if (j == i) > - { > -- int ttl, keytag, algo, digest, sigcnt, rrcnt; > -- unsigned char *psave; > -- struct all_addr a; > -- struct blockdata *key; > -- struct crec *crecp; > -+ int sigcnt, rrcnt; > - char *wildname; > - > - if (!explore_rrset(header, plen, class1, type1, name, > keyname, &sigcnt, &rrcnt)) > -@@ -2032,6 +2091,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - Can't overwrite name here. */ > - strcpy(daemon->workspacename, keyname); > - rc = zone_status(daemon->workspacename, class1, > keyname, now); > -+ > - if (rc != STAT_SECURE) > - { > - /* Zone is insecure, don't need to validate RRset > */ > -@@ -2088,65 +2148,6 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - if (rc == STAT_BOGUS) > - return rc; > - } > -- > -- /* If we just validated a DS RRset, cache it */ > -- /* Also note if the RRset is the answer to the > question, or the target of a CNAME */ > -- cache_start_insert(); > -- > -- for (p2 = ans_start, j = 0; j < ntohs(header- > >ancount); j++) > -- { > -- if (!(rc = extract_name(header, plen, &p2, > name, 0, 10))) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(type2, p2); > -- GETSHORT(class2, p2); > -- GETLONG(ttl, p2); > -- GETSHORT(rdlen2, p2); > -- > -- if (!CHECK_LEN(header, p2, plen, rdlen2)) > -- return STAT_BOGUS; /* bad packet */ > -- > -- if (class2 == class1 && rc == 1) > -- { > -- psave = p2; > -- > -- if (type1 == T_DS && type2 == T_DS) > -- { > -- if (rdlen2 < 4) > -- return STAT_BOGUS; /* bad packet */ > -- > -- GETSHORT(keytag, p2); > -- algo = *p2++; > -- digest = *p2++; > -- > -- /* Cache needs to known class for > DNSSEC stuff */ > -- a.addr.dnssec.class = class2; > -- > -- if ((key = blockdata_alloc((char*)p2, > rdlen2 - 4))) > -- { > -- if (!(crecp = cache_insert(name, > &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))) > -- blockdata_free(key); > -- else > -- { > -- a.addr.keytag = keytag; > -- log_query(F_NOEXTRA | > F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u"); > -- crecp->addr.ds.digest = > digest; > -- crecp->addr.ds.keydata = key; > -- crecp->addr.ds.algo = algo; > -- crecp->addr.ds.keytag = > keytag; > -- crecp->addr.ds.keylen = > rdlen2 - 4; > -- } > -- } > -- } > -- > -- p2 = psave; > -- } > -- > -- if (!ADD_RDLEN(header, p2, plen, rdlen2)) > -- return STAT_BOGUS; /* bad packet */ > -- } > -- > -- cache_end_insert(); > - } > - } > - } > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/019-Generalise_RR- > filtering_code_for_use_with_EDNS0.patch b/src/patches/dnsmasq/019- > Generalise_RR-filtering_code_for_use_with_EDNS0.patch > deleted file mode 100644 > index 0a4942a..0000000 > --- a/src/patches/dnsmasq/019-Generalise_RR- > filtering_code_for_use_with_EDNS0.patch > +++ /dev/null > @@ -1,755 +0,0 @@ > -From c2bcd1e183bcc5fdd63811c045355fc57e36ecfd Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Tue, 15 Dec 2015 17:25:21 +0000 > -Subject: [PATCH] Generalise RR-filtering code, for use with EDNS0. > - > ---- > - Makefile | 3 +- > - bld/Android.mk | 2 +- > - src/dnsmasq.h | 5 + > - src/dnssec.c | 307 +------------------------------------------ > ------- > - src/forward.c | 2 +- > - src/rrfilter.c | 339 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > - 6 files changed, 349 insertions(+), 309 deletions(-) > - create mode 100644 src/rrfilter.c > - > -diff --git a/Makefile b/Makefile > -index 4c87ea9..b664160 100644 > ---- a/Makefile > -+++ b/Makefile > -@@ -73,7 +73,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o > network.o \ > - dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ > - helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ > - dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ > -- domain.o dnssec.o blockdata.o tables.o loop.o inotify.o > poll.o > -+ domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \ > -+ poll.o rrfilter.o > - > - hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ > - dns-protocol.h radv-protocol.h ip6addr.h > -diff --git a/bld/Android.mk b/bld/Android.mk > -index 5364ee7..67b9c4b 100644 > ---- a/bld/Android.mk > -+++ b/bld/Android.mk > -@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c > dnsmasq.c \ > - dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ > - radv.c slaac.c auth.c ipset.c domain.c \ > - dnssec.c dnssec-openssl.c blockdata.c tables.c > \ > -- loop.c inotify.c poll.c > -+ loop.c inotify.c poll.c rrfilter.c > - > - LOCAL_MODULE := dnsmasq > - > -diff --git a/src/dnsmasq.h b/src/dnsmasq.h > -index 4344cae..39a930c 100644 > ---- a/src/dnsmasq.h > -+++ b/src/dnsmasq.h > -@@ -1513,3 +1513,8 @@ int poll_check(int fd, short event); > - void poll_listen(int fd, short event); > - int do_poll(int timeout); > - > -+/* rrfilter.c */ > -+size_t rrfilter(struct dns_header *header, size_t plen, int mode); > -+u16 *rrfilter_desc(int type); > -+int expand_workspace(unsigned char ***wkspc, int *szp, int new); > -+ > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 359231f..fa3eb81 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -507,50 +507,6 @@ static int check_date_range(unsigned long > date_start, unsigned long date_end) > - && serial_compare_32(curtime, date_end) == SERIAL_LT; > - } > - > --static u16 *get_desc(int type) > --{ > -- /* List of RRtypes which include domains in the data. > -- 0 -> domain > -- integer -> no of plain bytes > -- -1 -> end > -- > -- zero is not a valid RRtype, so the final entry is returned for > -- anything which needs no mangling. > -- */ > -- > -- static u16 rr_desc[] = > -- { > -- T_NS, 0, -1, > -- T_MD, 0, -1, > -- T_MF, 0, -1, > -- T_CNAME, 0, -1, > -- T_SOA, 0, 0, -1, > -- T_MB, 0, -1, > -- T_MG, 0, -1, > -- T_MR, 0, -1, > -- T_PTR, 0, -1, > -- T_MINFO, 0, 0, -1, > -- T_MX, 2, 0, -1, > -- T_RP, 0, 0, -1, > -- T_AFSDB, 2, 0, -1, > -- T_RT, 2, 0, -1, > -- T_SIG, 18, 0, -1, > -- T_PX, 2, 0, 0, -1, > -- T_NXT, 0, -1, > -- T_KX, 2, 0, -1, > -- T_SRV, 6, 0, -1, > -- T_DNAME, 0, -1, > -- 0, -1 /* wildcard/catchall */ > -- }; > -- > -- u16 *p = rr_desc; > -- > -- while (*p != type && *p != 0) > -- while (*p++ != (u16)-1); > -- > -- return p+1; > --} > -- > - /* Return bytes of canonicalised rdata, when the return value is > zero, the remaining > - data, pointed to by *p, should be used raw. */ > - static int get_rdata(struct dns_header *header, size_t plen, > unsigned char *end, char *buff, int bufflen, > -@@ -594,34 +550,6 @@ static int get_rdata(struct dns_header *header, > size_t plen, unsigned char *end, > - } > - } > - > --static int expand_workspace(unsigned char ***wkspc, int *szp, int > new) > --{ > -- unsigned char **p; > -- int old = *szp; > -- > -- if (old >= new+1) > -- return 1; > -- > -- if (new >= 100) > -- return 0; > -- > -- new += 5; > -- > -- if (!(p = whine_malloc(new * sizeof(unsigned char **)))) > -- return 0; > -- > -- if (old != 0 && *wkspc) > -- { > -- memcpy(p, *wkspc, old * sizeof(unsigned char **)); > -- free(*wkspc); > -- } > -- > -- *wkspc = p; > -- *szp = new; > -- > -- return 1; > --} > -- > - /* Bubble sort the RRset into the canonical order. > - Note that the byte-streams from two RRs may get unsynced: > consider > - RRs which have two domain-names at the start and then other > data. > -@@ -849,7 +777,7 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - int rdlen, j, name_labels; > - struct crec *crecp = NULL; > - int algo, labels, orig_ttl, key_tag; > -- u16 *rr_desc = get_desc(type); > -+ u16 *rr_desc = rrfilter_desc(type); > - > - if (wildcard_out) > - *wildcard_out = NULL; > -@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct > dns_header *header, char *end, char *name, i > - return ret; > - } > - > --/* Go through a domain name, find "pointers" and fix them up based > on how many bytes > -- we've chopped out of the packet, or check they don't point into > an elided part. */ > --static int check_name(unsigned char **namep, struct dns_header > *header, size_t plen, int fixup, unsigned char **rrs, int rr_count) > --{ > -- unsigned char *ansp = *namep; > -- > -- while(1) > -- { > -- unsigned int label_type; > -- > -- if (!CHECK_LEN(header, ansp, plen, 1)) > -- return 0; > -- > -- label_type = (*ansp) & 0xc0; > -- > -- if (label_type == 0xc0) > -- { > -- /* pointer for compression. */ > -- unsigned int offset; > -- int i; > -- unsigned char *p; > -- > -- if (!CHECK_LEN(header, ansp, plen, 2)) > -- return 0; > -- > -- offset = ((*ansp++) & 0x3f) << 8; > -- offset |= *ansp++; > -- > -- p = offset + (unsigned char *)header; > -- > -- for (i = 0; i < rr_count; i++) > -- if (p < rrs[i]) > -- break; > -- else > -- if (i & 1) > -- offset -= rrs[i] - rrs[i-1]; > -- > -- /* does the pointer end up in an elided RR? */ > -- if (i & 1) > -- return 0; > -- > -- /* No, scale the pointer */ > -- if (fixup) > -- { > -- ansp -= 2; > -- *ansp++ = (offset >> 8) | 0xc0; > -- *ansp++ = offset & 0xff; > -- } > -- break; > -- } > -- else if (label_type == 0x80) > -- return 0; /* reserved */ > -- else if (label_type == 0x40) > -- { > -- /* Extended label type */ > -- unsigned int count; > -- > -- if (!CHECK_LEN(header, ansp, plen, 2)) > -- return 0; > -- > -- if (((*ansp++) & 0x3f) != 1) > -- return 0; /* we only understand bitstrings */ > -- > -- count = *(ansp++); /* Bits in bitstring */ > -- > -- if (count == 0) /* count == 0 means 256 bits */ > -- ansp += 32; > -- else > -- ansp += ((count-1)>>3)+1; > -- } > -- else > -- { /* label type == 0 Bottom six bits is length */ > -- unsigned int len = (*ansp++) & 0x3f; > -- > -- if (!ADD_RDLEN(header, ansp, plen, len)) > -- return 0; > -- > -- if (len == 0) > -- break; /* zero length label marks the end. */ > -- } > -- } > -- > -- *namep = ansp; > -- > -- return 1; > --} > -- > --/* Go through RRs and check or fixup the domain names contained > within */ > --static int check_rrs(unsigned char *p, struct dns_header *header, > size_t plen, int fixup, unsigned char **rrs, int rr_count) > --{ > -- int i, type, class, rdlen; > -- unsigned char *pp; > -- > -- for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + > ntohs(header->arcount); i++) > -- { > -- pp = p; > -- > -- if (!(p = skip_name(p, header, plen, 10))) > -- return 0; > -- > -- GETSHORT(type, p); > -- GETSHORT(class, p); > -- p += 4; /* TTL */ > -- GETSHORT(rdlen, p); > -- > -- if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG) > -- { > -- /* fixup name of RR */ > -- if (!check_name(&pp, header, plen, fixup, rrs, rr_count)) > -- return 0; > -- > -- if (class == C_IN) > -- { > -- u16 *d; > -- > -- for (pp = p, d = get_desc(type); *d != (u16)-1; d++) > -- { > -- if (*d != 0) > -- pp += *d; > -- else if (!check_name(&pp, header, plen, fixup, > rrs, rr_count)) > -- return 0; > -- } > -- } > -- } > -- > -- if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return 0; > -- } > -- > -- return 1; > --} > -- > -- > --size_t filter_rrsigs(struct dns_header *header, size_t plen) > --{ > -- static unsigned char **rrs; > -- static int rr_sz = 0; > -- > -- unsigned char *p = (unsigned char *)(header+1); > -- int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar; > -- > -- if (ntohs(header->qdcount) != 1 || > -- !(p = skip_name(p, header, plen, 4))) > -- return plen; > -- > -- GETSHORT(qtype, p); > -- GETSHORT(qclass, p); > -- > -- /* First pass, find pointers to start and end of all the records > we wish to elide: > -- records added for DNSSEC, unless explicity queried for */ > -- for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; > -- i < ntohs(header->ancount) + ntohs(header->nscount) + > ntohs(header->arcount); > -- i++) > -- { > -- unsigned char *pstart = p; > -- int type, class; > -- > -- if (!(p = skip_name(p, header, plen, 10))) > -- return plen; > -- > -- GETSHORT(type, p); > -- GETSHORT(class, p); > -- p += 4; /* TTL */ > -- GETSHORT(rdlen, p); > -- > -- if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) > && > -- (type != qtype || class != qclass)) > -- { > -- if (!expand_workspace(&rrs, &rr_sz, rr_found + 1)) > -- return plen; > -- > -- rrs[rr_found++] = pstart; > -- > -- if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return plen; > -- > -- rrs[rr_found++] = p; > -- > -- if (i < ntohs(header->ancount)) > -- chop_an++; > -- else if (i < (ntohs(header->nscount) + ntohs(header- > >ancount))) > -- chop_ns++; > -- else > -- chop_ar++; > -- } > -- else if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return plen; > -- } > -- > -- /* Nothing to do. */ > -- if (rr_found == 0) > -- return plen; > -- > -- /* Second pass, look for pointers in names in the records we're > keeping and make sure they don't > -- point to records we're going to elide. This is theoretically > possible, but unlikely. If > -- it happens, we give up and leave the answer unchanged. */ > -- p = (unsigned char *)(header+1); > -- > -- /* question first */ > -- if (!check_name(&p, header, plen, 0, rrs, rr_found)) > -- return plen; > -- p += 4; /* qclass, qtype */ > -- > -- /* Now answers and NS */ > -- if (!check_rrs(p, header, plen, 0, rrs, rr_found)) > -- return plen; > -- > -- /* Third pass, elide records */ > -- for (p = rrs[0], i = 1; i < rr_found; i += 2) > -- { > -- unsigned char *start = rrs[i]; > -- unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : > ((unsigned char *)(header+1)) + plen; > -- > -- memmove(p, start, end-start); > -- p += end-start; > -- } > -- > -- plen = p - (unsigned char *)header; > -- header->ancount = htons(ntohs(header->ancount) - chop_an); > -- header->nscount = htons(ntohs(header->nscount) - chop_ns); > -- header->arcount = htons(ntohs(header->arcount) - chop_ar); > -- > -- /* Fourth pass, fix up pointers in the remaining records */ > -- p = (unsigned char *)(header+1); > -- > -- check_name(&p, header, plen, 1, rrs, rr_found); > -- p += 4; /* qclass, qtype */ > -- > -- check_rrs(p, header, plen, 1, rrs, rr_found); > -- > -- return plen; > --} > -- > - unsigned char* hash_questions(struct dns_header *header, size_t > plen, char *name) > - { > - int q; > -diff --git a/src/forward.c b/src/forward.c > -index dd22a62..3e801c8 100644 > ---- a/src/forward.c > -+++ b/src/forward.c > -@@ -662,7 +662,7 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > - > - /* If the requestor didn't set the DO bit, don't return DNSSEC > info. */ > - if (!do_bit) > -- n = filter_rrsigs(header, n); > -+ n = rrfilter(header, n, 1); > - #endif > - > - /* do this after extract_addresses. Ensure NODATA reply and > remove > -diff --git a/src/rrfilter.c b/src/rrfilter.c > -new file mode 100644 > -index 0000000..ae12261 > ---- /dev/null > -+++ b/src/rrfilter.c > -@@ -0,0 +1,339 @@ > -+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley > -+ > -+ This program is free software; you can redistribute it and/or > modify > -+ it under the terms of the GNU General Public License as > published by > -+ the Free Software Foundation; version 2 dated June, 1991, or > -+ (at your option) version 3 dated 29 June, 2007. > -+ > -+ This program is distributed in the hope that it will be useful, > -+ but WITHOUT ANY WARRANTY; without even the implied warranty of > -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > -+ GNU General Public License for more details. > -+ > -+ You should have received a copy of the GNU General Public > License > -+ along with this program. If not, see <http://www.gnu.org/licens > es/>. > -+*/ > -+ > -+/* Code to safely remove RRs from an DNS answer */ > -+ > -+#include "dnsmasq.h" > -+ > -+/* Go through a domain name, find "pointers" and fix them up based > on how many bytes > -+ we've chopped out of the packet, or check they don't point into > an elided part. */ > -+static int check_name(unsigned char **namep, struct dns_header > *header, size_t plen, int fixup, unsigned char **rrs, int rr_count) > -+{ > -+ unsigned char *ansp = *namep; > -+ > -+ while(1) > -+ { > -+ unsigned int label_type; > -+ > -+ if (!CHECK_LEN(header, ansp, plen, 1)) > -+ return 0; > -+ > -+ label_type = (*ansp) & 0xc0; > -+ > -+ if (label_type == 0xc0) > -+ { > -+ /* pointer for compression. */ > -+ unsigned int offset; > -+ int i; > -+ unsigned char *p; > -+ > -+ if (!CHECK_LEN(header, ansp, plen, 2)) > -+ return 0; > -+ > -+ offset = ((*ansp++) & 0x3f) << 8; > -+ offset |= *ansp++; > -+ > -+ p = offset + (unsigned char *)header; > -+ > -+ for (i = 0; i < rr_count; i++) > -+ if (p < rrs[i]) > -+ break; > -+ else > -+ if (i & 1) > -+ offset -= rrs[i] - rrs[i-1]; > -+ > -+ /* does the pointer end up in an elided RR? */ > -+ if (i & 1) > -+ return 0; > -+ > -+ /* No, scale the pointer */ > -+ if (fixup) > -+ { > -+ ansp -= 2; > -+ *ansp++ = (offset >> 8) | 0xc0; > -+ *ansp++ = offset & 0xff; > -+ } > -+ break; > -+ } > -+ else if (label_type == 0x80) > -+ return 0; /* reserved */ > -+ else if (label_type == 0x40) > -+ { > -+ /* Extended label type */ > -+ unsigned int count; > -+ > -+ if (!CHECK_LEN(header, ansp, plen, 2)) > -+ return 0; > -+ > -+ if (((*ansp++) & 0x3f) != 1) > -+ return 0; /* we only understand bitstrings */ > -+ > -+ count = *(ansp++); /* Bits in bitstring */ > -+ > -+ if (count == 0) /* count == 0 means 256 bits */ > -+ ansp += 32; > -+ else > -+ ansp += ((count-1)>>3)+1; > -+ } > -+ else > -+ { /* label type == 0 Bottom six bits is length */ > -+ unsigned int len = (*ansp++) & 0x3f; > -+ > -+ if (!ADD_RDLEN(header, ansp, plen, len)) > -+ return 0; > -+ > -+ if (len == 0) > -+ break; /* zero length label marks the end. */ > -+ } > -+ } > -+ > -+ *namep = ansp; > -+ > -+ return 1; > -+} > -+ > -+/* Go through RRs and check or fixup the domain names contained > within */ > -+static int check_rrs(unsigned char *p, struct dns_header *header, > size_t plen, int fixup, unsigned char **rrs, int rr_count) > -+{ > -+ int i, j, type, class, rdlen; > -+ unsigned char *pp; > -+ > -+ for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + > ntohs(header->arcount); i++) > -+ { > -+ pp = p; > -+ > -+ if (!(p = skip_name(p, header, plen, 10))) > -+ return 0; > -+ > -+ GETSHORT(type, p); > -+ GETSHORT(class, p); > -+ p += 4; /* TTL */ > -+ GETSHORT(rdlen, p); > -+ > -+ /* If this RR is to be elided, don't fix up its contents */ > -+ for (j = 0; j < rr_count; j += 2) > -+ if (rrs[j] == pp) > -+ break; > -+ > -+ if (j >= rr_count) > -+ { > -+ /* fixup name of RR */ > -+ if (!check_name(&pp, header, plen, fixup, rrs, rr_count)) > -+ return 0; > -+ > -+ if (class == C_IN) > -+ { > -+ u16 *d; > -+ > -+ for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; > d++) > -+ { > -+ if (*d != 0) > -+ pp += *d; > -+ else if (!check_name(&pp, header, plen, fixup, > rrs, rr_count)) > -+ return 0; > -+ } > -+ } > -+ } > -+ > -+ if (!ADD_RDLEN(header, p, plen, rdlen)) > -+ return 0; > -+ } > -+ > -+ return 1; > -+} > -+ > -+ > -+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */ > -+size_t rrfilter(struct dns_header *header, size_t plen, int mode) > -+{ > -+ static unsigned char **rrs; > -+ static int rr_sz = 0; > -+ > -+ unsigned char *p = (unsigned char *)(header+1); > -+ int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar; > -+ > -+ if (ntohs(header->qdcount) != 1 || > -+ !(p = skip_name(p, header, plen, 4))) > -+ return plen; > -+ > -+ GETSHORT(qtype, p); > -+ GETSHORT(qclass, p); > -+ > -+ /* First pass, find pointers to start and end of all the records > we wish to elide: > -+ records added for DNSSEC, unless explicity queried for */ > -+ for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; > -+ i < ntohs(header->ancount) + ntohs(header->nscount) + > ntohs(header->arcount); > -+ i++) > -+ { > -+ unsigned char *pstart = p; > -+ int type, class; > -+ > -+ if (!(p = skip_name(p, header, plen, 10))) > -+ return plen; > -+ > -+ GETSHORT(type, p); > -+ GETSHORT(class, p); > -+ p += 4; /* TTL */ > -+ GETSHORT(rdlen, p); > -+ > -+ if (!ADD_RDLEN(header, p, plen, rdlen)) > -+ return plen; > -+ > -+ /* Don't remove the answer. */ > -+ if (i < ntohs(header->ancount) && type == qtype && class == > qclass) > -+ continue; > -+ > -+ if (mode == 0) /* EDNS */ > -+ { > -+ /* EDNS mode, remove T_OPT from additional section only > */ > -+ if (i < (ntohs(header->nscount) + ntohs(header->ancount)) > || type != T_OPT) > -+ continue; > -+ } > -+ else if (type != T_NSEC && type != T_NSEC3 && type != > T_RRSIG) > -+ /* DNSSEC mode, remove SIGs and NSECs from all three > sections. */ > -+ continue; > -+ > -+ > -+ if (!expand_workspace(&rrs, &rr_sz, rr_found + 1)) > -+ return plen; > -+ > -+ rrs[rr_found++] = pstart; > -+ rrs[rr_found++] = p; > -+ > -+ if (i < ntohs(header->ancount)) > -+ chop_an++; > -+ else if (i < (ntohs(header->nscount) + ntohs(header- > >ancount))) > -+ chop_ns++; > -+ else > -+ chop_ar++; > -+ } > -+ > -+ /* Nothing to do. */ > -+ if (rr_found == 0) > -+ return plen; > -+ > -+ /* Second pass, look for pointers in names in the records we're > keeping and make sure they don't > -+ point to records we're going to elide. This is theoretically > possible, but unlikely. If > -+ it happens, we give up and leave the answer unchanged. */ > -+ p = (unsigned char *)(header+1); > -+ > -+ /* question first */ > -+ if (!check_name(&p, header, plen, 0, rrs, rr_found)) > -+ return plen; > -+ p += 4; /* qclass, qtype */ > -+ > -+ /* Now answers and NS */ > -+ if (!check_rrs(p, header, plen, 0, rrs, rr_found)) > -+ return plen; > -+ > -+ /* Third pass, elide records */ > -+ for (p = rrs[0], i = 1; i < rr_found; i += 2) > -+ { > -+ unsigned char *start = rrs[i]; > -+ unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : > ((unsigned char *)(header+1)) + plen; > -+ > -+ memmove(p, start, end-start); > -+ p += end-start; > -+ } > -+ > -+ plen = p - (unsigned char *)header; > -+ header->ancount = htons(ntohs(header->ancount) - chop_an); > -+ header->nscount = htons(ntohs(header->nscount) - chop_ns); > -+ header->arcount = htons(ntohs(header->arcount) - chop_ar); > -+ > -+ /* Fourth pass, fix up pointers in the remaining records */ > -+ p = (unsigned char *)(header+1); > -+ > -+ check_name(&p, header, plen, 1, rrs, rr_found); > -+ p += 4; /* qclass, qtype */ > -+ > -+ check_rrs(p, header, plen, 1, rrs, rr_found); > -+ > -+ return plen; > -+} > -+ > -+/* This is used in the DNSSEC code too, hence it's exported */ > -+u16 *rrfilter_desc(int type) > -+{ > -+ /* List of RRtypes which include domains in the data. > -+ 0 -> domain > -+ integer -> no of plain bytes > -+ -1 -> end > -+ > -+ zero is not a valid RRtype, so the final entry is returned for > -+ anything which needs no mangling. > -+ */ > -+ > -+ static u16 rr_desc[] = > -+ { > -+ T_NS, 0, -1, > -+ T_MD, 0, -1, > -+ T_MF, 0, -1, > -+ T_CNAME, 0, -1, > -+ T_SOA, 0, 0, -1, > -+ T_MB, 0, -1, > -+ T_MG, 0, -1, > -+ T_MR, 0, -1, > -+ T_PTR, 0, -1, > -+ T_MINFO, 0, 0, -1, > -+ T_MX, 2, 0, -1, > -+ T_RP, 0, 0, -1, > -+ T_AFSDB, 2, 0, -1, > -+ T_RT, 2, 0, -1, > -+ T_SIG, 18, 0, -1, > -+ T_PX, 2, 0, 0, -1, > -+ T_NXT, 0, -1, > -+ T_KX, 2, 0, -1, > -+ T_SRV, 6, 0, -1, > -+ T_DNAME, 0, -1, > -+ 0, -1 /* wildcard/catchall */ > -+ }; > -+ > -+ u16 *p = rr_desc; > -+ > -+ while (*p != type && *p != 0) > -+ while (*p++ != (u16)-1); > -+ > -+ return p+1; > -+} > -+ > -+int expand_workspace(unsigned char ***wkspc, int *szp, int new) > -+{ > -+ unsigned char **p; > -+ int old = *szp; > -+ > -+ if (old >= new+1) > -+ return 1; > -+ > -+ if (new >= 100) > -+ return 0; > -+ > -+ new += 5; > -+ > -+ if (!(p = whine_malloc(new * sizeof(unsigned char **)))) > -+ return 0; > -+ > -+ if (old != 0 && *wkspc) > -+ { > -+ memcpy(p, *wkspc, old * sizeof(unsigned char **)); > -+ free(*wkspc); > -+ } > -+ > -+ *wkspc = p; > -+ *szp = new; > -+ > -+ return 1; > -+} > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch > b/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch > deleted file mode 100644 > index ffb412b..0000000 > --- a/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch > +++ /dev/null > @@ -1,134 +0,0 @@ > -From 2dbba34b2c1289a108f876c78b84889f2a93115d Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Wed, 16 Dec 2015 13:41:58 +0000 > -Subject: [PATCH] DNSSEC validation tweak. > - > -A zone which has at least one key with an algorithm we don't > -support should be considered as insecure. > ---- > - src/dnssec.c | 82 ++++++++++++++++++++++++++++++++++++++--------- > ----------- > - 1 file changed, 54 insertions(+), 28 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index fa3eb81..dc563e0 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -763,10 +763,10 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > - STAT_NEED_KEY need DNSKEY to complete validation (name is > returned in keyname) > - STAT_NEED_DS need DS to complete validation (name is returned > in keyname) > - > -- if key is non-NULL, use that key, which has the algo and tag > given in the params of those names, > -+ If key is non-NULL, use that key, which has the algo and tag > given in the params of those names, > - otherwise find the key in the cache. > - > -- name is unchanged on exit. keyname is used as workspace and > trashed. > -+ Name is unchanged on exit. keyname is used as workspace and > trashed. > - > - Call explore_rrset first to find and count RRs and sigs. > - */ > -@@ -919,6 +919,7 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - return STAT_BOGUS; > - } > - > -+ > - /* The DNS packet is expected to contain the answer to a DNSKEY > query. > - Put all DNSKEYs in the answer which are valid into the cache. > - return codes: > -@@ -1831,15 +1832,15 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - > - /* Check signing status of name. > - returns: > -- STAT_SECURE zone is signed. > -- STAT_INSECURE zone proved unsigned. > -- STAT_NEED_DS require DS record of name returned in keyname. > -- > -+ STAT_SECURE zone is signed. > -+ STAT_INSECURE zone proved unsigned. > -+ STAT_NEED_DS require DS record of name returned in keyname. > -+ STAT_NEED_DNSKEY require DNSKEY record of name returned in > keyname. > - name returned unaltered. > - */ > - static int zone_status(char *name, int class, char *keyname, time_t > now) > - { > -- int name_start = strlen(name); > -+ int secure_ds, name_start = strlen(name); > - struct crec *crecp; > - char *p; > - > -@@ -1850,27 +1851,52 @@ static int zone_status(char *name, int > class, char *keyname, time_t now) > - if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS))) > - return STAT_NEED_DS; > - else > -- do > -- { > -- if (crecp->uid == (unsigned int)class) > -- { > -- /* F_DNSSECOK misused in DS cache records to non- > existance of NS record. > -- F_NEG && !F_DNSSECOK implies that we've proved > there's no DS record here, > -- but that's because there's no NS record either, > ie this isn't the start > -- of a zone. We only prove that the DNS tree below > a node is unsigned when > -- we prove that we're at a zone cut AND there's no > DS record. > -- */ > -- if (crecp->flags & F_NEG) > -- { > -- if (crecp->flags & F_DNSSECOK) > -- return STAT_INSECURE; /* proved no DS here */ > -- } > -- else if (!ds_digest_name(crecp->addr.ds.digest) || > !algo_digest_name(crecp->addr.ds.algo)) > -- return STAT_INSECURE; /* algo we can't use - > insecure */ > -- } > -- } > -- while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DS))); > -- > -+ { > -+ secure_ds = 0; > -+ > -+ do > -+ { > -+ if (crecp->uid == (unsigned int)class) > -+ { > -+ /* F_DNSSECOK misused in DS cache records to non- > existance of NS record. > -+ F_NEG && !F_DNSSECOK implies that we've proved > there's no DS record here, > -+ but that's because there's no NS record > either, ie this isn't the start > -+ of a zone. We only prove that the DNS tree > below a node is unsigned when > -+ we prove that we're at a zone cut AND there's > no DS record. > -+ */ > -+ if (crecp->flags & F_NEG) > -+ { > -+ if (crecp->flags & F_DNSSECOK) > -+ return STAT_INSECURE; /* proved no DS here > */ > -+ } > -+ else if (!ds_digest_name(crecp->addr.ds.digest) > || !algo_digest_name(crecp->addr.ds.algo)) > -+ return STAT_INSECURE; /* algo we can't use - > insecure */ > -+ else > -+ secure_ds = 1; > -+ } > -+ } > -+ while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DS))); > -+ } > -+ > -+ if (secure_ds) > -+ { > -+ /* We've found only DS records that attest to the DNSKEY > RRset in the zone, so we believe > -+ that RRset is good. Furthermore the DNSKEY whose hash > is proved by the DS record is > -+ one we can use. However the DNSKEY RRset may contain > more than one key and > -+ one of the other keys may use an algorithm we don't > support. If that's > -+ the case the zone is insecure for us. */ > -+ > -+ if (!(crecp = cache_find_by_name(NULL, keyname, now, > F_DNSKEY))) > -+ return STAT_NEED_KEY; > -+ > -+ do > -+ { > -+ if (crecp->uid == (unsigned int)class && > !algo_digest_name(crecp->addr.key.algo)) > -+ return STAT_INSECURE; > -+ } > -+ while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DNSKEY))); > -+ } > -+ > - if (name_start == 0) > - break; > - > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/021- > Tweaks_to_EDNS0_handling_in_DNS_replies.patch > b/src/patches/dnsmasq/021- > Tweaks_to_EDNS0_handling_in_DNS_replies.patch > deleted file mode 100644 > index c3c74cc..0000000 > --- a/src/patches/dnsmasq/021- > Tweaks_to_EDNS0_handling_in_DNS_replies.patch > +++ /dev/null > @@ -1,133 +0,0 @@ > -From dd4ad9ac7ea6d51dcc34a1f2cd2da14efbb87714 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Thu, 17 Dec 2015 10:44:58 +0000 > -Subject: [PATCH] Tweaks to EDNS0 handling in DNS replies. > - > ---- > - src/dnssec.c | 20 +++++++++----------- > - src/rfc1035.c | 57 +++++++++++++++++++++++++++++++++------------- > ----------- > - 2 files changed, 42 insertions(+), 35 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index dc563e0..012b2a6 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -2129,18 +2129,16 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - /* Empty DS without NSECS */ > - if (qtype == T_DS) > - return STAT_BOGUS; > -- else > -+ > -+ rc = zone_status(name, qclass, keyname, now); > -+ if (rc != STAT_SECURE) > - { > -- rc = zone_status(name, qclass, keyname, now); > -- if (rc != STAT_SECURE) > -- { > -- if (class) > -- *class = qclass; /* Class for NEED_DS or > NEED_DNSKEY */ > -- return rc; > -- } > -- > -- return STAT_BOGUS; /* signed zone, no NSECs */ > -- } > -+ if (class) > -+ *class = qclass; /* Class for NEED_DS or > NEED_DNSKEY */ > -+ return rc; > -+ } > -+ > -+ return STAT_BOGUS; /* signed zone, no NSECs */ > - } > - > - if (nsec_type == T_NSEC) > -diff --git a/src/rfc1035.c b/src/rfc1035.c > -index def8fa0..188d05f 100644 > ---- a/src/rfc1035.c > -+++ b/src/rfc1035.c > -@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; > - struct mx_srv_record *rec; > - size_t len; > -- > -+ > -+ if (ntohs(header->ancount) != 0 || > -+ ntohs(header->nscount) != 0 || > -+ ntohs(header->qdcount) == 0 || > -+ OPCODE(header) != QUERY ) > -+ return 0; > -+ > - /* Don't return AD set if checking disabled. */ > - if (header->hb4 & HB4_CD) > - sec_data = 0; > -@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - *ad_reqd = header->hb4 & HB4_AD; > - *do_bit = 0; > - > -- /* If there is an RFC2671 pseudoheader then it will be > overwritten by > -+ /* If there is an additional data section then it will be > overwritten by > - partial replies, so we have to do a dry run to see if we can > answer > -- the query. We check to see if the do bit is set, if so we > always > -- forward rather than answering from the cache, which doesn't > include > -- security information, unless we're in DNSSEC validation mode. > */ > -+ the query. */ > - > -- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) > -- { > -- unsigned short flags; > -- > -- have_pseudoheader = 1; > -+ if (ntohs(header->arcount) != 0) > -+ { > -+ dryrun = 1; > - > -- pheader += 4; /* udp size, ext_rcode */ > -- GETSHORT(flags, pheader); > -- > -- if ((sec_reqd = flags & 0x8000)) > -- { > -- *do_bit = 1;/* do bit */ > -- *ad_reqd = 1; > -+ /* If there's an additional section, there might be an > EDNS(0) pseudoheader */ > -+ if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) > -+ { > -+ unsigned short flags; > -+ > -+ have_pseudoheader = 1; > -+ > -+ pheader += 4; /* udp size, ext_rcode */ > -+ GETSHORT(flags, pheader); > -+ > -+ if ((sec_reqd = flags & 0x8000)) > -+ { > -+ *do_bit = 1;/* do bit */ > -+ *ad_reqd = 1; > -+ } > - } > -- > -- dryrun = 1; > - } > - > -- if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) > -- return 0; > -- > - for (rec = daemon->mxnames; rec; rec = rec->next) > - rec->offset = 0; > - > -@@ -1730,8 +1735,12 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - } > - else if ((crecp = cache_find_by_addr(NULL, &addr, > now, is_arpa))) > - { > -- /* Don't use cache when DNSSEC data required. */ > -- if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) > -+ /* Don't use cache when DNSSEC data required, > unless we know that > -+ the zone is unsigned, which implies that we're > doing > -+ validation. */ > -+ if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || > -+ !sec_reqd || > -+ (option_bool(OPT_DNSSEC_VALID) && !(crecp- > >flags & F_DNSSECOK))) > - { > - do > - { > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non- > existence_code_Check_zone_status_is_NSEC_proof_bad.patch > b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non- > existence_code_Check_zone_status_is_NSEC_proof_bad.patch > deleted file mode 100644 > index 60503e9..0000000 > --- a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non- > existence_code_Check_zone_status_is_NSEC_proof_bad.patch > +++ /dev/null > @@ -1,409 +0,0 @@ > -From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Thu, 17 Dec 2015 11:57:26 +0000 > -Subject: [PATCH] Tidy up DNSSEC non-existence code. Check zone > status is NSEC > - proof bad. > - > ---- > - src/dnssec.c | 207 +++++++++++++++++++++++++-------------------- > ------------- > - 1 file changed, 90 insertions(+), 117 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 012b2a6..ddae497 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1367,59 +1367,6 @@ static int hostname_cmp(const char *a, const > char *b) > - } > - } > - > --/* Find all the NSEC or NSEC3 records in a reply. > -- return an array of pointers to them. */ > --static int find_nsec_records(struct dns_header *header, size_t > plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd) > --{ > -- static unsigned char **nsecset = NULL; > -- static int nsecset_sz = 0; > -- > -- int type_found = 0; > -- unsigned char *p = skip_questions(header, plen); > -- int type, class, rdlen, i, nsecs_found; > -- > -- /* Move to NS section */ > -- if (!p || !(p = skip_section(p, ntohs(header->ancount), header, > plen))) > -- return 0; > -- > -- for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--) > -- { > -- unsigned char *pstart = p; > -- > -- if (!(p = skip_name(p, header, plen, 10))) > -- return 0; > -- > -- GETSHORT(type, p); > -- GETSHORT(class, p); > -- p += 4; /* TTL */ > -- GETSHORT(rdlen, p); > -- > -- if (class == class_reqd && (type == T_NSEC || type == > T_NSEC3)) > -- { > -- /* No mixed NSECing 'round here, thankyouverymuch */ > -- if (type_found == T_NSEC && type == T_NSEC3) > -- return 0; > -- if (type_found == T_NSEC3 && type == T_NSEC) > -- return 0; > -- > -- type_found = type; > -- > -- if (!expand_workspace(&nsecset, &nsecset_sz, > nsecs_found)) > -- return 0; > -- > -- nsecset[nsecs_found++] = pstart; > -- } > -- > -- if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return 0; > -- } > -- > -- *nsecsetp = nsecset; > -- *nsecsetl = nsecs_found; > -- > -- return type_found; > --} > -- > - static int prove_non_existence_nsec(struct dns_header *header, > size_t plen, unsigned char **nsecs, int nsec_count, > - char *workspace1, char > *workspace2, char *name, int type, int *nons) > - { > -@@ -1436,12 +1383,12 @@ static int prove_non_existence_nsec(struct > dns_header *header, size_t plen, unsi > - { > - p = nsecs[i]; > - if (!extract_name(header, plen, &p, workspace1, 1, 10)) > -- return STAT_BOGUS; > -+ return 0; > - p += 8; /* class, type, TTL */ > - GETSHORT(rdlen, p); > - psave = p; > - if (!extract_name(header, plen, &p, workspace2, 1, 10)) > -- return STAT_BOGUS; > -+ return 0; > - > - rc = hostname_cmp(workspace1, name); > - > -@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct > dns_header *header, size_t plen, unsi > - { > - /* 4035 para 5.4. Last sentence */ > - if (type == T_NSEC || type == T_RRSIG) > -- return STAT_SECURE; > -+ return 1; > - > - /* NSEC with the same name as the RR we're testing, check > - that the type in question doesn't appear in the type > map */ > -@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct > dns_header *header, size_t plen, unsi > - /* A CNAME answer would also be valid, so if there's > a CNAME is should > - have been returned. */ > - if ((p[2] & (0x80 >> T_CNAME)) != 0) > -- return STAT_BOGUS; > -+ return 0; > - > - /* If the SOA bit is set for a DS record, then we > have the > - DS from the wrong side of the delegation. */ > - if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0) > -- return STAT_BOGUS; > -+ return 0; > - } > - > - while (rdlen >= 2) > - { > - if (!CHECK_LEN(header, p, plen, rdlen)) > -- return STAT_BOGUS; > -+ return 0; > - > - if (p[0] == type >> 8) > - { > - /* Does the NSEC say our type exists? */ > - if (offset < p[1] && (p[offset+2] & mask) != 0) > -- return STAT_BOGUS; > -+ return 0; > - > - break; /* finshed checking */ > - } > -@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct > dns_header *header, size_t plen, unsi > - p += p[1]; > - } > - > -- return STAT_SECURE; > -+ return 1; > - } > - else if (rc == -1) > - { > - /* Normal case, name falls between NSEC name and next > domain name, > - wrap around case, name falls between NSEC name (rc == > -1) and end */ > - if (hostname_cmp(workspace2, name) >= 0 || > hostname_cmp(workspace1, workspace2) >= 0) > -- return STAT_SECURE; > -+ return 1; > - } > - else > - { > - /* wrap around case, name falls between start and next > domain name */ > - if (hostname_cmp(workspace1, workspace2) >= 0 && > hostname_cmp(workspace2, name) >=0 ) > -- return STAT_SECURE; > -+ return 1; > - } > - } > - > -- return STAT_BOGUS; > -+ return 0; > - } > - > - /* return digest length, or zero on error */ > -@@ -1701,7 +1648,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - for (i = 0; i < nsec_count; i++) > - { > - if (!(p = skip_name(nsecs[i], header, plen, 15))) > -- return STAT_BOGUS; /* bad packet */ > -+ return 0; /* bad packet */ > - > - p += 10; /* type, class, TTL, rdlen */ > - algo = *p++; > -@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - > - /* No usable NSEC3s */ > - if (i == nsec_count) > -- return STAT_BOGUS; > -+ return 0; > - > - p++; /* flags */ > - GETSHORT (iterations, p); > - salt_len = *p++; > - salt = p; > - if (!CHECK_LEN(header, salt, plen, salt_len)) > -- return STAT_BOGUS; /* bad packet */ > -+ return 0; /* bad packet */ > - > - /* Now prune so we only have NSEC3 records with same iterations, > salt and algo */ > - for (i = 0; i < nsec_count; i++) > -@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - nsecs[i] = NULL; /* Speculative, will be restored if OK. */ > - > - if (!(p = skip_name(nsec3p, header, plen, 15))) > -- return STAT_BOGUS; /* bad packet */ > -+ return 0; /* bad packet */ > - > - p += 10; /* type, class, TTL, rdlen */ > - > -@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - continue; > - > - if (!CHECK_LEN(header, p, plen, salt_len)) > -- return STAT_BOGUS; /* bad packet */ > -+ return 0; /* bad packet */ > - > - if (memcmp(p, salt, salt_len) != 0) > - continue; > -@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - > - /* Algo is checked as 1 above */ > - if (!(hash = hash_find("sha1"))) > -- return STAT_BOGUS; > -+ return 0; > - > - if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, > iterations)) == 0) > -- return STAT_BOGUS; > -+ return 0; > - > - if (check_nsec3_coverage(header, plen, digest_len, digest, type, > workspace1, workspace2, nsecs, nsec_count, nons)) > -- return STAT_SECURE; > -+ return 1; > - > - /* Can't find an NSEC3 which covers the name directly, we need > the "closest encloser NSEC3" > - or an answer inferred from a wildcard record. */ > -@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - break; > - > - if ((digest_len = hash_name(closest_encloser, &digest, hash, > salt, salt_len, iterations)) == 0) > -- return STAT_BOGUS; > -+ return 0; > - > - for (i = 0; i < nsec_count; i++) > - if ((p = nsecs[i])) > - { > - if (!extract_name(header, plen, &p, workspace1, 1, 0) > || > - !(base32_len = base32_decode(workspace1, (unsigned > char *)workspace2))) > -- return STAT_BOGUS; > -+ return 0; > - > - if (digest_len == base32_len && > - memcmp(digest, workspace2, digest_len) == 0) > -@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - while ((closest_encloser = strchr(closest_encloser, '.'))); > - > - if (!closest_encloser) > -- return STAT_BOGUS; > -+ return 0; > - > - /* Look for NSEC3 that proves the non-existence of the next- > closest encloser */ > - if ((digest_len = hash_name(next_closest, &digest, hash, salt, > salt_len, iterations)) == 0) > -- return STAT_BOGUS; > -+ return 0; > - > - if (!check_nsec3_coverage(header, plen, digest_len, digest, type, > workspace1, workspace2, nsecs, nsec_count, NULL)) > -- return STAT_BOGUS; > -+ return 0; > - > - /* Finally, check that there's no seat of wildcard synthesis */ > - if (!wildname) > - { > - if (!(wildcard = strchr(next_closest, '.')) || wildcard == > next_closest) > -- return STAT_BOGUS; > -+ return 0; > - > - wildcard--; > - *wildcard = '*'; > - > - if ((digest_len = hash_name(wildcard, &digest, hash, salt, > salt_len, iterations)) == 0) > -- return STAT_BOGUS; > -+ return 0; > - > - if (!check_nsec3_coverage(header, plen, digest_len, digest, > type, workspace1, workspace2, nsecs, nsec_count, NULL)) > -- return STAT_BOGUS; > -+ return 0; > - } > - > -- return STAT_SECURE; > -+ return 1; > -+} > -+ > -+static int prove_non_existence(struct dns_header *header, size_t > plen, char *keyname, char *name, int qtype, int qclass, char > *wildname, int *nons) > -+{ > -+ static unsigned char **nsecset = NULL; > -+ static int nsecset_sz = 0; > -+ > -+ int type_found = 0; > -+ unsigned char *p = skip_questions(header, plen); > -+ int type, class, rdlen, i, nsecs_found; > -+ > -+ /* Move to NS section */ > -+ if (!p || !(p = skip_section(p, ntohs(header->ancount), header, > plen))) > -+ return 0; > -+ > -+ for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--) > -+ { > -+ unsigned char *pstart = p; > -+ > -+ if (!(p = skip_name(p, header, plen, 10))) > -+ return 0; > -+ > -+ GETSHORT(type, p); > -+ GETSHORT(class, p); > -+ p += 4; /* TTL */ > -+ GETSHORT(rdlen, p); > -+ > -+ if (class == qclass && (type == T_NSEC || type == T_NSEC3)) > -+ { > -+ /* No mixed NSECing 'round here, thankyouverymuch */ > -+ if (type_found != 0 && type_found != type) > -+ return 0; > -+ > -+ type_found = type; > -+ > -+ if (!expand_workspace(&nsecset, &nsecset_sz, > nsecs_found)) > -+ return 0; > -+ > -+ nsecset[nsecs_found++] = pstart; > -+ } > -+ > -+ if (!ADD_RDLEN(header, p, plen, rdlen)) > -+ return 0; > -+ } > -+ > -+ if (type_found == T_NSEC) > -+ return prove_non_existence_nsec(header, plen, nsecset, > nsecs_found, daemon->workspacename, keyname, name, qtype, nons); > -+ else > -+ return prove_non_existence_nsec3(header, plen, nsecset, > nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, > nons); > - } > - > - /* Check signing status of name. > -@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - static unsigned char **targets = NULL; > - static int target_sz = 0; > - > -- unsigned char *ans_start, *p1, *p2, **nsecs; > -+ unsigned char *ans_start, *p1, *p2; > - int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, > targetidx; > -- int i, j, rc, nsec_count; > -- int nsec_type; > -+ int i, j, rc; > - > - if (neganswer) > - *neganswer = 0; > -@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - targets[j] = NULL; > - } > - > -- if (rc == STAT_SECURE_WILDCARD) > -- { > -- /* An attacker replay a wildcard answer with > a different > -- answer and overlay a genuine RR. To prove > this > -- hasn't happened, the answer must prove > that > -- the gennuine record doesn't exist. Check > that here. */ > -- if (!(nsec_type = find_nsec_records(header, > plen, &nsecs, &nsec_count, class1))) > -- return STAT_BOGUS; /* No NSECs or bad > packet */ > -- > -- /* Note that we may not yet have validated > the NSEC/NSEC3 RRsets. Since the check > -- below returns either SECURE or BOGUS, > that's not a problem. If the RRsets later fail > -- we'll return BOGUS then. */ > -- > -- if (nsec_type == T_NSEC) > -- rc = prove_non_existence_nsec(header, plen, > nsecs, nsec_count, daemon->workspacename, keyname, name, type1, > NULL); > -- else > -- rc = prove_non_existence_nsec3(header, > plen, nsecs, nsec_count, daemon->workspacename, > -- keyname, > name, type1, wildname, NULL); > -- > -- if (rc == STAT_BOGUS) > -- return rc; > -- } > -+ /* An attacker replay a wildcard answer with a > different > -+ answer and overlay a genuine RR. To prove > this > -+ hasn't happened, the answer must prove that > -+ the gennuine record doesn't exist. Check that > here. > -+ Note that we may not yet have validated the > NSEC/NSEC3 RRsets. > -+ That's not a problem since if the RRsets > later fail > -+ we'll return BOGUS then. */ > -+ if (rc == STAT_SECURE_WILDCARD && > !prove_non_existence(header, plen, keyname, name, type1, class1, > wildname, NULL)) > -+ return STAT_BOGUS; > - } > - } > - } > -@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - > - /* For anything other than a DS record, this situation is > OK if either > - the answer is in an unsigned zone, or there's a NSEC > records. */ > -- if (!(nsec_type = find_nsec_records(header, plen, &nsecs, > &nsec_count, qclass))) > -+ if (!prove_non_existence(header, plen, keyname, name, > qtype, qclass, NULL, nons)) > - { > - /* Empty DS without NSECS */ > - if (qtype == T_DS) > - return STAT_BOGUS; > - > -- rc = zone_status(name, qclass, keyname, now); > -- if (rc != STAT_SECURE) > -+ if ((rc = zone_status(name, qclass, keyname, now)) != > STAT_SECURE) > - { > - if (class) > - *class = qclass; /* Class for NEED_DS or > NEED_DNSKEY */ > -@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - > - return STAT_BOGUS; /* signed zone, no NSECs */ > - } > -- > -- if (nsec_type == T_NSEC) > -- rc = prove_non_existence_nsec(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, qtype, nons); > -- else > -- rc = prove_non_existence_nsec3(header, plen, nsecs, > nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons); > -- > -- if (rc != STAT_SECURE) > -- return rc; > - } > - > - return STAT_SECURE; > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/023- > Fix_brace_botch_in_dnssec_validate_ds.patch > b/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch > deleted file mode 100644 > index eda6fbd..0000000 > --- a/src/patches/dnsmasq/023- > Fix_brace_botch_in_dnssec_validate_ds.patch > +++ /dev/null > @@ -1,98 +0,0 @@ > -From 3b799c826db05fc2da1c6d15cbe372e394209d27 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Thu, 17 Dec 2015 16:58:04 +0000 > -Subject: [PATCH] Fix brace botch in dnssec_validate_ds() > -MIME-Version: 1.0 > -Content-Type: text/plain; charset=utf8 > -Content-Transfer-Encoding: 8bit > - > -Thanks to Michał Kępień for spotting this. > ---- > - src/dnssec.c | 34 +++++++++++++++++----------------- > - 1 file changed, 17 insertions(+), 17 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index ddae497..1f8c954 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -923,11 +923,11 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - /* The DNS packet is expected to contain the answer to a DNSKEY > query. > - Put all DNSKEYs in the answer which are valid into the cache. > - return codes: > -- STAT_OK Done, key(s) in cache. > -- STAT_BOGUS No DNSKEYs found, which can be > validated with DS, > -- or self-sign for DNSKEY RRset is not > valid, bad packet. > -- STAT_NEED_DS DS records to validate a key not found, > name in keyname > -- STAT_NEED_DNSKEY DNSKEY records to validate a key not > found, name in keyname > -+ STAT_OK Done, key(s) in cache. > -+ STAT_BOGUS No DNSKEYs found, which can be validated > with DS, > -+ or self-sign for DNSKEY RRset is not valid, > bad packet. > -+ STAT_NEED_DS DS records to validate a key not found, > name in keyname > -+ STAT_NEED_KEY DNSKEY records to validate a key not found, > name in keyname > - */ > - int dnssec_validate_by_ds(time_t now, struct dns_header *header, > size_t plen, char *name, char *keyname, int class) > - { > -@@ -1224,13 +1224,13 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - } > - > - p = psave; > -- > -- if (!ADD_RDLEN(header, p, plen, rdlen)) > -- return STAT_BOGUS; /* bad packet */ > - } > -- > -- cache_end_insert(); > -+ if (!ADD_RDLEN(header, p, plen, rdlen)) > -+ return STAT_BOGUS; /* bad packet */ > - } > -+ > -+ cache_end_insert(); > -+ > - } > - else > - { > -@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct > dns_header *header, size_t plen, char *key > - > - /* Check signing status of name. > - returns: > -- STAT_SECURE zone is signed. > -- STAT_INSECURE zone proved unsigned. > -- STAT_NEED_DS require DS record of name returned in keyname. > -- STAT_NEED_DNSKEY require DNSKEY record of name returned in > keyname. > -+ STAT_SECURE zone is signed. > -+ STAT_INSECURE zone proved unsigned. > -+ STAT_NEED_DS require DS record of name returned in keyname. > -+ STAT_NEED_KEY require DNSKEY record of name returned in keyname. > - name returned unaltered. > - */ > - static int zone_status(char *name, int class, char *keyname, time_t > now) > -@@ -2028,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - if (rc == STAT_SECURE) > - rc = STAT_BOGUS; > - if (class) > -- *class = class1; /* Class for NEED_DS or > NEED_DNSKEY */ > -+ *class = class1; /* Class for NEED_DS or > NEED_KEY */ > - } > - else > - rc = STAT_INSECURE; > -@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - { > - /* Zone is insecure, don't need to validate RRset > */ > - if (class) > -- *class = class1; /* Class for NEED_DS or > NEED_DNSKEY */ > -+ *class = class1; /* Class for NEED_DS or > NEED_KEY */ > - return rc; > - } > - > -@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct > dns_header *header, size_t plen, ch > - if ((rc = zone_status(name, qclass, keyname, now)) != > STAT_SECURE) > - { > - if (class) > -- *class = qclass; /* Class for NEED_DS or > NEED_DNSKEY */ > -+ *class = qclass; /* Class for NEED_DS or NEED_KEY > */ > - return rc; > - } > - > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/024- > Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p > atch b/src/patches/dnsmasq/024- > Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p > atch > deleted file mode 100644 > index abcae5c..0000000 > --- a/src/patches/dnsmasq/024- > Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.p > atch > +++ /dev/null > @@ -1,145 +0,0 @@ > -From 14a4ae883d51130d33da7133287e8867c64bab65 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Thu, 17 Dec 2015 17:23:03 +0000 > -Subject: [PATCH] Do a better job of determining which DNSSEC sig > algos are > - supported. > - > ---- > - src/dnssec.c | 52 +++++++++++++++++++++++++++++++++++++-------- > ------- > - 1 file changed, 37 insertions(+), 15 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 1f8c954..82394ee 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -65,10 +65,9 @@ static char *algo_digest_name(int algo) > - case 8: return "sha256"; > - case 10: return "sha512"; > - case 12: return "gosthash94"; > --#ifndef NO_NETTLE_ECC > - case 13: return "sha256"; > - case 14: return "sha384"; > --#endif > -+ > - default: return NULL; > - } > - } > -@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash > *hash, void **ctxp, unsigned char > - } > - > - static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned > int key_len, unsigned char *sig, size_t sig_len, > -- unsigned char *digest, int algo) > -+ unsigned char *digest, size_t > digest_len, int algo) > - { > - unsigned char *p; > - size_t exp_len; > - > - static struct rsa_public_key *key = NULL; > - static mpz_t sig_mpz; > -+ > -+ (void)digest_len; > - > - if (key == NULL) > - { > -@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata > *key_data, unsigned int key_len, > - } > - > - static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned > int key_len, unsigned char *sig, size_t sig_len, > -- unsigned char *digest, int algo) > -+ unsigned char *digest, size_t > digest_len, int algo) > - { > - unsigned char *p; > - unsigned int t; > -@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata > *key_data, unsigned int key_len, > - static struct dsa_public_key *key = NULL; > - static struct dsa_signature *sig_struct; > - > -+ (void)digest_len; > -+ > - if (key == NULL) > - { > - if (!(sig_struct = whine_malloc(sizeof(struct > dsa_signature))) || > -@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct > blockdata *key_data, unsigned int key_len > - } > - #endif > - > --static int verify(struct blockdata *key_data, unsigned int key_len, > unsigned char *sig, size_t sig_len, > -- unsigned char *digest, size_t digest_len, int > algo) > -+static int (*verify_func(int algo))(struct blockdata *key_data, > unsigned int key_len, unsigned char *sig, size_t sig_len, > -+ unsigned char *digest, size_t > digest_len, int algo) > - { > -- (void)digest_len; > -- > -+ > -+ /* Enure at runtime that we have support for this digest */ > -+ if (!hash_find(algo_digest_name(algo))) > -+ return NULL; > -+ > -+ /* This switch defines which sig algorithms we support, can't > introspect Nettle for that. */ > - switch (algo) > - { > - case 1: case 5: case 7: case 8: case 10: > -- return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len, > digest, algo); > -+ return dnsmasq_rsa_verify; > - > - case 3: case 6: > -- return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, > digest, algo); > -+ return dnsmasq_dsa_verify; > - > - #ifndef NO_NETTLE_ECC > - case 13: case 14: > -- return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, > digest, digest_len, algo); > -+ return dnsmasq_ecdsa_verify; > - #endif > - } > - > -- return 0; > -+ return NULL; > -+} > -+ > -+static int verify(struct blockdata *key_data, unsigned int key_len, > unsigned char *sig, size_t sig_len, > -+ unsigned char *digest, size_t digest_len, int > algo) > -+{ > -+ > -+ int (*func)(struct blockdata *key_data, unsigned int key_len, > unsigned char *sig, size_t sig_len, > -+ unsigned char *digest, size_t digest_len, int algo); > -+ > -+ func = verify_func(algo); > -+ > -+ if (!func) > -+ return 0; > -+ > -+ return (*func)(key_data, key_len, sig, sig_len, digest, > digest_len, algo); > - } > - > - /* Convert from presentation format to wire format, in place. > -@@ -732,7 +754,7 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > - if (check_date_range(sig_inception, sig_expiration) > && > - labels <= name_labels && > - type_covered == type && > -- algo_digest_name(algo)) > -+ verify_func(algo)) > - { > - if (!expand_workspace(&sigs, &sig_sz, sigidx)) > - return 0; > -@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class, > char *keyname, time_t now) > - if (crecp->flags & F_DNSSECOK) > - return STAT_INSECURE; /* proved no DS here > */ > - } > -- else if (!ds_digest_name(crecp->addr.ds.digest) > || !algo_digest_name(crecp->addr.ds.algo)) > -+ else if (!hash_find(ds_digest_name(crecp- > >addr.ds.digest)) || !verify_func(crecp->addr.ds.algo)) > - return STAT_INSECURE; /* algo we can't use - > insecure */ > - else > - secure_ds = 1; > -@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class, > char *keyname, time_t now) > - > - do > - { > -- if (crecp->uid == (unsigned int)class && > !algo_digest_name(crecp->addr.key.algo)) > -+ if (crecp->uid == (unsigned int)class && > !verify_func(crecp->addr.key.algo)) > - return STAT_INSECURE; > - } > - while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DNSKEY))); > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > b/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > deleted file mode 100644 > index c016e73..0000000 > --- a/src/patches/dnsmasq/025- > Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch > +++ /dev/null > @@ -1,643 +0,0 @@ > -From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sun, 20 Dec 2015 17:12:16 +0000 > -Subject: [PATCH] Major tidy up of EDNS0 handling and computation/use > of udp > - packet size. > - > ---- > - src/auth.c | 8 ++- > - src/dnsmasq.h | 7 ++- > - src/dnssec.c | 1 - > - src/forward.c | 184 ++++++++++++++++++++++++++++++++++++++++----- > ----------- > - src/netlink.c | 3 +- > - src/rfc1035.c | 81 +++++++------------------ > - src/rrfilter.c | 2 +- > - 7 files changed, 168 insertions(+), 118 deletions(-) > - > -diff --git a/src/auth.c b/src/auth.c > -index 2b0b7d6..85bd5e7 100644 > ---- a/src/auth.c > -+++ b/src/auth.c > -@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, > char **cut) > - } > - > - > --size_t answer_auth(struct dns_header *header, char *limit, size_t > qlen, time_t now, union mysockaddr *peer_addr, int local_query) > -+size_t answer_auth(struct dns_header *header, char *limit, size_t > qlen, time_t now, union mysockaddr *peer_addr, > -+ int local_query, int do_bit, int > have_pseudoheader) > - { > - char *name = daemon->namebuff; > - unsigned char *p, *ansp; > -@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, > char *limit, size_t qlen, time_t n > - header->ancount = htons(anscount); > - header->nscount = htons(authcount); > - header->arcount = htons(0); > -+ > -+ /* Advertise our packet size limit in our reply */ > -+ if (have_pseudoheader) > -+ return add_pseudoheader(header, ansp - (unsigned char > *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, > do_bit); > -+ > - return ansp - (unsigned char *)header; > - } > - > -diff --git a/src/dnsmasq.h b/src/dnsmasq.h > -index 39a930c..abb34c5 100644 > ---- a/src/dnsmasq.h > -+++ b/src/dnsmasq.h > -@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header > *header, size_t qlen, char *namebuff, > - int no_cache, int secure, int *doctored); > - size_t answer_request(struct dns_header *header, char *limit, > size_t qlen, > - struct in_addr local_addr, struct in_addr > local_netmask, > -- time_t now, int *ad_reqd, int *do_bit); > -+ time_t now, int ad_reqd, int do_bit, int > have_pseudoheader); > - int check_for_bogus_wildcard(struct dns_header *header, size_t > qlen, char *name, > - struct bogus_addr *addr, time_t now); > - int check_for_ignored_address(struct dns_header *header, size_t > qlen, struct bogus_addr *baddr); > -@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t > now); > - unsigned int questions_crc(struct dns_header *header, size_t plen, > char *buff); > - size_t resize_packet(struct dns_header *header, size_t plen, > - unsigned char *pheader, size_t hlen); > -+size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > -+ unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do); > - size_t add_mac(struct dns_header *header, size_t plen, char *limit, > union mysockaddr *l3); > - size_t add_source_addr(struct dns_header *header, size_t plen, char > *limit, union mysockaddr *source); > - #ifdef HAVE_DNSSEC > -@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int > ban_localhost); > - /* auth.c */ > - #ifdef HAVE_AUTH > - size_t answer_auth(struct dns_header *header, char *limit, size_t > qlen, > -- time_t now, union mysockaddr *peer_addr, int > local_query); > -+ time_t now, union mysockaddr *peer_addr, int > local_query, > -+ int do_bit, int have_pseudoheader); > - int in_zone(struct auth_zone *zone, char *name, char **cut); > - #endif > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 82394ee..299ca64 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo) > - case 12: return "gosthash94"; > - case 13: return "sha256"; > - case 14: return "sha384"; > -- > - default: return NULL; > - } > - } > -diff --git a/src/forward.c b/src/forward.c > -index 3e801c8..041353c 100644 > ---- a/src/forward.c > -+++ b/src/forward.c > -@@ -244,7 +244,6 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > - void *hash = &crc; > - #endif > - unsigned int gotname = extract_request(header, plen, daemon- > >namebuff, NULL); > -- unsigned char *pheader; > - > - (void)do_bit; > - > -@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > - there's no point retrying the query, retry the key query > instead...... */ > - if (forward->blocking_query) > - { > -- int fd; > -+ int fd, is_sign; > -+ unsigned char *pheader; > - > - forward->flags &= ~FREC_TEST_PKTSZ; > - > -@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > - blockdata_retrieve(forward->stash, forward->stash_len, > (void *)header); > - plen = forward->stash_len; > - > -- if (find_pseudoheader(header, plen, NULL, &pheader, > NULL)) > -- PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? > SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader); > -+ if (find_pseudoheader(header, plen, NULL, &pheader, > &is_sign) && !is_sign) > -+ PUTSHORT(SAFE_PKTSZ, pheader); > - > - if (forward->sentto->addr.sa.sa_family == AF_INET) > - log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", > (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); > -@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > - forward->log_id = daemon->log_id; > - > - if (option_bool(OPT_ADD_MAC)) > -- plen = add_mac(header, plen, ((char *) header) + daemon- > >packet_buff_sz, &forward->source); > -- > -+ { > -+ size_t new = add_mac(header, plen, ((char *) header) + > daemon->packet_buff_sz, &forward->source); > -+ if (new != plen) > -+ { > -+ plen = new; > -+ forward->flags |= FREC_ADDED_PHEADER; > -+ } > -+ } > -+ > - if (option_bool(OPT_CLIENT_SUBNET)) > - { > - size_t new = add_source_addr(header, plen, ((char *) > header) + daemon->packet_buff_sz, &forward->source); > - if (new != plen) > - { > - plen = new; > -- forward->flags |= FREC_HAS_SUBNET; > -+ forward->flags |= FREC_HAS_SUBNET | > FREC_ADDED_PHEADER; > - } > - } > - > - #ifdef HAVE_DNSSEC > - if (option_bool(OPT_DNSSEC_VALID)) > - { > -- size_t new_plen = add_do_bit(header, plen, ((char *) > header) + daemon->packet_buff_sz); > -+ size_t new = add_do_bit(header, plen, ((char *) header) + > daemon->packet_buff_sz); > - > -+ if (new != plen) > -+ forward->flags |= FREC_ADDED_PHEADER; > -+ > -+ plen = new; > -+ > - /* For debugging, set Checking Disabled, otherwise, have > the upstream check too, > - this allows it to select auth servers when one is > returning bad data. */ > - if (option_bool(OPT_DNSSEC_DEBUG)) > - header->hb4 |= HB4_CD; > - > -- if (new_plen != plen) > -- forward->flags |= FREC_ADDED_PHEADER; > -- > -- plen = new_plen; > - } > - #endif > - > -@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union > mysockaddr *udpaddr, > - } > - #endif > - } > -- > -- if (find_pseudoheader(header, plen, NULL, &pheader, > NULL)) > -- PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? > SAFE_PKTSZ : start->edns_pktsz, pheader); > - > -+#ifdef HAVE_DNSSEC > -+ if (option_bool(OPT_DNSSEC_VALID) && !do_bit) > -+ { > -+ /* Difficult one here. If our client didn't send > EDNS0, we will have set the UDP > -+ packet size to 512. But that won't provide > space for the RRSIGS in many cases. > -+ The RRSIGS will be stripped out before the > answer goes back, so the packet should > -+ shrink again. So, if we added a do-bit, bump > the udp packet size to the value > -+ known to be OK for this server. Maybe check > returned size after stripping and set > -+ the truncated bit? */ > -+ unsigned char *pheader; > -+ int is_sign; > -+ if (find_pseudoheader(header, plen, NULL, > &pheader, &is_sign)) > -+ PUTSHORT(start->edns_pktsz, pheader); > -+ } > -+#endif > -+ > - if (retry_send(sendto(fd, (char *)header, plen, 0, > - &start->addr.sa, > - sa_len(&start->addr)))) > -@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > - } > - #endif > - > -- /* If upstream is advertising a larger UDP packet size > -- than we allow, trim it so that we don't get overlarge > -- requests for the client. We can't do this for signed packets. > */ > -- > - if ((pheader = find_pseudoheader(header, n, &plen, &sizep, > &is_sign))) > - { > -- unsigned short udpsz; > -- unsigned char *psave = sizep; > -- > -- GETSHORT(udpsz, sizep); > -- > -- if (!is_sign && udpsz > daemon->edns_pktsz) > -- PUTSHORT(daemon->edns_pktsz, psave); > -- > - if (check_subnet && !check_source(header, plen, pheader, > query_source)) > - { > - my_syslog(LOG_WARNING, _("discarding DNS reply: subnet > option mismatch")); > - return 0; > - } > - > -- if (added_pheader) > -+ if (!is_sign) > - { > -- pheader = 0; > -- header->arcount = htons(0); > -+ if (added_pheader) > -+ { > -+ /* client didn't send EDNS0, we added one, strip it > off before returning answer. */ > -+ n = rrfilter(header, n, 0); > -+ pheader = NULL; > -+ } > -+ else > -+ { > -+ /* If upstream is advertising a larger UDP packet > size > -+ than we allow, trim it so that we don't get > overlarge > -+ requests for the client. We can't do this for > signed packets. */ > -+ unsigned short udpsz; > -+ unsigned char *psave = sizep; > -+ > -+ GETSHORT(udpsz, sizep); > -+ if (udpsz > daemon->edns_pktsz) > -+ PUTSHORT(daemon->edns_pktsz, psave); > -+ } > - } > - } > - > -@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header > *header, time_t now, struct server > - } > - > - if (option_bool(OPT_DNSSEC_VALID)) > -- header->hb4 &= ~HB4_AD; > -- > -- if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) > -- header->hb4 |= HB4_AD; > -- > -- /* If the requestor didn't set the DO bit, don't return DNSSEC > info. */ > -- if (!do_bit) > -- n = rrfilter(header, n, 1); > -+ { > -+ header->hb4 &= ~HB4_AD; > -+ > -+ if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) > -+ header->hb4 |= HB4_AD; > -+ > -+ /* If the requestor didn't set the DO bit, don't return > DNSSEC info. */ > -+ if (!do_bit) > -+ n = rrfilter(header, n, 1); > -+ } > - #endif > - > - /* do this after extract_addresses. Ensure NODATA reply and > remove > -@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t > now) > - if ((nn = resize_packet(header, (size_t)n, pheader, > plen))) > - { > - header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC); > -- header->hb4 &= ~(HB4_RA | HB4_RCODE); > -- forward_query(-1, NULL, NULL, 0, header, nn, now, > forward, 0, 0); > -+ header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | > HB4_AD); > -+ if (forward->flags |= FREC_CHECKING_DISABLED) > -+ header->hb4 |= HB4_CD; > -+ if (forward->flags |= FREC_AD_QUESTION) > -+ header->hb4 |= HB4_AD; > -+ if (forward->flags & FREC_DO_QUESTION) > -+ add_do_bit(header, nn, (char *)pheader + plen); > -+ forward_query(-1, NULL, NULL, 0, header, nn, now, > forward, forward->flags & FREC_AD_QUESTION, forward->flags & > FREC_DO_QUESTION); > - return; > - } > - } > -@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, > time_t now) > - { > - struct dns_header *header = (struct dns_header *)daemon->packet; > - union mysockaddr source_addr; > -- unsigned short type; > -+ unsigned char *pheader; > -+ unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 > */ > - struct all_addr dst_addr; > - struct in_addr netmask, dst_addr_4; > - size_t m; > - ssize_t n; > -- int if_index = 0, auth_dns = 0; > -+ int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = > 0; > - #ifdef HAVE_AUTH > - int local_auth = 0; > - #endif > -@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, > time_t now) > - #endif > - } > - > -+ if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL)) > -+ { > -+ unsigned short flags; > -+ > -+ have_pseudoheader = 1; > -+ GETSHORT(udp_size, pheader); > -+ pheader += 2; /* ext_rcode */ > -+ GETSHORT(flags, pheader); > -+ > -+ if (flags & 0x8000) > -+ do_bit = 1;/* do bit */ > -+ > -+ /* If the client provides an EDNS0 UDP size, use that to > limit our reply. > -+ (bounded by the maximum configured). If no EDNS0, then it > -+ defaults to 512 */ > -+ if (udp_size > daemon->edns_pktsz) > -+ udp_size = daemon->edns_pktsz; > -+ } > -+ > - #ifdef HAVE_AUTH > - if (auth_dns) > - { > -- m = answer_auth(header, ((char *) header) + daemon- > >packet_buff_sz, (size_t)n, now, &source_addr, local_auth); > -+ m = answer_auth(header, ((char *) header) + udp_size, > (size_t)n, now, &source_addr, > -+ local_auth, do_bit, have_pseudoheader); > - if (m >= 1) > - { > - send_from(listen->fd, option_bool(OPT_NOWILD) || > option_bool(OPT_CLEVERBIND), > -@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, > time_t now) > - else > - #endif > - { > -- int ad_reqd, do_bit; > -- m = answer_request(header, ((char *) header) + daemon- > >packet_buff_sz, (size_t)n, > -- dst_addr_4, netmask, now, &ad_reqd, > &do_bit); > -+ int ad_reqd = do_bit; > -+ /* RFC 6840 5.7 */ > -+ if (header->hb4 & HB4_AD) > -+ ad_reqd = 1; > -+ > -+ m = answer_request(header, ((char *) header) + udp_size, > (size_t)n, > -+ dst_addr_4, netmask, now, ad_reqd, do_bit, > have_pseudoheader); > - > - if (m >= 1) > - { > -@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t > now, > - #ifdef HAVE_AUTH > - int local_auth = 0; > - #endif > -- int checking_disabled, ad_question, do_bit, added_pheader = 0; > -+ int checking_disabled, do_bit, added_pheader = 0, > have_pseudoheader = 0; > - int check_subnet, no_cache_dnssec = 0, cache_secure = 0, > bogusanswer = 0; > - size_t m; > - unsigned short qtype; > -@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t > now, > - union mysockaddr peer_addr; > - socklen_t peer_len = sizeof(union mysockaddr); > - int query_count = 0; > -+ unsigned char *pheader; > - > - if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) > == -1) > - return packet; > -@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t > now, > - else > - dst_addr_4.s_addr = 0; > - > -+ do_bit = 0; > -+ > -+ if (find_pseudoheader(header, (size_t)size, NULL, &pheader, > NULL)) > -+ { > -+ unsigned short flags; > -+ > -+ have_pseudoheader = 1; > -+ pheader += 4; /* udp_size, ext_rcode */ > -+ GETSHORT(flags, pheader); > -+ > -+ if (flags & 0x8000) > -+ do_bit = 1;/* do bit */ > -+ } > -+ > - #ifdef HAVE_AUTH > - if (auth_dns) > -- m = answer_auth(header, ((char *) header) + 65536, > (size_t)size, now, &peer_addr, local_auth); > -+ m = answer_auth(header, ((char *) header) + 65536, > (size_t)size, now, &peer_addr, > -+ local_auth, do_bit, have_pseudoheader); > - else > - #endif > - { > -- /* m > 0 if answered from cache */ > -- m = answer_request(header, ((char *) header) + 65536, > (size_t)size, > -- dst_addr_4, netmask, now, > &ad_question, &do_bit); > -+ int ad_reqd = do_bit; > -+ /* RFC 6840 5.7 */ > -+ if (header->hb4 & HB4_AD) > -+ ad_reqd = 1; > -+ > -+ /* m > 0 if answered from cache */ > -+ m = answer_request(header, ((char *) header) + 65536, > (size_t)size, > -+ dst_addr_4, netmask, now, ad_reqd, > do_bit, have_pseudoheader); > - > - /* Do this by steam now we're not in the select() loop */ > - check_log_writer(1); > -@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t > now, > - } > - > - #ifdef HAVE_DNSSEC > -+ added_pheader = 0; > > - if (option_bool(OPT_DNSSEC_VALID)) > - { > - size_t new_size = add_do_bit(header, > size, ((char *) header) + 65536); > -@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t > now, > - > - m = process_reply(header, now, last_server, > (unsigned int)m, > - option_bool(OPT_NO_REBIND) > && !norebind, no_cache_dnssec, cache_secure, bogusanswer, > -- ad_question, do_bit, > added_pheader, check_subnet, &peer_addr); > -+ ad_reqd, do_bit, > added_pheader, check_subnet, &peer_addr); > - > - break; > - } > -diff --git a/src/netlink.c b/src/netlink.c > -index 753784d..3376d68 100644 > ---- a/src/netlink.c > -+++ b/src/netlink.c > -@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int > (*callback)()) > - rta = RTA_NEXT(rta, len1); > - } > - > -- if (inaddr && mac && callback_ok) > -+ if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | > NUD_FAILED)) && > -+ inaddr && mac && callback_ok) > - if (!((*callback)(neigh->ndm_family, inaddr, mac, > maclen, parm))) > - callback_ok = 0; > - } > -diff --git a/src/rfc1035.c b/src/rfc1035.c > -index 188d05f..18858a8 100644 > ---- a/src/rfc1035.c > -+++ b/src/rfc1035.c > -@@ -489,8 +489,8 @@ struct macparm { > - union mysockaddr *l3; > - }; > - > --static size_t add_pseudoheader(struct dns_header *header, size_t > plen, unsigned char *limit, > -- int optno, unsigned char *opt, > size_t optlen, int set_do) > -+size_t add_pseudoheader(struct dns_header *header, size_t plen, > unsigned char *limit, > -+ unsigned short udp_sz, int optno, unsigned > char *opt, size_t optlen, int set_do) > - { > - unsigned char *lenp, *datap, *p; > - int rdlen, is_sign; > -@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header > *header, size_t plen, unsigned > - return plen; > - *p++ = 0; /* empty name */ > - PUTSHORT(T_OPT, p); > -- PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be > overwritten */ > -+ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given > in EDNS0 header */ > - PUTSHORT(0, p); /* extended RCODE and version */ > - PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ > - lenp = p; > -@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, > char *mac, size_t maclen, void *p > - if (!match) > - return 1; /* continue */ > - > -- parm->plen = add_pseudoheader(parm->header, parm->plen, parm- > >limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); > -+ parm->plen = add_pseudoheader(parm->header, parm->plen, parm- > >limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); > - > - return 0; /* done */ > - } > -@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, > size_t plen, char *limit, union mysock > - { > - struct macparm parm; > - > --/* Must have an existing pseudoheader as the only ar-record, > -- or have no ar-records. Must also not be signed */ > -- > -- if (ntohs(header->arcount) > 1) > -- return plen; > -- > - parm.header = header; > - parm.limit = (unsigned char *)limit; > - parm.plen = plen; > -@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header > *header, size_t plen, char *limit, unio > - struct subnet_opt opt; > - > - len = calc_subnet_opt(&opt, source); > -- return add_pseudoheader(header, plen, (unsigned char *)limit, > EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > -+ return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); > - } > - > - #ifdef HAVE_DNSSEC > - size_t add_do_bit(struct dns_header *header, size_t plen, char > *limit) > - { > -- return add_pseudoheader(header, plen, (unsigned char *)limit, 0, > NULL, 0, 1); > -+ return add_pseudoheader(header, plen, (unsigned char *)limit, > PACKETSZ, 0, NULL, 0, 1); > - } > - #endif > - > -@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec > *crecp, time_t now) > - /* return zero if we can't answer from cache, or packet size if we > can */ > - size_t answer_request(struct dns_header *header, char *limit, > size_t qlen, > - struct in_addr local_addr, struct in_addr > local_netmask, > -- time_t now, int *ad_reqd, int *do_bit) > -+ time_t now, int ad_reqd, int do_bit, int > have_pseudoheader) > - { > - char *name = daemon->namebuff; > -- unsigned char *p, *ansp, *pheader; > -+ unsigned char *p, *ansp; > - unsigned int qtype, qclass; > - struct all_addr addr; > - int nameoffset; > - unsigned short flag; > - int q, ans, anscount = 0, addncount = 0; > -- int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0; > -+ int dryrun = 0; > - struct crec *crecp; > - int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; > - struct mx_srv_record *rec; > -@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - if (header->hb4 & HB4_CD) > - sec_data = 0; > - > -- /* RFC 6840 5.7 */ > -- *ad_reqd = header->hb4 & HB4_AD; > -- *do_bit = 0; > -- > - /* If there is an additional data section then it will be > overwritten by > - partial replies, so we have to do a dry run to see if we can > answer > - the query. */ > -- > - if (ntohs(header->arcount) != 0) > -- { > -- dryrun = 1; > -- > -- /* If there's an additional section, there might be an > EDNS(0) pseudoheader */ > -- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) > -- { > -- unsigned short flags; > -- > -- have_pseudoheader = 1; > -- > -- pheader += 4; /* udp size, ext_rcode */ > -- GETSHORT(flags, pheader); > -- > -- if ((sec_reqd = flags & 0x8000)) > -- { > -- *do_bit = 1;/* do bit */ > -- *ad_reqd = 1; > -- } > -- } > -- } > -+ dryrun = 1; > - > - for (rec = daemon->mxnames; rec; rec = rec->next) > - rec->offset = 0; > -@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - GETSHORT(qtype, p); > - GETSHORT(qclass, p); > - > -- /* Don't filter RRSIGS from answers to ANY queries, even if > do-bit > -- not set. */ > -- if (qtype == T_ANY) > -- *do_bit = 1; > -- > - ans = 0; /* have we answered this question */ > - > - if (qtype == T_TXT || qtype == T_ANY) > -@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - the zone is unsigned, which implies that we're > doing > - validation. */ > - if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || > -- !sec_reqd || > -+ !do_bit || > - (option_bool(OPT_DNSSEC_VALID) && !(crecp- > >flags & F_DNSSECOK))) > - { > - do > -@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - } > - > - /* If the client asked for DNSSEC don't use > cached data. */ > -- if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) > -+ if ((crecp->flags & (F_HOSTS | F_DHCP | > F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK)) > - do > - { > - /* don't answer wildcard queries with data > not from /etc/hosts > -@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - > - if (crecp->flags & F_NEG) > - { > -- /* We don't cache NSEC records, so if a > DNSSEC-validated negative answer > -- is cached and the client wants > DNSSEC, forward rather than answering from the cache */ > -- if (!sec_reqd || !(crecp->flags & > F_DNSSECOK)) > -- { > -- ans = 1; > -- auth = 0; > -- if (crecp->flags & F_NXDOMAIN) > -- nxdomain = 1; > -- if (!dryrun) > -- log_query(crecp->flags, name, > NULL, NULL); > -- } > -+ ans = 1; > -+ auth = 0; > -+ if (crecp->flags & F_NXDOMAIN) > -+ nxdomain = 1; > -+ if (!dryrun) > -+ log_query(crecp->flags, name, NULL, > NULL); > - } > - else > - { > -@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header > *header, char *limit, size_t qlen, > - > - len = ansp - (unsigned char *)header; > - > -+ /* Advertise our packet size limit in our reply */ > - if (have_pseudoheader) > -- len = add_pseudoheader(header, len, (unsigned char *)limit, 0, > NULL, 0, sec_reqd); > -+ len = add_pseudoheader(header, len, (unsigned char *)limit, > daemon->edns_pktsz, 0, NULL, 0, do_bit); > - > -- if (*ad_reqd && sec_data) > -+ if (ad_reqd && sec_data) > - header->hb4 |= HB4_AD; > - else > - header->hb4 &= ~HB4_AD; > -diff --git a/src/rrfilter.c b/src/rrfilter.c > -index ae12261..b26b39f 100644 > ---- a/src/rrfilter.c > -+++ b/src/rrfilter.c > -@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, > size_t plen, int mode) > - for (p = rrs[0], i = 1; i < rr_found; i += 2) > - { > - unsigned char *start = rrs[i]; > -- unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : > ((unsigned char *)(header+1)) + plen; > -+ unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : > ((unsigned char *)header) + plen; > - > - memmove(p, start, end-start); > - p += end-start; > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > b/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > deleted file mode 100644 > index 910921b..0000000 > --- a/src/patches/dnsmasq/026- > More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch > +++ /dev/null > @@ -1,262 +0,0 @@ > -From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sun, 20 Dec 2015 20:44:23 +0000 > -Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms. > - > ---- > - src/dnssec.c | 128 +++++++++++++++++++++++++++++---------------- > ------------- > - 1 file changed, 63 insertions(+), 65 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 299ca64..e09f304 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -70,7 +70,17 @@ static char *algo_digest_name(int algo) > - default: return NULL; > - } > - } > -- > -+ > -+/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-n > sec3-parameters.xhtml */ > -+static char *nsec3_digest_name(int digest) > -+{ > -+ switch (digest) > -+ { > -+ case 1: return "sha1"; > -+ default: return NULL; > -+ } > -+} > -+ > - /* Find pointer to correct hash function in nettle library */ > - static const struct nettle_hash *hash_find(char *name) > - { > -@@ -667,7 +677,6 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > - static int rrset_sz = 0, sig_sz = 0; > - unsigned char *p; > - int rrsetidx, sigidx, j, rdlen, res; > -- int name_labels = count_labels(name); /* For 4035 5.3.2 check */ > - int gotkey = 0; > - > - if (!(p = skip_questions(header, plen))) > -@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > - j != 0; j--) > - { > - unsigned char *pstart, *pdata; > -- int stype, sclass, algo, type_covered, labels, > sig_expiration, sig_inception; > -+ int stype, sclass, type_covered; > - > - pstart = p; > - > -@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > - return 0; /* bad packet */ > - > - GETSHORT(type_covered, p); > -- algo = *p++; > -- labels = *p++; > -- p += 4; /* orig_ttl */ > -- GETLONG(sig_expiration, p); > -- GETLONG(sig_inception, p); > -- p += 2; /* key_tag */ > -+ p += 16; /* algo, labels, orig_ttl, sig_expiration, > sig_inception, key_tag */ > - > - if (gotkey) > - { > -@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header > *header, size_t plen, int class, int > - } > - } > - > -- /* Don't count signatures for algos we don't support > */ > -- if (check_date_range(sig_inception, sig_expiration) > && > -- labels <= name_labels && > -- type_covered == type && > -- verify_func(algo)) > -+ > -+ if (type_covered == type) > - { > - if (!expand_workspace(&sigs, &sig_sz, sigidx)) > - return 0; > -@@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - char *name, char *keyname, char > **wildcard_out, struct blockdata *key, int keylen, int algo_in, int > keytag_in) > - { > - unsigned char *p; > -- int rdlen, j, name_labels; > -+ int rdlen, j, name_labels, sig_expiration, sig_inception; > - struct crec *crecp = NULL; > - int algo, labels, orig_ttl, key_tag; > - u16 *rr_desc = rrfilter_desc(type); > -@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct > dns_header *header, size_t plen, in > - algo = *p++; > - labels = *p++; > - GETLONG(orig_ttl, p); > -- p += 8; /* sig_expiration, sig_inception already checked */ > -+ GETLONG(sig_expiration, p); > -+ GETLONG(sig_inception, p); > - GETSHORT(key_tag, p); > - > - if (!extract_name(header, plen, &p, keyname, 1, 0)) > - return STAT_BOGUS; > - > -- if (!(hash = hash_find(algo_digest_name(algo))) || > -+ if (!check_date_range(sig_inception, sig_expiration) || > -+ labels > name_labels || > -+ !(hash = hash_find(algo_digest_name(algo))) || > - !hash_init(hash, &ctx, &digest)) > - continue; > - > -@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct > dns_header *header, size_t plen, ch > - else > - { > - a.addr.keytag = keytag; > -- log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u"); > -+ if (verify_func(algo)) > -+ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u"); > -+ else > -+ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)"); > - > - recp1->addr.key.keylen = rdlen - 4; > - recp1->addr.key.keydata = key; > -@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct > dns_header *header, size_t plen, char > - else > - { > - a.addr.keytag = keytag; > -- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, > name, &a, "DS keytag %u"); > -+ if (hash_find(ds_digest_name(digest)) && > verify_func(algo)) > -+ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u"); > -+ else > -+ log_query(F_NOEXTRA | F_KEYTAG | > F_UPSTREAM, name, &a, "DS keytag %u (not supported)"); > -+ > - crecp->addr.ds.digest = digest; > - crecp->addr.ds.keydata = key; > - crecp->addr.ds.algo = algo; > -@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - *nons = 1; > - > - /* Look though the NSEC3 records to find the first one with > -- an algorithm we support (currently only algo == 1). > -+ an algorithm we support. > - > - Take the algo, iterations, and salt of that record > - as the ones we're going to use, and prune any > -@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - p += 10; /* type, class, TTL, rdlen */ > - algo = *p++; > - > -- if (algo == 1) > -+ if ((hash = hash_find(nsec3_digest_name(algo)))) > - break; /* known algo */ > - } > - > -@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - nsecs[i] = nsec3p; > - } > - > -- /* Algo is checked as 1 above */ > -- if (!(hash = hash_find("sha1"))) > -- return 0; > -- > - if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, > iterations)) == 0) > - return 0; > - > -@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct > dns_header *header, size_t plen, char *key > - > - if (type_found == T_NSEC) > - return prove_non_existence_nsec(header, plen, nsecset, > nsecs_found, daemon->workspacename, keyname, name, qtype, nons); > -- else > -+ else if (type_found == T_NSEC3) > - return prove_non_existence_nsec3(header, plen, nsecset, > nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, > nons); > -+ else > -+ return 0; > - } > - > - /* Check signing status of name. > -@@ -1857,7 +1866,7 @@ static int prove_non_existence(struct > dns_header *header, size_t plen, char *key > - */ > - static int zone_status(char *name, int class, char *keyname, time_t > now) > - { > -- int secure_ds, name_start = strlen(name); > -+ int name_start = strlen(name); > - struct crec *crecp; > - char *p; > - > -@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int > class, char *keyname, time_t now) > - > - if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS))) > - return STAT_NEED_DS; > -+ > -+ /* F_DNSSECOK misused in DS cache records to non-existance > of NS record. > -+ F_NEG && !F_DNSSECOK implies that we've proved there's no > DS record here, > -+ but that's because there's no NS record either, ie this > isn't the start > -+ of a zone. We only prove that the DNS tree below a node > is unsigned when > -+ we prove that we're at a zone cut AND there's no DS > record. */ > -+ if (crecp->flags & F_NEG) > -+ { > -+ if (crecp->flags & F_DNSSECOK) > -+ return STAT_INSECURE; /* proved no DS here */ > -+ } > - else > - { > -- secure_ds = 0; > -- > -+ int gotone = 0; > -+ > -+ /* If all the DS records have digest and/or sig algos we > don't support, > -+ then the zone is insecure. Note that if an algo > -+ appears in the DS, then RRSIGs for that algo MUST > -+ exist for each RRset: 4035 para 2.2 So if we find > -+ a DS here with digest and sig we can do, we're > entitled > -+ to assume we can validate the zone and if we can't > later, > -+ because an RRSIG is missing we return BOGUS. > -+ */ > - do > - { > -- if (crecp->uid == (unsigned int)class) > -- { > -- /* F_DNSSECOK misused in DS cache records to non- > existance of NS record. > -- F_NEG && !F_DNSSECOK implies that we've proved > there's no DS record here, > -- but that's because there's no NS record > either, ie this isn't the start > -- of a zone. We only prove that the DNS tree > below a node is unsigned when > -- we prove that we're at a zone cut AND there's > no DS record. > -- */ > -- if (crecp->flags & F_NEG) > -- { > -- if (crecp->flags & F_DNSSECOK) > -- return STAT_INSECURE; /* proved no DS here > */ > -- } > -- else if (!hash_find(ds_digest_name(crecp- > >addr.ds.digest)) || !verify_func(crecp->addr.ds.algo)) > -- return STAT_INSECURE; /* algo we can't use - > insecure */ > -- else > -- secure_ds = 1; > -- } > -+ if (crecp->uid == (unsigned int)class && > -+ hash_find(ds_digest_name(crecp->addr.ds.digest)) > && > -+ verify_func(crecp->addr.ds.algo)) > -+ gotone = 1; > - } > - while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DS))); > -- } > -- > -- if (secure_ds) > -- { > -- /* We've found only DS records that attest to the DNSKEY > RRset in the zone, so we believe > -- that RRset is good. Furthermore the DNSKEY whose hash > is proved by the DS record is > -- one we can use. However the DNSKEY RRset may contain > more than one key and > -- one of the other keys may use an algorithm we don't > support. If that's > -- the case the zone is insecure for us. */ > -- > -- if (!(crecp = cache_find_by_name(NULL, keyname, now, > F_DNSKEY))) > -- return STAT_NEED_KEY; > - > -- do > -- { > -- if (crecp->uid == (unsigned int)class && > !verify_func(crecp->addr.key.algo)) > -- return STAT_INSECURE; > -- } > -- while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DNSKEY))); > -+ if (!gotone) > -+ return STAT_INSECURE; > - } > - > - if (name_start == 0) > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by- > one_in_DNSSEC_hostname_cmp.patch b/src/patches/dnsmasq/027- > Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch > deleted file mode 100644 > index 031339e..0000000 > --- a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by- > one_in_DNSSEC_hostname_cmp.patch > +++ /dev/null > @@ -1,27 +0,0 @@ > -From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sun, 20 Dec 2015 20:50:05 +0000 > -Subject: [PATCH] Nasty, rare and obscure off-by-one in DNSSEC > hostname_cmp(). > - > ---- > - src/dnssec.c | 4 ++-- > - 1 file changed, 2 insertions(+), 2 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index e09f304..29848e1 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1394,8 +1394,8 @@ static int hostname_cmp(const char *a, const > char *b) > - if (sb == b) > - return 1; > - > -- ea = sa--; > -- eb = sb--; > -+ ea = --sa; > -+ eb = --sb; > - } > - } > - > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch b/src/patches/dnsmasq/028- > Minor_tweak_to_previous_commit.patch > deleted file mode 100644 > index f3758fc..0000000 > --- a/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch > +++ /dev/null > @@ -1,39 +0,0 @@ > -From a86fdf437ecc29398f9715ceb5240442a17ac014 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sun, 20 Dec 2015 21:19:20 +0000 > -Subject: [PATCH] Minor tweak to previous commit. > - > ---- > - src/dnssec.c | 6 ++---- > - 1 file changed, 2 insertions(+), 4 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 29848e1..9fa64b6 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1889,8 +1889,6 @@ static int zone_status(char *name, int class, > char *keyname, time_t now) > - } > - else > - { > -- int gotone = 0; > -- > - /* If all the DS records have digest and/or sig algos we > don't support, > - then the zone is insecure. Note that if an algo > - appears in the DS, then RRSIGs for that algo MUST > -@@ -1904,11 +1902,11 @@ static int zone_status(char *name, int > class, char *keyname, time_t now) > - if (crecp->uid == (unsigned int)class && > - hash_find(ds_digest_name(crecp->addr.ds.digest)) > && > - verify_func(crecp->addr.ds.algo)) > -- gotone = 1; > -+ break; > - } > - while ((crecp = cache_find_by_name(crecp, keyname, now, > F_DS))); > - > -- if (!gotone) > -+ if (!crecp) > - return STAT_INSECURE; > - } > - > --- > -1.7.10.4 > - > diff --git a/src/patches/dnsmasq/029- > NSEC3_check_RFC5155_para_8_2.patch b/src/patches/dnsmasq/029- > NSEC3_check_RFC5155_para_8_2.patch > deleted file mode 100644 > index 33219d2..0000000 > --- a/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch > +++ /dev/null > @@ -1,39 +0,0 @@ > -From ce5732e84fc46d7f99c152f736cfb4ef5ec98a01 Mon Sep 17 00:00:00 > 2001 > -From: Simon Kelley <simon@thekelleys.org.uk> > -Date: Sun, 20 Dec 2015 21:39:19 +0000 > -Subject: [PATCH] NSEC3 check: RFC5155 para 8.2 > - > ---- > - src/dnssec.c | 8 ++++++-- > - 1 file changed, 6 insertions(+), 2 deletions(-) > - > -diff --git a/src/dnssec.c b/src/dnssec.c > -index 9fa64b6..486e422 100644 > ---- a/src/dnssec.c > -+++ b/src/dnssec.c > -@@ -1704,7 +1704,7 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - for (i = 0; i < nsec_count; i++) > - { > - unsigned char *nsec3p = nsecs[i]; > -- int this_iter; > -+ int this_iter, flags; > - > - nsecs[i] = NULL; /* Speculative, will be restored if OK. */ > - > -@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct > dns_header *header, size_t plen, uns > - if (*p++ != algo) > - continue; > - > -- p++; /* flags */ > -+ flags = *p++; /* flags */ > - > -+ /* 5155 8.2 */ > -+ if (flags != 0 && flags != 1) > -+ continue; > -+ > - GETSHORT(this_iter, p); > - if (this_iter != iterations) > - continue; > --- > -1.7.10.4 > -
Hi, On 28.02.2016 21:19, Michael Tremer wrote: > I merged this patch and the one after. > > Please give this version a good test as it is a pre-release version. Its running here. > You can maintain a branch where you integrate all new changes, but I > think it is not required to send every single one to the mailing list. > It creates a bit of noise and I think that unfortunately nobody is > testing every single one any ways. Which is sad. Yep. ;-) > Can we have maybe one aggregated patch after every release of a Core > Update? So we always have the latest version of dnsmasq in the updates? I'll do that. If not otherwise wanted, I'll send the current - patched - version after every Core Update. Best, Matthias
On Mon, 2016-02-29 at 20:22 +0100, Matthias Fischer wrote: > Hi, > > On 28.02.2016 21:19, Michael Tremer wrote: > > > > I merged this patch and the one after. > > > > Please give this version a good test as it is a pre-release > > version. > Its running here. > > > > > You can maintain a branch where you integrate all new changes, but > > I > > think it is not required to send every single one to the mailing > > list. > > It creates a bit of noise and I think that unfortunately nobody is > > testing every single one any ways. Which is sad. > Yep. ;-) > > > > > Can we have maybe one aggregated patch after every release of a > > Core > > Update? So we always have the latest version of dnsmasq in the > > updates? > I'll do that. If not otherwise wanted, I'll send the current - > patched - > version after every Core Update. > > Best, > Matthias @list: I hope to have an opportunity to test RealSoonNow via an alternate boot scheme on current hardware. Do you want me to test the i586 or the x86_64? Paul
Hi, On Mon, 2016-02-29 at 15:39 -0600, Paul Simmons wrote: > On Mon, 2016-02-29 at 20:22 +0100, Matthias Fischer wrote: > > Hi, > > > > On 28.02.2016 21:19, Michael Tremer wrote: > > > > > > I merged this patch and the one after. > > > > > > Please give this version a good test as it is a pre-release > > > version. > > Its running here. > > > > > > > > You can maintain a branch where you integrate all new changes, > > > but > > > I > > > think it is not required to send every single one to the mailing > > > list. > > > It creates a bit of noise and I think that unfortunately nobody > > > is > > > testing every single one any ways. Which is sad. > > Yep. ;-) > > > > > > > > Can we have maybe one aggregated patch after every release of a > > > Core > > > Update? So we always have the latest version of dnsmasq in the > > > updates? > > I'll do that. If not otherwise wanted, I'll send the current - > > patched - > > version after every Core Update. > > > > Best, > > Matthias > > @list: > > I hope to have an opportunity to test RealSoonNow via an alternate > boot > scheme on current hardware. > > Do you want me to test the i586 or the x86_64? Ideally both :) But as we do not release the 64 bit builds at the moment, i586 is preferred. Best, -Michael > > Paul
Is there any chance the x86_64 version will ever be released? If it is a question of testing, I will volunteer to test it. Best regards, Fred Kienker -----Original Message----- From: Michael Tremer [mailto:michael.tremer@ipfire.org] Sent: Wednesday, March 02, 2016 6:49 PM To: Paul Simmons; development@lists.ipfire.org Subject: Re: [PATCH] dnsmasq: 2.76test10 with latest patches (001-004) Hi, On Mon, 2016-02-29 at 15:39 -0600, Paul Simmons wrote: > On Mon, 2016-02-29 at 20:22 +0100, Matthias Fischer wrote: > > Hi, > > > > On 28.02.2016 21:19, Michael Tremer wrote: > > > > > > I merged this patch and the one after. > > > > > > Please give this version a good test as it is a pre-release > > > version. > > Its running here. > > > > > > > > You can maintain a branch where you integrate all new changes, but > > > I think it is not required to send every single one to the mailing > > > list. > > > It creates a bit of noise and I think that unfortunately nobody is > > > testing every single one any ways. Which is sad. > > Yep. ;-) > > > > > > > > Can we have maybe one aggregated patch after every release of a > > > Core Update? So we always have the latest version of dnsmasq in > > > the updates? > > I'll do that. If not otherwise wanted, I'll send the current - > > patched - version after every Core Update. > > > > Best, > > Matthias > > @list: > > I hope to have an opportunity to test RealSoonNow via an alternate > boot scheme on current hardware. > > Do you want me to test the i586 or the x86_64? Ideally both :) But as we do not release the 64 bit builds at the moment, i586 is preferred. Best, -Michael > > Paul
Hi, it is indeed a question of testing. We intend to release it soon, but unfortunately there is only little man power to work on an other architecture. So contribution is appreciated. Best, -Michael On Thu, 2016-03-03 at 14:06 -0500, Kienker, Fred wrote: > Is there any chance the x86_64 version will ever be released? If it > is a > question of testing, I will volunteer to test it. > > Best regards, > Fred Kienker > > -----Original Message----- > From: Michael Tremer [mailto:michael.tremer@ipfire.org] > Sent: Wednesday, March 02, 2016 6:49 PM > To: Paul Simmons; development@lists.ipfire.org > Subject: Re: [PATCH] dnsmasq: 2.76test10 with latest patches (001- > 004) > > Hi, > > On Mon, 2016-02-29 at 15:39 -0600, Paul Simmons wrote: > > On Mon, 2016-02-29 at 20:22 +0100, Matthias Fischer wrote: > > > Hi, > > > > > > On 28.02.2016 21:19, Michael Tremer wrote: > > > > > > > > I merged this patch and the one after. > > > > > > > > Please give this version a good test as it is a pre-release > > > > version. > > > Its running here. > > > > > > > > > > > You can maintain a branch where you integrate all new changes, > > > > but > > > > > I think it is not required to send every single one to the > > > > mailing > > > > > list. > > > > It creates a bit of noise and I think that unfortunately nobody > > > > is > > > > > testing every single one any ways. Which is sad. > > > Yep. ;-) > > > > > > > > > > > Can we have maybe one aggregated patch after every release of > > > > a > > > > Core Update? So we always have the latest version of dnsmasq > > > > in > > > > the updates? > > > I'll do that. If not otherwise wanted, I'll send the current - > > > patched - version after every Core Update. > > > > > > Best, > > > Matthias > > > > @list: > > > > I hope to have an opportunity to test RealSoonNow via an alternate > > boot scheme on current hardware. > > > > Do you want me to test the i586 or the x86_64? > > Ideally both :) But as we do not release the 64 bit builds at the > moment, i586 is preferred. > > Best, > -Michael > > > > > Paul >