public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: passt-dev@passt.top
Cc: Andrea Bolognani <abologna@redhat.com>
Subject: [PATCH 3/3] conf, udp: Allow any loopback address to be used as resolver
Date: Thu, 23 Feb 2023 18:08:00 +0100	[thread overview]
Message-ID: <20230223170800.3888094-4-sbrivio@redhat.com> (raw)
In-Reply-To: <20230223170800.3888094-1-sbrivio@redhat.com>

Andrea reports that with a Fedora 37 guest running on a Fedora 37
host, both using systemd-resolved, with passt connecting them,
running with default options, DNS queries don't work.

systemd-resolved on the host is reachable only at the loopback
address 127.0.0.53.

We advertise the default gateway address to the guest as resolver,
because our local address is of course unreachable from there, which
means we see DNS queries directed to the default gateway, and we
redirect them to 127.0.0.1. However, systemd-resolved doesn't answer
on 127.0.0.1.

To fix this, set @dns_match to the address of the default gateway,
unless a different resolver address is explicitly configured, so that
we know we explicitly have to map DNS queries, in this case, to the
address of the local resolver.

This means that in udp_tap_handler() we need to check, first, if
the destination address of packets matches @dns_match: even if it's
the address of the local gateway, we want to map that to a specific
address, which isn't necessarily 127.0.0.1.

Do the same for IPv6 for consistency, even though IPv6 defines a
single loopback address.

Reported-by: Andrea Bolognani <abologna@redhat.com>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
 conf.c |  6 ++++++
 udp.c  | 20 ++++++++++----------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/conf.c b/conf.c
index ed25e35..37f25d6 100644
--- a/conf.c
+++ b/conf.c
@@ -395,6 +395,9 @@ static void add_dns4(struct ctx *c, struct in_addr *addr, struct in_addr **conf)
 		if (!c->no_map_gw) {
 			**conf = c->ip4.gw;
 			(*conf)++;
+
+			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match))
+				c->ip4.dns_match = c->ip4.gw;
 		}
 	} else {
 		**conf = *addr;
@@ -419,6 +422,9 @@ static void add_dns6(struct ctx *c,
 		if (!c->no_map_gw) {
 			memcpy(*conf, &c->ip6.gw, sizeof(**conf));
 			(*conf)++;
+
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match))
+				memcpy(&c->ip6.dns_match, addr, sizeof(*addr));
 		}
 	} else {
 		memcpy(*conf, addr, sizeof(**conf));
diff --git a/udp.c b/udp.c
index 1d65559..20a9ea0 100644
--- a/udp.c
+++ b/udp.c
@@ -857,17 +857,16 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 
 		udp_tap_map[V4][src].ts = now->tv_sec;
 
-		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) &&
-		    !c->no_map_gw) {
+		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_match) &&
+		    ntohs(s_in.sin_port) == 53) {
+			s_in.sin_addr = c->ip4.dns_host;
+		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) &&
+			   !c->no_map_gw) {
 			if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
 				s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 			else
 				s_in.sin_addr = c->ip4.addr_seen;
-		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr,
-					      &c->ip4.dns_match) &&
-			   ntohs(s_in.sin_port) == 53) {
-			s_in.sin_addr = c->ip4.dns_host;
 		}
 	} else {
 		s_in6 = (struct sockaddr_in6) {
@@ -880,7 +879,11 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		sa = (struct sockaddr *)&s_in6;
 		sl = sizeof(s_in6);
 
-		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) && !c->no_map_gw) {
+		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
+		    ntohs(s_in6.sin6_port) == 53) {
+			s_in6.sin6_addr = c->ip6.dns_host;
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) &&
+			   !c->no_map_gw) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
 				s_in6.sin6_addr = in6addr_loopback;
@@ -888,9 +891,6 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 				s_in6.sin6_addr = c->ip6.addr;
 			else
 				s_in6.sin6_addr = c->ip6.addr_seen;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
-			   ntohs(s_in6.sin6_port) == 53) {
-			s_in6.sin6_addr = c->ip6.dns_host;
 		} else if (IN6_IS_ADDR_LINKLOCAL(&s_in6.sin6_addr)) {
 			bind_addr = &c->ip6.addr_ll;
 		}
-- 
@@ -857,17 +857,16 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 
 		udp_tap_map[V4][src].ts = now->tv_sec;
 
-		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) &&
-		    !c->no_map_gw) {
+		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_match) &&
+		    ntohs(s_in.sin_port) == 53) {
+			s_in.sin_addr = c->ip4.dns_host;
+		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) &&
+			   !c->no_map_gw) {
 			if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
 				s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 			else
 				s_in.sin_addr = c->ip4.addr_seen;
-		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr,
-					      &c->ip4.dns_match) &&
-			   ntohs(s_in.sin_port) == 53) {
-			s_in.sin_addr = c->ip4.dns_host;
 		}
 	} else {
 		s_in6 = (struct sockaddr_in6) {
@@ -880,7 +879,11 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		sa = (struct sockaddr *)&s_in6;
 		sl = sizeof(s_in6);
 
-		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) && !c->no_map_gw) {
+		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
+		    ntohs(s_in6.sin6_port) == 53) {
+			s_in6.sin6_addr = c->ip6.dns_host;
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) &&
+			   !c->no_map_gw) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
 				s_in6.sin6_addr = in6addr_loopback;
@@ -888,9 +891,6 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 				s_in6.sin6_addr = c->ip6.addr;
 			else
 				s_in6.sin6_addr = c->ip6.addr_seen;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
-			   ntohs(s_in6.sin6_port) == 53) {
-			s_in6.sin6_addr = c->ip6.dns_host;
 		} else if (IN6_IS_ADDR_LINKLOCAL(&s_in6.sin6_addr)) {
 			bind_addr = &c->ip6.addr_ll;
 		}
-- 
2.39.1


  parent reply	other threads:[~2023-02-23 17:08 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-23 17:07 [PATCH 0/3] Allow non-127.0.0.1 loopback address as host resolver Stefano Brivio
2023-02-23 17:07 ` [PATCH 1/3] udp: Actually use host resolver to forward DNS queries Stefano Brivio
2023-02-27 12:02   ` David Gibson
2023-02-23 17:07 ` [PATCH 2/3] conf: Split add_dns{4,6}() out of get_dns() Stefano Brivio
2023-02-27 12:04   ` David Gibson
2023-02-23 17:08 ` Stefano Brivio [this message]
2023-02-27 12:07   ` [PATCH 3/3] conf, udp: Allow any loopback address to be used as resolver David Gibson
2023-02-23 17:53 ` [PATCH 0/3] Allow non-127.0.0.1 loopback address as host resolver Andrea Bolognani

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230223170800.3888094-4-sbrivio@redhat.com \
    --to=sbrivio@redhat.com \
    --cc=abologna@redhat.com \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).