[Dnsmasq-discuss] Extend server to accept hostnames for upstream resolver
Dear Simon, In docker swarm and compose configurations, other containers are only reachable via hostnames. It is not always possible to assign IP addresses beforehand. Hence, the upstream server IP is not known at dnsmasq start when the upstream is part of the deployed configuration, e.g., a local cloudflared or unbound container. So far, getting dnsmasq to run in such a case requires hacks that somehow try to determine the IP address before starting dnsmasq. An example for such a hack (not invented by me): https://github.com/tschaffter/docker-dnsmasq/blob/54b5d5d551746b6f1708fbf4a705e2de66c2eaee/docker-entrypoint.sh#L14-L23 This patch implements name resolution functionality for server=... by querying the system resolver for a hostname. It is only used when a user supplied something that is not a valid IP address (dnsmasq currently fails hard in this case so this isn't a breaking change) and can be omitted by a compile time flag (I think it's worthwhile to have it). I know my proposal does sound somewhat strange (resolving a DNS server name) but this is something that is somewhat frequently needed and currently only possible through external hacks. From 93f597e943283124af2e39620e748635cc6a04d6 Mon Sep 17 00:00:00 2001 From: Dominik Derigs Date: Thu, 3 Feb 2022 16:12:16 +0100 Subject: [PATCH] Extend server to accept hostnames for upstream resolver Signed-off-by: DL6ER --- man/dnsmasq.8 | 4 +++ src/config.h | 3 +++ src/option.c | 69 ++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 9af4ec8..87486a5 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -511,6 +511,10 @@ The query-port flag is ignored for any servers which have a source address specified but the port may be specified directly as part of the source address. Forcing queries to an interface is not implemented on all platforms supported by dnsmasq. + +If dnsmasq is compiled with HAVE_RESOLVESERVER, the upstream server may be specified with a hostname +rather than an IP address. In this case, dnsmasq will try to use the system resolver to get the IP +address of a server during startup. If name resolution fails, starting dnsmasq fails. .TP .B --rev-server=[/][,][#][@][@[#]] This is functionally the same as diff --git a/src/config.h b/src/config.h index 227fb1f..20b9487 100644 --- a/src/config.h +++ b/src/config.h @@ -138,6 +138,9 @@ HAVE_LOOP HAVE_INOTIFY use the Linux inotify facility to efficiently re-read configuration files. +HAVE_RESOLVESERVER + lookup servers if specified via hostnames instead of IP addresses. + NO_ID Don't report *.bind CHAOS info to clients, forward such requests upstream instead. NO_TFTP diff --git a/src/option.c b/src/option.c index 5230eaf..bf1087a 100644 --- a/src/option.c +++ b/src/option.c @@ -19,6 +19,10 @@ #include "dnsmasq.h" #include +#ifdef HAVE_RESOLVESERVER +#include +#endif + static volatile int mem_recover = 0; static jmp_buf mem_jmp; static int one_file(char *file, int hard_opt); @@ -846,6 +850,11 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a char *interface_opt = NULL; int scope_index = 0; char *scope_id; + int addr_type = 0; +#ifdef HAVE_RESOLVESERVER + int ecode = 0; + struct addrinfo *hostinfo, hints = { 0 }; +#endif *interface = 0; @@ -882,6 +891,64 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a } if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) + addr_type = AF_INET; + else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0) + addr_type = AF_INET6; +#ifdef HAVE_RESOLVESERVER + /* if the argument is neither an IPv4 not an IPv6 address, it might be a + hostname and we should try to resolve it to a suitable address */ + else +{ + memset(&hints, 0, sizeof(hints)); + /* The AI_ADDRCONFIG flag ensures that then IPv4 addresses are returned in + the result only if the local system has at least one IPv4 address + configured, and IPv6 addresses are returned only if the local system + has at least one IPv6 address configured. The loopback address is not + considered for this case as valid as a configured address. This flag is + useful on, for example, IPv4-only systems, to ensure that getaddrinfo() + does not return IPv6 socket addresses that would always fail in + subsequent connect() or bind() attempts. */ + hints.ai_flags = AI_ADDRCONFIG; +#if defined(HAVE_IDN) && defined(AI_IDN) + /* If the AI_IDN flag is specified and we have glibc 2.3.4 or newer, then + the node name given in node is converted to IDN format if necessary. + The source encoding is that of the current locale. */ + hints.ai_flags |= AI_IDN; +#endif + /* The value AF_UNSPEC indicates that getaddrinfo() should return socket + addresses for any address family (either IPv
[Dnsmasq-discuss] Fwd: [PATCH] Addressing hostsdir shortcomings
Dear Simon, Second resubmission of my patches. They still apply cleanly to current master. Best, Dominik Forwarded Message From: Dominik Derigs To: dnsmasq-discuss@lists.thekelleys.org.uk , Simon Kelley Subject: [PATCH] Addressing hostsdir shortcomings Date: Sat, 08 Jan 2022 11:45:32 +0100 Hey Simon, dnsmasq v2.73 added --hostsdir which is an efficient way of re- loading only parts of the cache. When we tried to use hostsdir yesterday, we identified three problems. They are described below. Patches addressing them are attached. --- ISSUE 1 --- Logging imprecision Assume you have multiple files in hostsdir, dnsmasq can only log the directory not the file that was the real source: dnsmasq: read /home/test/hostsdir/hosts1 - 1 addresses dnsmasq: read /home/test/hostsdir/hosts2 - 1 addresses dnsmasq: read /home/test/hostsdir/hosts3 - 1 addresses dnsmasq: 1 127.0.0.1/34170 query[A] aaa from 127.0.0.1 dnsmasq: 1 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 1 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.1 dnsmasq: 1 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 This happens because the cache entries all use the same index that is the directory name. --- ISSUE 2 --- Outdated entries are not removed When hostsdir re-reads the file, it does not remove outdated entries. Assume you modify "192.168.1.1 aaa" to "192.168.1.2 aaa", dnsmasq will now serve two A records for "aaa". This may be considered okay, however, if I add "192.168.1.1 bbb", PTR requests for this domain will still be replied with "aaa" which might be completely outdated information. --- ISSUE 3 --- Ever growing replies under certain situations When a users uses an editor that creates (temporary) files during editing (like "sed -i") or uses a script that writes files line by line (like "echo '' >> file"), they can quickly end up with strange things like dnsmasq: 3 127.0.0.1/34170 query[A] aaa from 127.0.0.1 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.1 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 dnsmasq: 3 127.0.0.1/34170 /home/test/hostsdir aaa is 192.168.1.2 which is not very meaningful. We check for duplicates before inserting into the cache, however, duplicate checking can be foiled here: add_hosts_entry() calls cache_find_by_name() only once (say it returned "192.168.1.1") so the memcmp() on the address fails and we can add an arbitrary amount of 192.168.1.2 entries. For addressing issue 1, I added a new struct *dyndir having a linked list of struct *hostsfile. With this, cache_insert() can get the correct index. If a file is newly added, we just add a new *hostsfile entry to the list (index++). Issue 2 is an easy one as we can selectively clean the cache when we know the uid to be removed. This can be called before running read_hostsfile() to insert new stuff. I added MOVE_FROM and DELETE to inotify_add_watch() so we catch if a file was removed. In this case, we only remove old entries. Issue 3 is fixed by adding a loop over cache_find_by_name() in add_hosts_entry() to check possible multiple records. Best, Dominik [sent earlier as https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q3/015704.html , resubmitting patches rebased on latest master] From 7873cc3dbfce3edeb534bf4d0a0030894aaa152a Mon Sep 17 00:00:00 2001 From: Dominik Derigs Date: Wed, 29 Sep 2021 08:22:05 +0200 Subject: [PATCH 1/3] Extend hostsdir to store the individual files as sources for loggin Signed-off-by: DL6ER --- src/cache.c | 9 +++-- src/dnsmasq.h | 13 ++- src/inotify.c | 103 ++ src/option.c | 40 4 files changed, 111 insertions(+), 54 deletions(-) diff --git a/src/cache.c b/src/cache.c index 246c3f2..e86d69b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1839,6 +1839,7 @@ void dump_cache(time_t now) char *record_source(unsigned int index) { struct hostsfile *ah; + struct dyndir *dd; if (index == SRC_CONFIG) return "config"; @@ -1850,9 +1851,11 @@ char *record_source(unsigned int index) return ah->fname; #ifdef HAVE_INOTIFY - for (ah = daemon->dynamic_dirs; ah; ah = ah->next) - if (ah->index == index) - return ah->fname; + /* Dynamic directories contain multiple files */ + for (dd = daemon->dynamic_dirs; dd; dd = dd->next) +for (ah = dd->files; ah; ah = ah->next) + if (ah->index == index) + return ah->fname; #endif return ""; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 1b00298..c6efb6b 100644 --- a/src/dnsmasq.h +++
Re: [Dnsmasq-discuss] [PATCH] Heap use after free in dhcp6_no_relay (CVE-2022-0934)
Hi Lonnie, I made just quick evaluation, but it does not seem possible. It happens during creating a reply to dhcp message. ra-only ranges should not create DHCP range, which would accept incoming message. It should log message "no address range available for DHCPv6 request" followed by some detail. If it does so, then it avoids function where only it may happen. If no DHCP6 messages are involved, this vulnerability cannot be triggered. ra-only should only broadcast its prefix(es) to end stations without accepting messages from them. It should be safe. Regards, Petr On 4/1/22 16:37, Lonnie Abelbeck wrote: >> On Mar 31, 2022, at 2:04 PM, Petr Menšík wrote: >> >> Possible vulnerability were found in latest dnsmasq. It were found with help >> of oss-fuzz Google project by me and short after that independently also by >> Richard Johnson of Trellix Threat Labs. >> >> It is affected only by DHCPv6 requests, which could be crafted to modify >> already freed memory. Red Hat security assigned this vulnerability >> CVE-2022-0934. > Are dnsmasq IPv6 configs *only* using "ra-only" (ex.): > -- > dhcp-range=...,ra-only,64,24h > -- > Immune from CVE-2022-0934 ? > > Lonnie > -- Petr Menšík Software Engineer Red Hat, http://www.redhat.com/ email: pemen...@redhat.com PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB ___ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss
Re: [Dnsmasq-discuss] [PATCH] Heap use after free in dhcp6_no_relay (CVE-2022-0934)
Hey Petr, Your analysis is much appreciated! Thank you. Lonnie > On Apr 2, 2022, at 10:01 AM, Petr Menšík wrote: > > Hi Lonnie, > > I made just quick evaluation, but it does not seem possible. It happens > during creating a reply to dhcp message. ra-only ranges should not > create DHCP range, which would accept incoming message. It should log > message "no address range available for DHCPv6 request" followed by some > detail. If it does so, then it avoids function where only it may happen. > > If no DHCP6 messages are involved, this vulnerability cannot be > triggered. ra-only should only broadcast its prefix(es) to end stations > without accepting messages from them. It should be safe. > > Regards, > Petr > > On 4/1/22 16:37, Lonnie Abelbeck wrote: >>> On Mar 31, 2022, at 2:04 PM, Petr Menšík wrote: >>> >>> Possible vulnerability were found in latest dnsmasq. It were found with >>> help of oss-fuzz Google project by me and short after that independently >>> also by Richard Johnson of Trellix Threat Labs. >>> >>> It is affected only by DHCPv6 requests, which could be crafted to modify >>> already freed memory. Red Hat security assigned this vulnerability >>> CVE-2022-0934. >> Are dnsmasq IPv6 configs *only* using "ra-only" (ex.): >> -- >> dhcp-range=...,ra-only,64,24h >> -- >> Immune from CVE-2022-0934 ? >> >> Lonnie >> > -- > Petr Menšík > Software Engineer > Red Hat, http://www.redhat.com/ > email: pemen...@redhat.com > PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB > > ___ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss