On 9/19/21 01:03, Simon Kelley wrote:
> On 16/09/2021 07:29, Todd Derr wrote:
>> Hi, first time poster and I'm relatively new to dnsmasq. I'm using
>> dnsmasq from brew on MacOS; I recently upgraded and ran into an issue
>> with a name that has a v4 address but no v6 address, like so:
>>
>>     log-queries
>>     log-facility=/usr/local/var/log/dnsmasq.log
>>     address=/dummy.com/127.0.0.2 <http://dummy.com/127.0.0.2>
>>
>> On 2.85 and below, the A query is answered and the AAAA returns NODATA:
>>
>>     Sep 13 16:29:38 dnsmasq[68]: query[A] dummy.com <http://dummy.com>
>>     from 127.0.0.1
>>     Sep 13 16:29:38 dnsmasq[68]: config dummy.com <http://dummy.com> is
>>     127.0.0.2
>>     Sep 13 16:29:38 dnsmasq[68]: query[AAAA] dummy.com
>>     <http://dummy.com> from 127.0.0.1
>>     Sep 13 16:29:38 dnsmasq[68]: config dummy.com <http://dummy.com> is
>>     NODATA-IPv6
>>
>>
>> Whereas on 2.86 the AAAA query gets forwarded to the system nameservers:
>>
>>     Sep 14 20:50:08 dnsmasq[31529]: query[A] dummy.com
>>     <http://dummy.com> from 127.0.0.1
>>     Sep 14 20:50:08 dnsmasq[31529]: config dummy.com <http://dummy.com>
>>     is 127.0.0.2
>>     Sep 14 20:50:08 dnsmasq[31529]: query[AAAA] dummy.com
>>     <http://dummy.com> from 127.0.0.1
>>     Sep 14 20:50:08 dnsmasq[31529]: forwarded dummy.com
>>     <http://dummy.com> to 8.8.8.8
>>     Sep 14 20:50:08 dnsmasq[31529]: forwarded dummy.com
>>     <http://dummy.com> to 8.8.4.4
>>     Sep 14 20:50:08 dnsmasq[31529]: reply dummy.com <http://dummy.com>
>>     is <CNAME>
>>     Sep 14 20:50:08 dnsmasq[31529]: reply odrfn4em.cname.us.ngrok.io
>>     <http://odrfn4em.cname.us.ngrok.io> is 2600:1f16:d83:1202::6e:5
>>
>> Was this an intentional change in behavior?  I didn't see anything in
>> the CHANGELOG and haven't tried to look through the code changes yet.
> The whole implementation of this got re-written for 2.86, but the
> intention was not to actually change behaviour.  It looks like this
> slipped through.
>
> I'm in a quandary about if this change is a bad thing, or not. In
> general the dnsmasq philosophy is that you configure stuff that you want
> it to overlay on the public DNS, and everything else gets passed through
> unchanged. It is, for instance, the case that if you put an IPV4 address
> in /etc/hosts but not an IPv6 address, then AAAA queries will be passed
> through, and all versions of dnsmasq forever have done that.
Sure, backward compatibility is important. I am not sure it always makes
sense to forward AAAA queries on locally defined A records. Especially
since --address serves similar purpose, but its behavior is opposite. I
think it might be nice if desired mode could be changed by configuration
options. But unless new options are used, existing configuration from
previous version should behave the same way, unless it was a bug.
>
> In 2.86, there's a defined priority list for domains, so the behaviour
> you want is easy to define
>
> address=/dummy.com/127.0.0.2
> local=/dummy.com/
>
> For A queries, the first line has priority, for all others, the second
> line returns NODATA*
>
>
> *Actually, NODATA comes from the combination of both lines; the second
> by itself would generate NXDOMAIN.
>
>
> TL;DR The new behaviour is a regression, and an unintended one. But the
> new behaviour is more consistent and well defined and allows for a
> different configuration which provides the old behaviour if required.
>
> Maybe better documentation is the solution?

I would consider it a regression. Because even quite old 2.79 release
behaves consistently the same way, this seems quite significant behavior
change. Could --address include also local by default, but allow current
way via modified syntax? For example:

address=/dummy.com/127.0.0.2,only # keep current behavior, similar to
host-record
address=/example.com/::1 # works the same way as up to 2.85

Especially because it can leak previously blocked queries to upstream
servers, which can be used for malicious purposes.

I would have sent a patch, but I were unable to to solve filters in
domain-match.c for it to behave the original way. But I just
reimplemented what Simon has offered as a workaround. It adds a new
unnecessary --local serv_local structure, but is simple enough. So
attached is minimalistic version. I think signalling via SERV_ flags
should be used instead, but I failed to find working way to do it.

