conf: Treat --dns addresses as guest visible addresses

Although it's not 100% explicit in the man page, addresses given to
the --dns option are intended to be addresses as seen by the guest.
This differs from addresses taken from the host's /etc/resolv.conf,
which must be translated to guest accessible versions in some cases.

Our implementation is currently inconsistent on this: when using
--dns-forward, you must usually also give --dns with the matching address,
which is meaningful only in the guest's address view.  However if you give
--dns with a loopback addres, it will be translated like a host view
address.

Move the remapping logic for DNS addresses out of add_dns4() and add_dns6()
into add_dns_resolv() so that it is only applied for host nameserver
addresses, not for nameservers given explicitly with --dns.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-08-21 14:20:06 +10:00 committed by Stefano Brivio
parent a6066f4e27
commit 0b25cac94e
2 changed files with 53 additions and 51 deletions

90
conf.c
View file

@ -353,7 +353,7 @@ bind_all_fail:
/** /**
* add_dns4() - Possibly add the IPv4 address of a DNS resolver to configuration * add_dns4() - Possibly add the IPv4 address of a DNS resolver to configuration
* @c: Execution context * @c: Execution context
* @addr: Address found in /etc/resolv.conf * @addr: Guest nameserver IPv4 address
* @idx: Index of free entry in array of IPv4 resolvers * @idx: Index of free entry in array of IPv4 resolvers
* *
* Return: Number of entries added (0 or 1) * Return: Number of entries added (0 or 1)
@ -361,64 +361,29 @@ bind_all_fail:
static unsigned add_dns4(struct ctx *c, const struct in_addr *addr, static unsigned add_dns4(struct ctx *c, const struct in_addr *addr,
unsigned idx) unsigned idx)
{ {
unsigned added = 0;
if (idx >= ARRAY_SIZE(c->ip4.dns)) if (idx >= ARRAY_SIZE(c->ip4.dns))
return 0; return 0;
/* Guest or container can only access local addresses via redirect */ c->ip4.dns[idx] = *addr;
if (IN4_IS_ADDR_LOOPBACK(addr)) { return 1;
if (!c->no_map_gw) {
c->ip4.dns[idx] = c->ip4.gw;
added++;
if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match))
c->ip4.dns_match = c->ip4.gw;
}
} else {
c->ip4.dns[idx] = *addr;
added++;
}
if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_host))
c->ip4.dns_host = *addr;
return added;
} }
/** /**
* add_dns6() - Possibly add the IPv6 address of a DNS resolver to configuration * add_dns6() - Possibly add the IPv6 address of a DNS resolver to configuration
* @c: Execution context * @c: Execution context
* @addr: Address found in /etc/resolv.conf * @addr: Guest nameserver IPv6 address
* @idx: Index of free entry in array of IPv6 resolvers * @idx: Index of free entry in array of IPv6 resolvers
* *
* Return: Number of entries added (0 or 1) * Return: Number of entries added (0 or 1)
*/ */
static unsigned add_dns6(struct ctx *c, struct in6_addr *addr, unsigned idx) static unsigned add_dns6(struct ctx *c, const struct in6_addr *addr,
unsigned idx)
{ {
unsigned added = 0;
if (idx >= ARRAY_SIZE(c->ip6.dns)) if (idx >= ARRAY_SIZE(c->ip6.dns))
return 0; return 0;
/* Guest or container can only access local addresses via redirect */ c->ip6.dns[idx] = *addr;
if (IN6_IS_ADDR_LOOPBACK(addr)) { return 1;
if (!c->no_map_gw) {
c->ip6.dns[idx] = c->ip6.gw;
added++;
if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match))
c->ip6.dns_match = c->ip6.gw;
}
} else {
c->ip6.dns[idx] = *addr;
added++;
}
if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_host))
c->ip6.dns_host = *addr;
return added;
} }
/** /**
@ -437,11 +402,44 @@ static void add_dns_resolv(struct ctx *c, const char *nameserver,
struct in6_addr ns6; struct in6_addr ns6;
struct in_addr ns4; struct in_addr ns4;
if (idx4 && inet_pton(AF_INET, nameserver, &ns4)) if (idx4 && inet_pton(AF_INET, nameserver, &ns4)) {
*idx4 += add_dns4(c, &ns4, *idx4); if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_host))
c->ip4.dns_host = ns4;
/* Guest or container can only access local addresses via
* redirect
*/
if (IN4_IS_ADDR_LOOPBACK(&ns4)) {
if (c->no_map_gw)
return;
ns4 = c->ip4.gw;
if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match))
c->ip4.dns_match = c->ip4.gw;
}
*idx4 += add_dns4(c, &ns4, *idx4);
}
if (idx6 && inet_pton(AF_INET6, nameserver, &ns6)) {
if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_host))
c->ip6.dns_host = ns6;
/* Guest or container can only access local addresses via
* redirect
*/
if (IN6_IS_ADDR_LOOPBACK(&ns6)) {
if (c->no_map_gw)
return;
ns6 = c->ip6.gw;
if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match))
c->ip6.dns_match = c->ip6.gw;
}
if (idx6 && inet_pton(AF_INET6, nameserver, &ns6))
*idx6 += add_dns6(c, &ns6, *idx6); *idx6 += add_dns6(c, &ns6, *idx6);
}
} }
/** /**

14
passt.1
View file

@ -236,11 +236,15 @@ interface will be chosen instead.
.TP .TP
.BR \-D ", " \-\-dns " " \fIaddr .BR \-D ", " \-\-dns " " \fIaddr
Use \fIaddr\fR (IPv4 or IPv6) for DHCP, DHCPv6, NDP or DNS forwarding, as Instruct the guest (via DHCP, DHVPv6 or NDP) to use \fIaddr\fR (IPv4
configured (see options \fB--no-dhcp-dns\fR, \fB--dhcp-dns\fR, or IPv6) as a nameserver, as configured (see options
\fB--dns-forward\fR) instead of reading addresses from \fI/etc/resolv.conf\fR. \fB--no-dhcp-dns\fR, \fB--dhcp-dns\fR) instead of reading addresses
This option can be specified multiple times. Specifying \fB-D none\fR disables from \fI/etc/resolv.conf\fR. This option can be specified multiple
usage of DNS addresses altogether. times. Specifying \fB-D none\fR disables usage of DNS addresses
altogether. Unlike addresses from \fI/etc/resolv.conf\fR, \fIaddr\fR
is given to the guest without remapping. For example \fB--dns
127.0.0.1\fR will instruct the guest to use itself as nameserver, not
the host.
.TP .TP
.BR \-\-dns-forward " " \fIaddr .BR \-\-dns-forward " " \fIaddr