[Dnsmasq-discuss] Extend server to accept hostnames for upstream resolver

2022-04-02 Thread Dominik Derigs
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

2022-04-02 Thread Dominik Derigs
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)

2022-04-02 Thread Petr Menšík
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)

2022-04-02 Thread Lonnie Abelbeck
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