>
>
> Cheers,
>
> Simon.
>> Is there any way to disable it? As a workaround I added this to the
>> config, which may have the same basic effect as NODATA but it's hacky
>> and worries me a bit:
>>
>>     address=/dummy.com/ <http://dummy.com/>:: 
>>
> See above.
>
>> The actual problem this caused is kind of comical in retrospect but
>> bewildering and frustrating until I figured it out:
>> * Since the initial A query still returns the expected v4 address
>> (127.0.0.2), the HTTP request that triggered the lookup succeeded.
>> * However, since the AAAA query contains a CNAME, the resolver dutifully
>> looks up the v4 address for that CNAME and effectively poisons the cache
>> and makes future requests fail (since the ngrok tunnel is not up)
>> * Adding to the fun, since ping only does the A query, it didn't perturb
>> the state of the cache.
>> * The TTL for the CNAME is 1 hour
>>
>> add that all up, and I had this running in a terminal and would see the
>> address spontaneously change for reasons that took me quite a while to
>> discern:
>>
>>     while true; do echo "$(date) $(ping -c1 -t1 dummy.com
>>     <http://dummy.com> | head -1)"; sleep 1; done
>>
>>
>> it was a wild ride, thanks for following along and I hope you had a
>> laugh at my expense.
> We're not laughing. We like a thorough analysis of the problem, and that
> is one.
It is true common resolvers like BIND9 or Unbound work only in terms of
zones. AFAIK it is impossible for them to allow CNAME on single query
type but respond without CNAME on another type for the same name. I
guess this is a price paid for working without zones concept, just on
per-query level. Ideally we would cache CNAME also with original query
type and use that cache record only for that type, always together.
Never use it for different types. We rely on upstream recursive resolver
to deliver it anyway.
>
>
>> todd.
>>
Regards,

Petr

-- 
Petr Menšík
Software Engineer
Red Hat, http://www.redhat.com/
email: pemen...@redhat.com
PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB
From 67f1eefdd921a1f67172d02cb5975d03eeac72fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com>
Date: Sat, 2 Oct 2021 00:52:26 +0200
Subject: [PATCH] Fall back to previous release behaviour
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Change default behaviour of --address back to 2.85 and previous
behaviour. Add a new way to specify new functionality, which might be
useful also. Document the change in manual.

Signed-off-by: Petr Menšík <pemen...@redhat.com>
---
 man/dnsmasq.8 |  5 +++--
 src/option.c  | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 1d4993c..457667a 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -514,7 +514,7 @@ is exactly equivalent to
 .B --server=/3.2.1.in-addr.arpa/192.168.0.1
 Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is omitted, dnsmasq substitutes either 32 (IPv4) or 128 (IPv6).
 .TP
-.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
+.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>[,only]]
 Specify an IP address to return for any host in the given domains.
 Queries in the domains are never forwarded and always replied to
 with the specified IP address which may be IPv4 or IPv6. To give
@@ -537,7 +537,8 @@ address of 0.0.0.0 and its IPv6 equivalent of :: so
 \fB--address=/example.com/#\fP will return NULL addresses for example.com and
 its subdomains. This is partly syntactic sugar for \fB--address=/example.com/0.0.0.0\fP
 and \fB--address=/example.com/::\fP but is also more efficient than including both
-as separate configuration lines. Note that NULL addresses normally work in the same way as localhost, so beware that clients looking up these names are likely to end up talking to themselves.
+as separate configuration lines. Note that NULL addresses normally work in the same way as localhost, so beware that clients looking up these names are likely to end up talking to themselves. If <ipaddr>,only is used,
+only queries to ipaddr address family are replaced. Other query types are left unaffected.
 .TP
 .B --ipset=/<domain>[/<domain>...]/<ipset>[,<ipset>...]
 Places the resolved IP addresses of queries for one or more domains in
diff --git a/src/option.c b/src/option.c
index 4e533be..58caae9 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2747,6 +2747,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	union all_addr addr;
 	union mysockaddr serv_addr, source_addr;
 	char interface[IF_NAMESIZE+1];
+	int add_local = 0;
 
 	unhide_metas(arg);
 	
@@ -2768,6 +2769,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	  flags = SERV_LITERAL_ADDRESS;
 	else if (option != 'S')
 	  {
+	    char *comma = split(arg);
+	    add_local = 1;
 	    /* # as literal address means return zero address for 4 and 6 */
 	    if (strcmp(arg, "#") == 0)
 	      flags = SERV_ALL_ZEROS | SERV_LITERAL_ADDRESS;
@@ -2777,6 +2780,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	      flags = SERV_6ADDR | SERV_LITERAL_ADDRESS;
 	    else
 	      ret_err(_("Bad address in --address"));
+	    if (comma)
+	      {
+		if (strcmp(comma, "only") == 0)
+		  add_local = 0;
+		else
+		  ret_err(_("Unknown address qualifier"));
+	      }
 	  }
 	else
 	  {
@@ -2804,6 +2814,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	    
 	    if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, &addr))
 	      ret_err(gen_err);
+	    if (add_local)
+	      {
+		/* without --address=/example.com/,only add also --local=/example.com/ to keep
+		 * previous behaviour. */
+		int local_flags = flags & ~(SERV_ALL_ZEROS|SERV_4ADDR|SERV_6ADDR);
+		if (!add_update_server(local_flags, &serv_addr, &source_addr, interface, domain, &addr))
+		  ret_err(gen_err);
+	      }
 	    
 	    if (!lastdomain || domain == lastdomain)
 	      break;
-- 
2.31.1

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to