I'm sharing this mostly for debugging / investigation of:
https://github.com/containers/container-libs/pull/755#issuecomment-439042013...
even though the change is probably correct and needed regardless of
that.
If we have map_guest_addr or map_host_loopback addresses set for IPv6,
before using them for inbound NAT from the host, make sure they match
the scope of the original packet, otherwise we might unexpectedly
turn global unicast addresses into link-local ones for packets coming
from the host itself.
Link: https://github.com/containers/container-libs/pull/755#issuecomment-439042013...
Signed-off-by: Stefano Brivio
---
fwd.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/fwd.c b/fwd.c
index 0697435..d224c0a 100644
--- a/fwd.c
+++ b/fwd.c
@@ -974,6 +974,20 @@ uint8_t fwd_nat_from_splice(const struct fwd_rule *rule, uint8_t proto,
return PIF_HOST;
}
+/**
+ * fwd_scope6_match() - Check if the IPv6 scope of two addresses match
+ * @a: First address
+ * @b: Second address
+ *
+ * Return: true for two IPv6 link-local or both not link-local, false otherwise
+ *
+ * NOTE: This currently ignores any other difference in scope
+ */
+bool fwd_scope6_match(const struct in6_addr *a, const struct in6_addr *b)
+{
+ return IN6_IS_ADDR_LINKLOCAL(a) == IN6_IS_ADDR_LINKLOCAL(b);
+}
+
/**
* nat_inbound() - Apply address translation for inbound (HOST to TAP)
* @c: Execution context
@@ -993,13 +1007,15 @@ bool nat_inbound(const struct ctx *c, const union inany_addr *addr,
/* Specifically 127.0.0.1, not 127.0.0.0/8 */
*translated = inany_from_v4(c->ip4.map_host_loopback);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.map_host_loopback) &&
- inany_equals6(addr, &in6addr_loopback)) {
+ inany_equals6(addr, &in6addr_loopback) &&
+ fwd_scope6_match(&addr->a6, &c->ip6.map_host_loopback)) {
translated->a6 = c->ip6.map_host_loopback;
} else if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.map_guest_addr) &&
inany_equals4(addr, &c->ip4.addr)) {
*translated = inany_from_v4(c->ip4.map_guest_addr);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.map_guest_addr) &&
- inany_equals6(addr, &c->ip6.addr)) {
+ inany_equals6(addr, &c->ip6.addr) &&
+ fwd_scope6_match(&addr->a6, &c->ip6.map_guest_addr)) {
translated->a6 = c->ip6.map_guest_addr;
} else if (fwd_guest_accessible(c, addr)) {
*translated = *addr;
--
2.43.0