udp: Check for answers to forwarded DNS queries before handling local redirects

Now that we allow loopback DNS addresses to be used as targets for
forwarding, we need to check if DNS answers come from those targets,
before deciding to eventually remap traffic for local redirects.

Otherwise, the source address won't match the one configured as
forwarder, which means that the guest or the container will refuse
those responses.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2022-11-02 23:59:01 +01:00
parent 73f50a76aa
commit db74679f98

18
udp.c
View file

@ -678,7 +678,11 @@ static void udp_sock_fill_data_v4(const struct ctx *c, int n,
src_port = ntohs(b->s_in.sin_port); src_port = ntohs(b->s_in.sin_port);
if (IN4_IS_ADDR_LOOPBACK(&b->s_in.sin_addr) || if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) &&
IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.dns[0]) &&
src_port == 53) {
b->iph.saddr = c->ip4.dns_fwd.s_addr;
} else if (IN4_IS_ADDR_LOOPBACK(&b->s_in.sin_addr) ||
IN4_IS_ADDR_UNSPECIFIED(&b->s_in.sin_addr)|| IN4_IS_ADDR_UNSPECIFIED(&b->s_in.sin_addr)||
IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.addr_seen)) { IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.addr_seen)) {
b->iph.saddr = c->ip4.gw.s_addr; b->iph.saddr = c->ip4.gw.s_addr;
@ -691,10 +695,6 @@ static void udp_sock_fill_data_v4(const struct ctx *c, int n,
udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK; udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK;
bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port); bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port);
} else if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) &&
IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.dns[0]) &&
src_port == 53) {
b->iph.saddr = c->ip4.dns_fwd.s_addr;
} else { } else {
b->iph.saddr = b->s_in.sin_addr.s_addr; b->iph.saddr = b->s_in.sin_addr.s_addr;
} }
@ -770,6 +770,10 @@ static void udp_sock_fill_data_v6(const struct ctx *c, int n,
if (IN6_IS_ADDR_LINKLOCAL(src)) { if (IN6_IS_ADDR_LINKLOCAL(src)) {
b->ip6h.daddr = c->ip6.addr_ll_seen; b->ip6h.daddr = c->ip6.addr_ll_seen;
b->ip6h.saddr = b->s_in6.sin6_addr; b->ip6h.saddr = b->s_in6.sin6_addr;
} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd) &&
IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns[0]) && src_port == 53) {
b->ip6h.daddr = c->ip6.addr_seen;
b->ip6h.saddr = c->ip6.dns_fwd;
} else if (IN6_IS_ADDR_LOOPBACK(src) || } else if (IN6_IS_ADDR_LOOPBACK(src) ||
IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen) || IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen) ||
IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) { IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
@ -794,10 +798,6 @@ static void udp_sock_fill_data_v6(const struct ctx *c, int n,
udp_tap_map[V6][src_port].flags &= ~PORT_GUA; udp_tap_map[V6][src_port].flags &= ~PORT_GUA;
bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port); bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_fwd) &&
IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns[0]) && src_port == 53) {
b->ip6h.daddr = c->ip6.addr_seen;
b->ip6h.saddr = c->ip6.dns_fwd;
} else { } else {
b->ip6h.daddr = c->ip6.addr_seen; b->ip6h.daddr = c->ip6.addr_seen;
b->ip6h.saddr = b->s_in6.sin6_addr; b->ip6h.saddr = b->s_in6.sin6_addr;