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