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: Paul Holzinger <pholzing@redhat.com>,
	David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v2 2/3] conf: Split the notions of read DNS addresses and offered ones
Date: Thu,  3 Nov 2022 07:33:40 +0100	[thread overview]
Message-ID: <20221103063341.401251-3-sbrivio@redhat.com> (raw)
In-Reply-To: <20221103063341.401251-1-sbrivio@redhat.com>

With --dns-forward, if the host has a loopback address configured as
DNS server, we should actually use it to forward queries, but, if
--no-map-gw is passed, we shouldn't offer the same address via DHCP,
NDP and DHCPv6, because it's not going to be reachable.

Problematic configuration:

* systemd-resolved configuring the usual 127.0.0.53 on the host: we
  read that from /etc/resolv.conf

* --dns-forward specified with an unrelated address, for example
  198.51.100.1

We still want to forward queries to 127.0.0.53, if we receive one
directed to 198.51.100.1, so we can't drop 127.0.0.53 from our list:
we want to use it for forwarding. At the same time, we shouldn't
offer 127.0.0.53 to the guest or container either.

With this change, I'm only covering the case of automatically
configured DNS servers from /etc/resolv.conf. We could extend this to
addresses configured with command-line options, but I don't really
see a likely use case at this point.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
 conf.c   | 50 +++++++++++++++++++++++++++++++++++---------------
 dhcp.c   |  4 ++--
 dhcpv6.c |  5 +++--
 ndp.c    |  6 +++---
 passt.h  |  8 ++++++--
 5 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/conf.c b/conf.c
index 1576744..7c8d2d4 100644
--- a/conf.c
+++ b/conf.c
@@ -355,10 +355,11 @@ overlap:
  */
 static void get_dns(struct ctx *c)
 {
+	struct in6_addr *dns6_send = &c->ip6.dns_send[0];
 	int dns4_set, dns6_set, dnss_set, dns_set, fd;
+	struct in_addr *dns4_send = &c->ip4.dns[0];
 	struct in6_addr *dns6 = &c->ip6.dns[0];
 	struct fqdn *s = c->dns_search;
-	struct in_addr *dns4 = &c->ip4.dns[0];
 	struct lineread resolvconf;
 	int line_len;
 	char *line, *p, *end;
@@ -388,31 +389,47 @@ static void get_dns(struct ctx *c)
 			if (!dns4_set &&
 			    dns4 - &c->ip4.dns[0] < ARRAY_SIZE(c->ip4.dns) - 1 &&
 			    inet_pton(AF_INET, p + 1, dns4)) {
-				/* We can only access local addresses via the gw redirect */
-				if (IN4_IS_ADDR_LOOPBACK(dns4)) {
-					if (c->no_map_gw) {
-						dns4->s_addr = htonl(INADDR_ANY);
-						continue;
+				/* Guest or container can only access local
+				 * addresses via local redirect
+				 */
+				if (IPV4_IS_LOOPBACK(ntohl(*dns4))) {
+					if (!c->no_map_gw) {
+						*dns4_send = c->ip4.gw;
+						dns4_send++;
 					}
-					*dns4 = c->ip4.gw;
+				} else {
+					*dns4_send = *dns4;
+					dns4_send++;
 				}
+
 				dns4++;
+
 				dns4->s_addr = htonl(INADDR_ANY);
+				dns4_send->s_addr = htonl(INADDR_ANY);
 			}
 
 			if (!dns6_set &&
 			    dns6 - &c->ip6.dns[0] < ARRAY_SIZE(c->ip6.dns) - 1 &&
 			    inet_pton(AF_INET6, p + 1, dns6)) {
-				/* We can only access local addresses via the gw redirect */
+				/* Guest or container can only access local
+				 * addresses via local redirect
+				 */
 				if (IN6_IS_ADDR_LOOPBACK(dns6)) {
-					if (c->no_map_gw) {
-						memset(dns6, 0, sizeof(*dns6));
-						continue;
+					if (!c->no_map_gw) {
+						memcpy(dns6_send, &c->ip6.gw,
+						       sizeof(*dns6_send));
+						dns6_send++;
 					}
-					memcpy(dns6, &c->ip6.gw, sizeof(*dns6));
+				} else {
+					memcpy(dns6_send, dns6,
+					       sizeof(*dns6_send));
+					dns6_send++;
 				}
+
 				dns6++;
+
 				memset(dns6, 0, sizeof(*dns6));
+				memset(dns6_send, 0, sizeof(*dns6_send));
 			}
 		} else if (!dnss_set && strstr(line, "search ") == line &&
 			   s == c->dns_search) {
@@ -867,10 +884,12 @@ static void conf_print(const struct ctx *c)
 			     inet_ntop(AF_INET, &c->ip4.gw,   buf4, sizeof(buf4)));
 		}
 
-		for (i = 0; !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); i++) {
+		for (i = 0; !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_send[i]);
+		     i++) {
 			if (!i)
 				info("DNS:");
-			inet_ntop(AF_INET, &c->ip4.dns[i], buf4, sizeof(buf4));
+			inet_ntop(AF_INET, &c->ip4.dns_send[i], buf4,
+				  sizeof(buf4));
 			info("    %s", buf4);
 		}
 
@@ -901,7 +920,8 @@ static void conf_print(const struct ctx *c)
 		     inet_ntop(AF_INET6, &c->ip6.addr_ll, buf6, sizeof(buf6)));
 
 dns6:
