Signed-off-by: Matthias Fischer matthias.fischer@ipfire.org --- lfs/dnsmasq | 4 + ...orwarding_to_private_servers_for_a_domain.patch | 41 ++++ ...ors_and_check_we_have_a_root-trust_anchor.patch | 70 +++++++ ...ze_calculation_when_hosts-file_read_fails.patch | 41 ++++ ...main_servers_unless_trust-anchor_provided.patch | 217 +++++++++++++++++++++ 5 files changed, 373 insertions(+) create mode 100644 src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch create mode 100644 src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch create mode 100644 src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch create mode 100644 src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch
diff --git a/lfs/dnsmasq b/lfs/dnsmasq index e145a39..0affcf5 100644 --- a/lfs/dnsmasq +++ b/lfs/dnsmasq @@ -117,6 +117,10 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/042-Handle_building_with_script_support_enabled_and_DHCP_disabled.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/043-Update_copyright_notices_Happy_new_year.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/044-Fix_FTBFS_when_scripts_excluded_at_compilation_time.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
cd $(DIR_APP) && sed -i src/config.h \ diff --git a/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch b/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch new file mode 100644 index 0000000..11cf20a --- /dev/null +++ b/src/patches/dnsmasq/045-Inhibit_DNSSEC_validation_when_forwarding_to_private_servers_for_a_domain.patch @@ -0,0 +1,41 @@ +From 5757371d43891e830abe19aacae5378a79c7851c Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Mon, 11 Jan 2016 22:50:00 +0000 +Subject: [PATCH] Inhibit DNSSEC validation when forwarding to private servers + for a domain. + +server=/example.com/<ip-of-server> + +The rationale is that the chain-of-trust will not be complete to +private servers. If it was, it would not be necessary to access the +server direct. +--- + src/forward.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/forward.c b/src/forward.c +index 47c6ded..1458578 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -406,7 +406,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + } + + #ifdef HAVE_DNSSEC +- if (option_bool(OPT_DNSSEC_VALID)) ++ if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN)) + { + size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ); + +@@ -858,7 +858,8 @@ void reply_query(int fd, int family, time_t now) + no_cache_dnssec = 1; + + #ifdef HAVE_DNSSEC +- if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED)) ++ if (server && !(server->flags & SERV_HAS_DOMAIN) && ++ option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED)) + { + int status = 0; + +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch b/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch new file mode 100644 index 0000000..b58b6d2 --- /dev/null +++ b/src/patches/dnsmasq/046-DNSSEC_Handle_non-root_trust_anchors_and_check_we_have_a_root-trust_anchor.patch @@ -0,0 +1,70 @@ +From a63b8b89e66a097fca7cba3efc7923636574ec2c Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Tue, 12 Jan 2016 11:28:58 +0000 +Subject: [PATCH] DNSSEC: Handle non-root trust anchors, and check we have a + root trust anchor. + +--- + src/dnsmasq.c | 12 ++++++++++-- + src/dnssec.c | 19 ++++++++++++++++++- + 2 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/src/dnsmasq.c b/src/dnsmasq.c +index 8032fc7..e993629 100644 +--- a/src/dnsmasq.c ++++ b/src/dnsmasq.c +@@ -169,8 +169,16 @@ int main (int argc, char **argv) + if (option_bool(OPT_DNSSEC_VALID)) + { + #ifdef HAVE_DNSSEC +- if (!daemon->ds) +- die(_("no trust anchors provided for DNSSEC"), NULL, EC_BADCONF); ++ struct ds_config *ds; ++ ++ /* Must have at least a root trust anchor, or the DNSSEC code ++ can loop forever. */ ++ for (ds = daemon->ds; ds; ds = ds->next) ++ if (ds->name[0] == 0) ++ break; ++ ++ if (!ds) ++ die(_("no root trust anchor provided for DNSSEC"), NULL, EC_BADCONF); + + if (daemon->cachesize < CACHESIZ) + die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF); +diff --git a/src/dnssec.c b/src/dnssec.c +index a432ebf..18efa59 100644 +--- a/src/dnssec.c ++++ b/src/dnssec.c +@@ -1873,10 +1873,27 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key + */ + static int zone_status(char *name, int class, char *keyname, time_t now) + { +- int name_start = strlen(name); ++ int name_start = strlen(name); /* for when TA is root */ + struct crec *crecp; + char *p; ++ ++ /* First, work towards the root, looking for a trust anchor. ++ This can either be one configured, or one previously cached. ++ We can assume, if we don't find one first, that there is ++ a trust anchor at the root. */ ++ for (p = name; p; p = strchr(p, '.')) ++ { ++ if (*p == '.') ++ p++; ++ ++ if (cache_find_by_name(NULL, p, now, F_DS)) ++ { ++ name_start = p - name; ++ break; ++ } ++ } + ++ /* Now work away from the trust anchor */ + while (1) + { + strcpy(keyname, &name[name_start]); +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch b/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch new file mode 100644 index 0000000..71db7e7 --- /dev/null +++ b/src/patches/dnsmasq/047-Fix_bad_cache-size_calculation_when_hosts-file_read_fails.patch @@ -0,0 +1,41 @@ +From eddf3652845b30236a99187db19d13bc6d1f282d Mon Sep 17 00:00:00 2001 +From: =?utf8?q?Andr=C3=A9=20Gl=C3=BCpker?= andre.gluepker@st.ovgu.de +Date: Tue, 12 Jan 2016 12:54:17 +0000 +Subject: [PATCH] Fix bad cache-size calculation when hosts-file read fails. + +--- + CHANGELOG | 4 ++++ + src/cache.c | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/CHANGELOG b/CHANGELOG +index 93c73d0..dcaa699 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -18,6 +18,10 @@ version 2.76 + that the same name is empty. Thanks to Edwin Török for + the patch. + ++ Fix failure to correctly calculate cache-size when ++ reading a hosts-file fails. Thanks to André Glüpker ++ for the patch. ++ + + version 2.75 + Fix reversion on 2.74 which caused 100% CPU use when a +diff --git a/src/cache.c b/src/cache.c +index d4b71a5..a9eaa65 100644 +--- a/src/cache.c ++++ b/src/cache.c +@@ -919,7 +919,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr + if (!f) + { + my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno)); +- return 0; ++ return cache_size; + } + + eatspace(f); +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch b/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch new file mode 100644 index 0000000..62d4f8d --- /dev/null +++ b/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch @@ -0,0 +1,217 @@ +From 367341f7456c33c66142d66b0e76c56d53bca4f2 Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Tue, 12 Jan 2016 15:58:23 +0000 +Subject: [PATCH] Disable DNSSEC for server=/domain/.. servers unless + trust-anchor provided. + +--- + src/dnsmasq.h | 1 + + src/dnssec.c | 2 +- + src/forward.c | 30 ++++++++++++++++++++++-------- + src/network.c | 38 ++++++++++++++++++++++++++++++++++---- + 4 files changed, 58 insertions(+), 13 deletions(-) + +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index b2d1c5e..543481c 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -477,6 +477,7 @@ union mysockaddr { + #define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */ + #define SERV_FROM_FILE 4096 /* read from --servers-file */ + #define SERV_LOOP 8192 /* server causes forwarding loop */ ++#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */ + + struct serverfd { + int fd; +diff --git a/src/dnssec.c b/src/dnssec.c +index 18efa59..ebb9c93 100644 +--- a/src/dnssec.c ++++ b/src/dnssec.c +@@ -1892,7 +1892,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now) + break; + } + } +- ++ + /* Now work away from the trust anchor */ + while (1) + { +diff --git a/src/forward.c b/src/forward.c +index 1458578..11c0d45 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -106,8 +106,8 @@ int send_from(int fd, int nowild, char *packet, size_t len, + return 1; + } + +-static unsigned int search_servers(time_t now, struct all_addr **addrpp, +- unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind) ++static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype, ++ char *qdomain, int *type, char **domain, int *norebind) + + { + /* If the query ends in the domain in one of our servers, set +@@ -175,7 +175,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, + + if (domainlen >= matchlen) + { +- *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND); ++ *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC); + *domain = serv->domain; + matchlen = domainlen; + if (serv->flags & SERV_NO_ADDR) +@@ -233,12 +233,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + struct frec *forward, int ad_reqd, int do_bit) + { + char *domain = NULL; +- int type = 0, norebind = 0; ++ int type = SERV_DO_DNSSEC, norebind = 0; + struct all_addr *addrp = NULL; + unsigned int flags = 0; + struct server *start = NULL; + #ifdef HAVE_DNSSEC + void *hash = hash_questions(header, plen, daemon->namebuff); ++ int do_dnssec = 0; + #else + unsigned int crc = questions_crc(header, plen, daemon->namebuff); + void *hash = &crc; +@@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + daemon->last_server = NULL; + } + type = forward->sentto->flags & SERV_TYPE; ++#ifdef HAVE_DNSSEC ++ do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC; ++#endif ++ + if (!(start = forward->sentto->next)) + start = daemon->servers; /* at end of list, recycle */ + header->id = htons(forward->new_id); +@@ -324,6 +329,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + if (gotname) + flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); + ++#ifdef HAVE_DNSSEC ++ do_dnssec = type & SERV_DO_DNSSEC; ++ type &= ~SERV_DO_DNSSEC; ++#endif ++ + if (!flags && !(forward = get_new_frec(now, NULL, 0))) + /* table full - server failure. */ + flags = F_NEG; +@@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + } + + #ifdef HAVE_DNSSEC +- if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN)) ++ if (option_bool(OPT_DNSSEC_VALID) && do_dnssec) + { + size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ); + +@@ -858,7 +868,7 @@ void reply_query(int fd, int family, time_t now) + no_cache_dnssec = 1; + + #ifdef HAVE_DNSSEC +- if (server && !(server->flags & SERV_HAS_DOMAIN) && ++ if (server && (server->flags & SERV_DO_DNSSEC) && + option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED)) + { + int status = 0; +@@ -1640,6 +1650,10 @@ unsigned char *tcp_request(int confd, time_t now, + if (gotname) + flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); + ++#ifdef HAVE_DNSSEC ++ type &= ~SERV_DO_DNSSEC; ++#endif ++ + if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server) + last_server = daemon->servers; + else +@@ -1711,7 +1725,7 @@ unsigned char *tcp_request(int confd, time_t now, + } + + #ifdef HAVE_DNSSEC +- if (option_bool(OPT_DNSSEC_VALID)) ++ if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC)) + { + new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536); + +@@ -1757,7 +1771,7 @@ unsigned char *tcp_request(int confd, time_t now, + #endif + + #ifdef HAVE_DNSSEC +- if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled) ++ if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC)) + { + int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */ + int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount); +diff --git a/src/network.c b/src/network.c +index 66b91ad..303ae50 100644 +--- a/src/network.c ++++ b/src/network.c +@@ -1430,12 +1430,38 @@ void check_servers(void) + if (!option_bool(OPT_NOWILD)) + enumerate_interfaces(0); + ++#ifdef HAVE_DNSSEC ++ /* Disable DNSSEC validation when using server=/domain/.... servers ++ unless there's a configured trust anchor. */ ++ for (serv = daemon->servers; serv; serv = serv->next) ++ serv->flags |= SERV_DO_DNSSEC; ++#endif ++ + for (serv = daemon->servers; serv; serv = serv->next) + { +- if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) ++ if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) + { +- port = prettyprint_addr(&serv->addr, daemon->namebuff); ++#ifdef HAVE_DNSSEC ++ if (option_bool(OPT_DNSSEC_VALID) && (serv->flags & SERV_HAS_DOMAIN)) ++ { ++ struct ds_config *ds; ++ char *domain = serv->domain; ++ ++ /* .example.com is valid */ ++ while (*domain == '.') ++ domain++; ++ ++ for (ds = daemon->ds; ds; ds = ds->next) ++ if (ds->name[0] != 0 && hostname_isequal(domain, ds->name)) ++ break; + ++ if (!ds) ++ serv->flags &= ~SERV_DO_DNSSEC; ++ } ++#endif ++ ++ port = prettyprint_addr(&serv->addr, daemon->namebuff); ++ + /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */ + if (serv->addr.sa.sa_family == AF_INET && + serv->addr.in.sin_addr.s_addr == 0) +@@ -1471,7 +1497,11 @@ void check_servers(void) + { + if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV)) + { +- char *s1, *s2; ++ char *s1, *s2, *s3 = ""; ++#ifdef HAVE_DNSSEC ++ if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC)) ++ s3 = _("(no DNSSEC)"); ++#endif + if (!(serv->flags & SERV_HAS_DOMAIN)) + s1 = _("unqualified"), s2 = _("names"); + else if (strlen(serv->domain) == 0) +@@ -1484,7 +1514,7 @@ void check_servers(void) + else if (serv->flags & SERV_USE_RESOLV) + my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2); + else +- my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2); ++ my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3); + } + #ifdef HAVE_LOOP + else if (serv->flags & SERV_LOOP) +-- +1.7.10.4 +