For the records: I'm testing this one since a few days. No problems yet.
For details see: http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=summary
Signed-off-by: Matthias Fischer matthias.fischer@ipfire.org --- lfs/dnsmasq | 5 + .../051-Fix_botch_in_forward_c_flags_code.patch | 29 +++ .../052-Fix_sporadic_crash_in_find_mac.patch | 27 +++ ..._code_and_set_conntrack_on_DNSSEC_queries.patch | 270 +++++++++++++++++++++ ...ms_in_last_commit_when_DNSSEC_not_enabled.patch | 58 +++++ ...main-needed_set_and_no_servers_configured.patch | 91 +++++++ 6 files changed, 480 insertions(+) create mode 100644 src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch create mode 100644 src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch create mode 100644 src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch create mode 100644 src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch create mode 100644 src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch
diff --git a/lfs/dnsmasq b/lfs/dnsmasq index 4e5951f..5134c13 100644 --- a/lfs/dnsmasq +++ b/lfs/dnsmasq @@ -123,6 +123,11 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/048-Disable_DNSSEC_for_server_domain_servers_unless_trust-anchor_provided.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/049-arp_c_tidy_up.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/050-Complete_work_to_allow_DNSSEC_validation_with_private_DNS_servers.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch + cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
cd $(DIR_APP) && sed -i src/config.h \ diff --git a/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch b/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch new file mode 100644 index 0000000..aff7f37 --- /dev/null +++ b/src/patches/dnsmasq/051-Fix_botch_in_forward_c_flags_code.patch @@ -0,0 +1,29 @@ +From 1801a29226c53e8af3f7a0f149d3ec9f06c04f3c Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Sun, 17 Jan 2016 21:53:57 +0000 +Subject: [PATCH] Fix botch in forward.c flags code. + +Thanks to Matthias Anfree for spotting this. +--- + src/forward.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/forward.c b/src/forward.c +index c48fd75..95c5ef9 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -810,9 +810,9 @@ void reply_query(int fd, int family, time_t now) + { + header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC); + header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD); +- if (forward->flags |= FREC_CHECKING_DISABLED) ++ if (forward->flags & FREC_CHECKING_DISABLED) + header->hb4 |= HB4_CD; +- if (forward->flags |= FREC_AD_QUESTION) ++ if (forward->flags & FREC_AD_QUESTION) + header->hb4 |= HB4_AD; + if (forward->flags & FREC_DO_QUESTION) + add_do_bit(header, nn, (unsigned char *)pheader + plen); +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch b/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch new file mode 100644 index 0000000..54efae9 --- /dev/null +++ b/src/patches/dnsmasq/052-Fix_sporadic_crash_in_find_mac.patch @@ -0,0 +1,27 @@ +From f4d0c660ca403e933d51093167c0d01526c7f9d1 Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Mon, 18 Jan 2016 12:51:08 +0000 +Subject: [PATCH] Fix sporadic crash in find_mac() - hwlen must be zero for + empty entries. + +--- + src/arp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/arp.c b/src/arp.c +index 968455c..d70d2af 100644 +--- a/src/arp.c ++++ b/src/arp.c +@@ -188,7 +188,8 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now) + arps = arp; + arp->status = ARP_EMPTY; + arp->family = addr->sa.sa_family; +- ++ arp->hwlen = 0; ++ + if (addr->sa.sa_family == AF_INET) + arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr; + #ifdef HAVE_IPV6 +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch b/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch new file mode 100644 index 0000000..3f8b053 --- /dev/null +++ b/src/patches/dnsmasq/053-Complete_DNSSEC_server-selection_code_and_set_conntrack_on_DNSSEC_queries.patch @@ -0,0 +1,270 @@ +From f344dbc62216570b6471c81e4e39fc99bf47af5f Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Mon, 18 Jan 2016 18:04:17 +0000 +Subject: [PATCH] Complete DNSSEC server-selection code and set conntrack on + DNSSEC queries. + +--- + src/forward.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 121 insertions(+), 27 deletions(-) + +diff --git a/src/forward.c b/src/forward.c +index 95c5ef9..506d194 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -923,7 +923,7 @@ void reply_query(int fd, int family, time_t now) + status = STAT_ABANDONED; + else + { +- int fd, type; ++ int fd, type = SERV_DO_DNSSEC; + struct frec *next = new->next; + char *domain; + +@@ -936,7 +936,7 @@ void reply_query(int fd, int family, time_t now) + servers for domains are involved. */ + if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0) + { +- struct server *start = server; ++ struct server *start = server, *new_server = NULL; + type &= ~SERV_DO_DNSSEC; + + while (1) +@@ -945,8 +945,12 @@ void reply_query(int fd, int family, time_t now) + (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && + !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) + { +- server = start; +- break; ++ new_server = start; ++ if (server == start) ++ { ++ new_server = NULL; ++ break; ++ } + } + + if (!(start = start->next)) +@@ -954,7 +958,11 @@ void reply_query(int fd, int family, time_t now) + if (start == server) + break; + } ++ ++ if (new_server) ++ server = new_server; + } ++ + new->sentto = server; + + new->rfd4 = NULL; +@@ -1010,6 +1018,15 @@ void reply_query(int fd, int family, time_t now) + + if (fd != -1) + { ++#ifdef HAVE_CONNTRACK ++ /* Copy connection mark of incoming query to outgoing connection. */ ++ if (option_bool(OPT_CONNTRACK)) ++ { ++ unsigned int mark; ++ if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark)) ++ setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); ++ } ++#endif + while (retry_send(sendto(fd, (char *)header, nn, 0, + &server->addr.sa, + sa_len(&server->addr)))); +@@ -1072,7 +1089,7 @@ void reply_query(int fd, int family, time_t now) + else + header->hb4 &= ~HB4_CD; + +- if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, ++ if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, + forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, + forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source))) + { +@@ -1433,20 +1450,27 @@ void receive_query(struct listener *listen, time_t now) + } + + #ifdef HAVE_DNSSEC ++/* Recurse up the key heirarchy */ + static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, +- int class, char *name, char *keyname, struct server *server, int *keycount) ++ int class, char *name, char *keyname, struct server *server, ++ int have_mark, unsigned int mark, int *keycount) + { +- /* Recurse up the key heirarchy */ + int new_status; + unsigned char *packet = NULL; +- size_t m; + unsigned char *payload = NULL; + struct dns_header *new_header = NULL; + u16 *length = NULL; +- unsigned char c1, c2; ++ ++ (void)have_mark; ++ (void)mark; + + while (1) + { ++ int type = SERV_DO_DNSSEC; ++ char *domain; ++ size_t m; ++ unsigned char c1, c2; ++ + /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */ + if (--(*keycount) == 0) + new_status = STAT_ABANDONED; +@@ -1480,6 +1504,67 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si + new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz); + + *length = htons(m); ++ ++ /* Find server to forward to. This will normally be the ++ same as for the original query, but may be another if ++ servers for domains are involved. */ ++ if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) == 0) ++ { ++ struct server *start = server, *new_server = NULL; ++ type &= ~SERV_DO_DNSSEC; ++ ++ while (1) ++ { ++ if (type == (start->flags & SERV_TYPE) && ++ (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && ++ !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) ++ { ++ new_server = start; ++ if (server == start) ++ { ++ new_server = NULL; ++ break; ++ } ++ } ++ ++ if (!(start = start->next)) ++ start = daemon->servers; ++ if (start == server) ++ break; ++ } ++ ++ ++ if (new_server) ++ { ++ server = new_server; ++ /* may need to make new connection. */ ++ if (server->tcpfd == -1) ++ { ++ if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1) ++ { ++ new_status = STAT_ABANDONED; ++ break; ++ } ++ ++#ifdef HAVE_CONNTRACK ++ /* Copy connection mark of incoming query to outgoing connection. */ ++ if (have_mark) ++ setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); ++#endif ++ ++ if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) || ++ connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1) ++ { ++ close(server->tcpfd); ++ server->tcpfd = -1; ++ new_status = STAT_ABANDONED; ++ break; ++ } ++ ++ } ++ } ++ } ++ + + if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) || + !read_write(server->tcpfd, &c1, 1, 1) || +@@ -1492,7 +1577,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si + + m = (c1 << 8) | c2; + +- new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount); ++ new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount); + + if (new_status != STAT_OK) + break; +@@ -1536,10 +1621,30 @@ unsigned char *tcp_request(int confd, time_t now, + socklen_t peer_len = sizeof(union mysockaddr); + int query_count = 0; + unsigned char *pheader; ++#ifdef HAVE_CONNTRACK ++ unsigned int mark = 0; ++ int have_mark = 0; ++#endif + + if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) + return packet; +- ++ ++#ifdef HAVE_CONNTRACK ++ /* Get connection mark of incoming query to set on outgoing connections. */ ++ if (option_bool(OPT_CONNTRACK)) ++ { ++ struct all_addr local; ++#ifdef HAVE_IPV6 ++ if (local_addr->sa.sa_family == AF_INET6) ++ local.addr.addr6 = local_addr->in6.sin6_addr; ++ else ++#endif ++ local.addr.addr4 = local_addr->in.sin_addr; ++ ++ have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark); ++ } ++#endif ++ + /* We can be configured to only accept queries from at-most-one-hop-away addresses. */ + if (option_bool(OPT_LOCAL_SERVICE)) + { +@@ -1665,7 +1770,7 @@ unsigned char *tcp_request(int confd, time_t now, + { + unsigned int flags = 0; + struct all_addr *addrp = NULL; +- int type = 0; ++ int type = SERV_DO_DNSSEC; + char *domain = NULL; + size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet); + +@@ -1728,20 +1833,8 @@ unsigned char *tcp_request(int confd, time_t now, + + #ifdef HAVE_CONNTRACK + /* Copy connection mark of incoming query to outgoing connection. */ +- if (option_bool(OPT_CONNTRACK)) +- { +- unsigned int mark; +- struct all_addr local; +-#ifdef HAVE_IPV6 +- if (local_addr->sa.sa_family == AF_INET6) +- local.addr.addr6 = local_addr->in6.sin6_addr; +- else +-#endif +- local.addr.addr4 = local_addr->in.sin_addr; +- +- if (get_incoming_mark(&peer_addr, &local, 1, &mark)) +- setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); +- } ++ if (have_mark) ++ setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); + #endif + + if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) || +@@ -1802,7 +1895,8 @@ unsigned char *tcp_request(int confd, time_t now, + if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC)) + { + int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */ +- int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount); ++ int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, ++ last_server, have_mark, mark, &keycount); + char *result, *domain = "result"; + + if (status == STAT_ABANDONED) +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch b/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch new file mode 100644 index 0000000..f409038 --- /dev/null +++ b/src/patches/dnsmasq/054-Fix_problems_in_last_commit_when_DNSSEC_not_enabled.patch @@ -0,0 +1,58 @@ +From f7443d76f7b4ff1c2eb05a0313619b0a4bb8787e Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Tue, 19 Jan 2016 20:29:57 +0000 +Subject: [PATCH] Fix problems in last commit when DNSSEC not enabled. + +--- + src/forward.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/src/forward.c b/src/forward.c +index 506d194..ff0ab7e 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -331,8 +331,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + + #ifdef HAVE_DNSSEC + do_dnssec = type & SERV_DO_DNSSEC; +- type &= ~SERV_DO_DNSSEC; +-#endif ++#endif ++ type &= ~SERV_DO_DNSSEC; + + if (!flags && !(forward = get_new_frec(now, NULL, 0))) + /* table full - server failure. */ +@@ -1461,9 +1461,6 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si + struct dns_header *new_header = NULL; + u16 *length = NULL; + +- (void)have_mark; +- (void)mark; +- + while (1) + { + int type = SERV_DO_DNSSEC; +@@ -1621,10 +1618,8 @@ unsigned char *tcp_request(int confd, time_t now, + socklen_t peer_len = sizeof(union mysockaddr); + int query_count = 0; + unsigned char *pheader; +-#ifdef HAVE_CONNTRACK + unsigned int mark = 0; + int have_mark = 0; +-#endif + + if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) + return packet; +@@ -1783,9 +1778,7 @@ unsigned char *tcp_request(int confd, time_t now, + if (gotname) + flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); + +-#ifdef HAVE_DNSSEC + type &= ~SERV_DO_DNSSEC; +-#endif + + if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server) + last_server = daemon->servers; +-- +1.7.10.4 + diff --git a/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch b/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch new file mode 100644 index 0000000..9eea14a --- /dev/null +++ b/src/patches/dnsmasq/055-Fix_wrong_reply_to_simple_name_when_--domain-needed_set_and_no_servers_configured.patch @@ -0,0 +1,91 @@ +From d05dd58de1113bb99060af2772247a45ceb3a1ad Mon Sep 17 00:00:00 2001 +From: Simon Kelley simon@thekelleys.org.uk +Date: Tue, 19 Jan 2016 21:23:30 +0000 +Subject: [PATCH] Fix wrong reply to simple name when --domain-needed set and + no servers configured. + +Also return REFUSED and not SERVFAIL when out of memory. + +Thanks to Allain Legacy for problem report. +--- + CHANGELOG | 9 +++++++++ + src/forward.c | 13 +++++++------ + src/rfc1035.c | 4 +--- + 3 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/CHANGELOG b/CHANGELOG +index dcaa699..d3cf909 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -22,6 +22,15 @@ version 2.76 + reading a hosts-file fails. Thanks to André Glüpker + for the patch. + ++ Fix wrong answer to simple name query when --domain-needed ++ set, but no upstream servers configured. Dnsmasq returned ++ REFUSED, in this case, when it should be the same as when ++ upstream servers are configured - NOERROR. Thanks to ++ Allain Legacy for spotting the problem. ++ ++ Return REFUSED when running out of forwarding table slots, ++ not SERVFAIL. ++ + + version 2.75 + Fix reversion on 2.74 which caused 100% CPU use when a +diff --git a/src/forward.c b/src/forward.c +index ff0ab7e..414f988 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -249,9 +249,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + (void)do_bit; + + /* may be no servers available. */ +- if (!daemon->servers) +- forward = NULL; +- else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))) ++ if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))) + { + /* If we didn't get an answer advertising a maximal packet in EDNS, + fall back to 1280, which should work everywhere on IPv6. +@@ -334,9 +332,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + #endif + type &= ~SERV_DO_DNSSEC; + +- if (!flags && !(forward = get_new_frec(now, NULL, 0))) +- /* table full - server failure. */ +- flags = F_NEG; ++ if (daemon->servers && !flags) ++ forward = get_new_frec(now, NULL, 0); ++ /* table full - flags == 0, return REFUSED */ + + if (forward) + { +@@ -1621,6 +1619,9 @@ unsigned char *tcp_request(int confd, time_t now, + unsigned int mark = 0; + int have_mark = 0; + ++ (void)mark; ++ (void)have_mark; ++ + if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) + return packet; + +diff --git a/src/rfc1035.c b/src/rfc1035.c +index 55dec48..9c0ddb5 100644 +--- a/src/rfc1035.c ++++ b/src/rfc1035.c +@@ -896,9 +896,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen, + header->nscount = htons(0); + header->arcount = htons(0); + header->ancount = htons(0); /* no answers unless changed below */ +- if (flags == F_NEG) +- SET_RCODE(header, SERVFAIL); /* couldn't get memory */ +- else if (flags == F_NOERR) ++ if (flags == F_NOERR) + SET_RCODE(header, NOERROR); /* empty domain */ + else if (flags == F_NXDOMAIN) + SET_RCODE(header, NXDOMAIN); +-- +1.7.10.4 +