-		for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i]); i++) {
+		for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_send[i]);
+		     i++) {
 			if (!i)
 				info("DNS:");
 			inet_ntop(AF_INET6, &c->ip6.dns[i], buf6, sizeof(buf6));
diff --git a/dhcp.c b/dhcp.c
index 0c6f712..12da47a 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -359,9 +359,9 @@ int dhcp(const struct ctx *c, const struct pool *p)
 	}
 
 	for (i = 0, opts[6].slen = 0;
-	     !c->no_dhcp_dns && !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]);
+	     !c->no_dhcp_dns && !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_send[i]);
 	     i++) {
-		((struct in_addr *)opts[6].s)[i] = c->ip4.dns[i];
+		((struct in_addr *)opts[6].s)[i] = c->ip4.dns_send[i];
 		opts[6].slen += sizeof(uint32_t);
 	}
 
diff --git a/dhcpv6.c b/dhcpv6.c
index e763aed..67262e6 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -379,7 +379,7 @@ static size_t dhcpv6_dns_fill(const struct ctx *c, char *buf, int offset)
 	if (c->no_dhcp_dns)
 		goto search;
 
-	for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[i]); i++) {
+	for (i = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_send[i]); i++) {
 		if (!i) {
 			srv = (struct opt_dns_servers *)(buf + offset);
 			offset += sizeof(struct opt_hdr);
@@ -387,7 +387,8 @@ static size_t dhcpv6_dns_fill(const struct ctx *c, char *buf, int offset)
 			srv->hdr.l = 0;
 		}
 
-		memcpy(&srv->addr[i], &c->ip6.dns[i], sizeof(srv->addr[i]));
+		memcpy(&srv->addr[i], &c->ip6.dns_send[i],
+		       sizeof(srv->addr[i]));
 		srv->hdr.l += sizeof(srv->addr[i]);
 		offset += sizeof(srv->addr[i]);
 	}
diff --git a/ndp.c b/ndp.c
index 80e1f19..6d79477 100644
--- a/ndp.c
+++ b/ndp.c
@@ -121,7 +121,7 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih, const struct in6_addr *saddr)
 		if (c->no_dhcp_dns)
 			goto dns_done;
 
