The PORT_LOCAL, PORT_LOOPBACK and PORT_GUA flags in udp_tap_port are a rudimentary form of "connection" tracking for UDP. We need this because there are several remote source addresses that we have to translate to the gateway address when we present packets to the guest. We need these flags to work out which address to translate that gateway address back to for reply packets. The flags are confusing, though, it's not really clear what each one means individually, and LOCAL and LOOPBACK are only ever tested in combination. Really, it all boils down to just 3 options: - Packets from addr_seen got tanslated - Packets from (host side) loopback got translated - Packets from addr got translated Replace the flags with an enum explicitly giving those options. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- udp.c | 67 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/udp.c b/udp.c index 950d5a9..3c78fca 100644 --- a/udp.c +++ b/udp.c @@ -120,6 +120,18 @@ #define UDP_CONN_TIMEOUT 180 /* s, timeout for ephemeral or local bind */ #define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */ +/** + * enum udp_port_remote - Original remote address of UDP "connection" to a port + * @PORT_LOOPBACK - Original remote address was (host side) loopback + * @PORT_ADDR_SEEN - Original remote address was the same as the guest is using + * @PORT_ADDR - Original remote address was guest assigned address + */ +enum udp_port_remote { + PORT_LOOPBACK = 0, + PORT_ADDR_SEEN = 1, + PORT_ADDR = 2, +}; + /** * struct udp_tap_port - Port tracking based on tap-facing source port * @sock: Socket bound to source port used as index @@ -128,10 +140,7 @@ */ struct udp_tap_port { int sock; - uint8_t flags; -#define PORT_LOCAL BIT(0) -#define PORT_LOOPBACK BIT(1) -#define PORT_GUA BIT(2) + enum udp_port_remote remote; time_t ts; }; @@ -600,17 +609,13 @@ static size_t udp_update_hdr4(const struct ctx *c, int n, in_port_t dstport, IN4_ARE_ADDR_EQUAL(src, &c->ip4.addr)) { b->iph.saddr = c->ip4.gw.s_addr; udp_tap_map[V4][src_port].ts = now->tv_sec; - udp_tap_map[V4][src_port].flags |= PORT_LOCAL; if (IN4_IS_ADDR_LOOPBACK(src)) - udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK; - else - udp_tap_map[V4][src_port].flags &= ~PORT_LOOPBACK; - - if (IN4_ARE_ADDR_EQUAL(src, &c->ip4.addr)) - udp_tap_map[V4][src_port].flags |= PORT_GUA; + udp_tap_map[V4][src_port].remote = PORT_LOOPBACK; + else if (IN4_ARE_ADDR_EQUAL(src, &c->ip4.addr)) + udp_tap_map[V4][src_port].remote = PORT_ADDR; else - udp_tap_map[V4][src_port].flags &= ~PORT_GUA; + udp_tap_map[V4][src_port].remote = PORT_ADDR_SEEN; bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port); } else { @@ -668,17 +673,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport, b->ip6h.saddr = c->ip6.addr_ll; udp_tap_map[V6][src_port].ts = now->tv_sec; - udp_tap_map[V6][src_port].flags |= PORT_LOCAL; if (IN6_IS_ADDR_LOOPBACK(src)) - udp_tap_map[V6][src_port].flags |= PORT_LOOPBACK; - else - udp_tap_map[V6][src_port].flags &= ~PORT_LOOPBACK; - - if (IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) - udp_tap_map[V6][src_port].flags |= PORT_GUA; + udp_tap_map[V6][src_port].remote = PORT_LOOPBACK; + else if (IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) + udp_tap_map[V6][src_port].remote = PORT_ADDR; else - udp_tap_map[V6][src_port].flags &= ~PORT_GUA; + udp_tap_map[V6][src_port].remote = PORT_ADDR_SEEN; bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port); } else { @@ -855,13 +856,17 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr, s_in.sin_addr = c->ip4.dns_host; } else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) && !c->no_map_gw) { - if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) || - (udp_tap_map[V4][dst].flags & PORT_LOOPBACK)) + switch (udp_tap_map[V4][dst].remote) { + case PORT_LOOPBACK: s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - else if (udp_tap_map[V4][dst].flags & PORT_GUA) + break; + case PORT_ADDR: s_in.sin_addr = c->ip4.addr; - else + break; + case PORT_ADDR_SEEN: s_in.sin_addr = c->ip4.addr_seen; + break; + } } if (!(s = udp_tap_map[V4][src].sock)) { @@ -903,13 +908,17 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr, s_in6.sin6_addr = c->ip6.dns_host; } else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) && !c->no_map_gw) { - if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) || - (udp_tap_map[V6][dst].flags & PORT_LOOPBACK)) + switch (udp_tap_map[V6][dst].remote) { + case PORT_LOOPBACK: s_in6.sin6_addr = in6addr_loopback; - else if (udp_tap_map[V6][dst].flags & PORT_GUA) + break; + case PORT_ADDR: s_in6.sin6_addr = c->ip6.addr; - else + break; + case PORT_ADDR_SEEN: s_in6.sin6_addr = c->ip6.addr_seen; + break; + } } else if (IN6_IS_ADDR_LINKLOCAL(&s_in6.sin6_addr)) { bind_addr = &c->ip6.addr_ll; } @@ -1162,7 +1171,7 @@ static void udp_timer_one(struct ctx *c, int v6, enum udp_act_type type, if (ts->tv_sec - tp->ts > UDP_CONN_TIMEOUT) { s = tp->sock; - tp->flags = 0; + tp->remote = PORT_LOOPBACK; } break; -- 2.40.1