fwd: Update flow forwarding logic for UDP

Add logic to the fwd_nat_from_*() functions to forwarding UDP packets.  The
logic here doesn't exactly match our current forwarding, since our current
forwarding has some very strange and buggy edge cases.  Instead it's
attempting to replicate what appears to be the intended logic behind the
current forwarding.

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-07-18 15:26:45 +10:00 committed by Stefano Brivio
parent c000f2aba6
commit 8abd06e9fa

27
fwd.c
View file

@ -169,12 +169,16 @@ void fwd_scan_ports_init(struct ctx *c)
uint8_t fwd_nat_from_tap(const struct ctx *c, uint8_t proto, uint8_t fwd_nat_from_tap(const struct ctx *c, uint8_t proto,
const struct flowside *ini, struct flowside *tgt) const struct flowside *ini, struct flowside *tgt)
{ {
(void)proto;
tgt->eaddr = ini->faddr; tgt->eaddr = ini->faddr;
tgt->eport = ini->fport; tgt->eport = ini->fport;
if (!c->no_map_gw) { if (proto == IPPROTO_UDP && tgt->eport == 53 &&
inany_equals4(&tgt->eaddr, &c->ip4.dns_match)) {
tgt->eaddr = inany_from_v4(c->ip4.dns_host);
} else if (proto == IPPROTO_UDP && tgt->eport == 53 &&
inany_equals6(&tgt->eaddr, &c->ip6.dns_match)) {
tgt->eaddr.a6 = c->ip6.dns_host;
} else if (!c->no_map_gw) {
if (inany_equals4(&tgt->eaddr, &c->ip4.gw)) if (inany_equals4(&tgt->eaddr, &c->ip4.gw))
tgt->eaddr = inany_loopback4; tgt->eaddr = inany_loopback4;
else if (inany_equals6(&tgt->eaddr, &c->ip6.gw)) else if (inany_equals6(&tgt->eaddr, &c->ip6.gw))
@ -191,6 +195,10 @@ uint8_t fwd_nat_from_tap(const struct ctx *c, uint8_t proto,
/* Let the kernel pick a host side source port */ /* Let the kernel pick a host side source port */
tgt->fport = 0; tgt->fport = 0;
if (proto == IPPROTO_UDP) {
/* But for UDP we preserve the source port */
tgt->fport = ini->eport;
}
return PIF_HOST; return PIF_HOST;
} }
@ -233,9 +241,14 @@ uint8_t fwd_nat_from_splice(const struct ctx *c, uint8_t proto,
tgt->eport = ini->fport; tgt->eport = ini->fport;
if (proto == IPPROTO_TCP) if (proto == IPPROTO_TCP)
tgt->eport += c->tcp.fwd_out.delta[tgt->eport]; tgt->eport += c->tcp.fwd_out.delta[tgt->eport];
else if (proto == IPPROTO_UDP)
tgt->eport += c->udp.fwd_out.f.delta[tgt->eport];
/* Let the kernel pick a host side source port */ /* Let the kernel pick a host side source port */
tgt->fport = 0; tgt->fport = 0;
if (proto == IPPROTO_UDP)
/* But for UDP preserve the source port */
tgt->fport = ini->eport;
return PIF_HOST; return PIF_HOST;
} }
@ -257,9 +270,11 @@ uint8_t fwd_nat_from_host(const struct ctx *c, uint8_t proto,
tgt->eport = ini->fport; tgt->eport = ini->fport;
if (proto == IPPROTO_TCP) if (proto == IPPROTO_TCP)
tgt->eport += c->tcp.fwd_in.delta[tgt->eport]; tgt->eport += c->tcp.fwd_in.delta[tgt->eport];
else if (proto == IPPROTO_UDP)
tgt->eport += c->udp.fwd_in.f.delta[tgt->eport];
if (c->mode == MODE_PASTA && inany_is_loopback(&ini->eaddr) && if (c->mode == MODE_PASTA && inany_is_loopback(&ini->eaddr) &&
proto == IPPROTO_TCP) { (proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
/* spliceable */ /* spliceable */
/* Preserve the specific loopback adddress used, but let the /* Preserve the specific loopback adddress used, but let the
@ -267,11 +282,15 @@ uint8_t fwd_nat_from_host(const struct ctx *c, uint8_t proto,
*/ */
tgt->faddr = ini->eaddr; tgt->faddr = ini->eaddr;
tgt->fport = 0; tgt->fport = 0;
if (proto == IPPROTO_UDP)
/* But for UDP preserve the source port */
tgt->fport = ini->eport;
if (inany_v4(&ini->eaddr)) if (inany_v4(&ini->eaddr))
tgt->eaddr = inany_loopback4; tgt->eaddr = inany_loopback4;
else else
tgt->eaddr = inany_loopback6; tgt->eaddr = inany_loopback6;
return PIF_SPLICE; return PIF_SPLICE;
} }