-		for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns[n]); n++);
+		for (n = 0; !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_send[n]); n++);
 		if (n) {
 			*p++ = 25;				/* RDNSS */
 			*p++ = 1 + 2 * n;			/* length */
@@ -130,8 +130,8 @@ int ndp(struct ctx *c, const struct icmp6hdr *ih, const struct in6_addr *saddr)
 			p += 4;
 
 			for (i = 0; i < n; i++) {
-				memcpy(p, &c->ip6.dns[i], 16);	/* address */
-				p += 16;
+				memcpy(p, &c->ip6.dns_send[i], 16);
+				p += 16;			/* address */
 			}
 
 			for (n = 0; *c->dns_search[n].n; n++)
diff --git a/passt.h b/passt.h
index 1a8d74b..e92d233 100644
--- a/passt.h
+++ b/passt.h
@@ -101,7 +101,8 @@ enum passt_modes {
  * @addr_seen:		Latest IPv4 address seen as source from tap
  * @prefixlen:		IPv4 prefix length (netmask)
  * @gw:			Default IPv4 gateway, network order
- * @dns:		IPv4 DNS addresses, zero-terminated, network order
+ * @dns:		Host IPv4 DNS addresses, zero-terminated, network order
+ * @dns_send:		Offered IPv4 DNS, zero-terminated, network order
  * @dns_fwd:		Address forwarded (UDP) to first IPv4 DNS, network order
  */
 struct ip4_ctx {
@@ -110,6 +111,7 @@ struct ip4_ctx {
 	int prefix_len;
 	struct in_addr gw;
 	struct in_addr dns[MAXNS + 1];
+	uint32_t dns_send[MAXNS + 1];
 	struct in_addr dns_fwd;
 };
 
@@ -120,7 +122,8 @@ struct ip4_ctx {
  * @addr_seen:		Latest IPv6 global/site address seen as source from tap
  * @addr_ll_seen:	Latest IPv6 link-local address seen as source from tap
  * @gw:			Default IPv6 gateway
- * @dns:		IPv6 DNS addresses, zero-terminated
+ * @dns:		Host IPv6 DNS addresses, zero-terminated
+ * @dns_send:		Offered IPv6 DNS addresses, zero-terminated
  * @dns_fwd:		Address forwarded (UDP) to first IPv6 DNS, network order
  */
 struct ip6_ctx {
@@ -130,6 +133,7 @@ struct ip6_ctx {
 	struct in6_addr addr_ll_seen;
 	struct in6_addr gw;
 	struct in6_addr dns[MAXNS + 1];
+	struct in6_addr dns_send[MAXNS + 1];
 	struct in6_addr dns_fwd;
 };
 
-- 
@@ -101,7 +101,8 @@ enum passt_modes {
  * @addr_seen:		Latest IPv4 address seen as source from tap
  * @prefixlen:		IPv4 prefix length (netmask)
  * @gw:			Default IPv4 gateway, network order
- * @dns:		IPv4 DNS addresses, zero-terminated, network order
+ * @dns:		Host IPv4 DNS addresses, zero-terminated, network order
+ * @dns_send:		Offered IPv4 DNS, zero-terminated, network order
  * @dns_fwd:		Address forwarded (UDP) to first IPv4 DNS, network order
  */
 struct ip4_ctx {
@@ -110,6 +111,7 @@ struct ip4_ctx {
 	int prefix_len;
 	struct in_addr gw;
 	struct in_addr dns[MAXNS + 1];
+	uint32_t dns_send[MAXNS + 1];
 	struct in_addr dns_fwd;
 };
 
@@ -120,7 +122,8 @@ struct ip4_ctx {
  * @addr_seen:		Latest IPv6 global/site address seen as source from tap
  * @addr_ll_seen:	Latest IPv6 link-local address seen as source from tap
  * @gw:			Default IPv6 gateway
- * @dns:		IPv6 DNS addresses, zero-terminated
+ * @dns:		Host IPv6 DNS addresses, zero-terminated
+ * @dns_send:		Offered IPv6 DNS addresses, zero-terminated
  * @dns_fwd:		Address forwarded (UDP) to first IPv6 DNS, network order
  */
 struct ip6_ctx {
@@ -130,6 +133,7 @@ struct ip6_ctx {
 	struct in6_addr addr_ll_seen;
 	struct in6_addr gw;
 	struct in6_addr dns[MAXNS + 1];
+	struct in6_addr dns_send[MAXNS + 1];
 	struct in6_addr dns_fwd;
 };
 
-- 
2.35.1


  parent reply	other threads:[~2022-11-03  6:33 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-03  6:33 [PATCH v2 0/3] Fixes and workarounds for pasta with Podman in Google Cloud Stefano Brivio
2022-11-03  6:33 ` [PATCH v2 1/3] conf: Consistency check between configured IPv4 netmask and gateway Stefano Brivio
2022-11-03  6:33 ` Stefano Brivio [this message]
2022-11-03  7:10   ` [PATCH v2 2/3] conf: Split the notions of read DNS addresses and offered ones Stefano Brivio
2022-11-03  6:33 ` [PATCH v2 3/3] udp: Check for answers to forwarded DNS queries before handling local redirects Stefano Brivio

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=20221103063341.401251-3-sbrivio@redhat.com \
    --to=sbrivio@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=pholzing@redhat.com \
    /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).