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 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(a)gibson.dropbear.id.au> --- conf.c | 88 ++++++++++++++++++++++++++++----------------------------- passt.1 | 14 +++++---- 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/conf.c b/conf.c index bf61c143..3c102bcf 100644 --- a/conf.c +++ b/conf.c @@ -353,7 +353,7 @@ bind_all_fail: /** * add_dns4() - Possibly add the IPv4 address of a DNS resolver to configuration * @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 * * 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, unsigned idx) { - unsigned added = 0; - if (idx >= ARRAY_SIZE(c->ip4.dns)) return 0; - /* Guest or container can only access local addresses via redirect */ - if (IN4_IS_ADDR_LOOPBACK(addr)) { - 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; + c->ip4.dns[idx] = *addr; + return 1; } /** * add_dns6() - Possibly add the IPv6 address of a DNS resolver to configuration * @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 * * 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)) return 0; - /* Guest or container can only access local addresses via redirect */ - if (IN6_IS_ADDR_LOOPBACK(addr)) { - 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; + c->ip6.dns[idx] = *addr; + return 1; } /** @@ -437,11 +402,44 @@ static void add_dns_resolv(struct ctx *c, const char *nameserver, struct in6_addr ns6; struct in_addr ns4; - if (idx4 && inet_pton(AF_INET, nameserver, &ns4)) + if (idx4 && inet_pton(AF_INET, nameserver, &ns4)) { + 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); + } } /** diff --git a/passt.1 b/passt.1 index 3062b719..dca433b6 100644 --- a/passt.1 +++ b/passt.1 @@ -236,11 +236,15 @@ interface will be chosen instead. .TP .BR \-D ", " \-\-dns " " \fIaddr -Use \fIaddr\fR (IPv4 or IPv6) for DHCP, DHCPv6, NDP or DNS forwarding, as -configured (see options \fB--no-dhcp-dns\fR, \fB--dhcp-dns\fR, -\fB--dns-forward\fR) instead of reading addresses from \fI/etc/resolv.conf\fR. -This option can be specified multiple times. Specifying \fB-D none\fR disables -usage of DNS addresses altogether. +Instruct the guest (via DHCP, DHVPv6 or NDP) to use \fIaddr\fR (IPv4 +or IPv6) as a nameserver, as configured (see options +\fB--no-dhcp-dns\fR, \fB--dhcp-dns\fR) instead of reading addresses +from \fI/etc/resolv.conf\fR. This option can be specified multiple +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 .BR \-\-dns-forward " " \fIaddr -- 2.46.0