udp: Allow loopback connections from host using configured unicast address

Likely for testing purposes only: allow connections from host to
guest or namespace using, as connection target, the configured,
possibly global unicast address.

In this case, we have to map the destination address to a link-local
address, and for port-based tracked responses, the source address
needs to be again the unicast address: not loopback, not link-local.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2022-02-20 03:47:19 +01:00
parent 89678c5157
commit 9afd87b733

20
udp.c
View file

@ -125,13 +125,15 @@
* @sock: Socket bound to source port used as index * @sock: Socket bound to source port used as index
* @ts: Activity timestamp from tap, used for socket aging * @ts: Activity timestamp from tap, used for socket aging
* @ts_local: Timestamp of tap packet to gateway address, aging for local bind * @ts_local: Timestamp of tap packet to gateway address, aging for local bind
* @loopback: Whether local bind should use loopback address as source * @loopback: Whether local bind maps to loopback address as source
* @gua: Whether local bind maps to configured unicast address as source
*/ */
struct udp_tap_port { struct udp_tap_port {
int sock; int sock;
time_t ts; time_t ts;
time_t ts_local; time_t ts_local;
int loopback; int loopback;
int gua;
}; };
/** /**
@ -701,10 +703,13 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
b->ip6h.saddr = b->s_in6.sin6_addr; b->ip6h.saddr = b->s_in6.sin6_addr;
} else if (IN6_IS_ADDR_LOOPBACK(&b->s_in6.sin6_addr) || } else if (IN6_IS_ADDR_LOOPBACK(&b->s_in6.sin6_addr) ||
!memcmp(&b->s_in6.sin6_addr, &c->addr6_seen, !memcmp(&b->s_in6.sin6_addr, &c->addr6_seen,
sizeof(c->addr6)) ||
!memcmp(&b->s_in6.sin6_addr, &c->addr6,
sizeof(c->addr6))) { sizeof(c->addr6))) {
in_port_t src = htons(b->s_in6.sin6_port); in_port_t src = htons(b->s_in6.sin6_port);
b->ip6h.daddr = c->addr6_ll_seen; b->ip6h.daddr = c->addr6_ll_seen;
if (IN6_IS_ADDR_LINKLOCAL(&c->gw6)) if (IN6_IS_ADDR_LINKLOCAL(&c->gw6))
b->ip6h.saddr = c->gw6; b->ip6h.saddr = c->gw6;
else else
@ -717,6 +722,12 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
else else
udp_tap_map[V6][src].loopback = 0; udp_tap_map[V6][src].loopback = 0;
if (!memcmp(&b->s_in6.sin6_addr, &c->addr6,
sizeof(c->addr6)))
udp_tap_map[V6][src].gua = 1;
else
udp_tap_map[V6][src].gua = 0;
bitmap_set(udp_act[V6][UDP_ACT_TAP], src); bitmap_set(udp_act[V6][UDP_ACT_TAP], src);
} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) && } else if (!IN6_IS_ADDR_UNSPECIFIED(&c->dns6_fwd) &&
!memcmp(&b->s_in6.sin6_addr, &c->dns6_fwd, !memcmp(&b->s_in6.sin6_addr, &c->dns6_fwd,
@ -987,6 +998,8 @@ int udp_tap_handler(struct ctx *c, int af, void *addr,
if (!udp_tap_map[V6][dst].ts_local || if (!udp_tap_map[V6][dst].ts_local ||
udp_tap_map[V6][dst].loopback) udp_tap_map[V6][dst].loopback)
s_in6.sin6_addr = in6addr_loopback; s_in6.sin6_addr = in6addr_loopback;
else if (udp_tap_map[V6][dst].gua)
s_in6.sin6_addr = c->addr6;
else else
s_in6.sin6_addr = c->addr6_seen; s_in6.sin6_addr = c->addr6_seen;
} else if (!memcmp(addr, &c->dns6_fwd, sizeof(c->dns6_fwd)) && } else if (!memcmp(addr, &c->dns6_fwd, sizeof(c->dns6_fwd)) &&
@ -1212,8 +1225,11 @@ static void udp_timer_one(struct ctx *c, int v6, enum udp_act_type type,
if (ts->tv_sec - tp->ts > UDP_CONN_TIMEOUT) if (ts->tv_sec - tp->ts > UDP_CONN_TIMEOUT)
s = tp->sock; s = tp->sock;
if (ts->tv_sec - tp->ts_local > UDP_CONN_TIMEOUT) if (ts->tv_sec - tp->ts_local > UDP_CONN_TIMEOUT) {
tp->ts_local = 0; tp->ts_local = 0;
tp->loopback = 0;
tp->gua = 0;
}
break; break;
case UDP_ACT_INIT_CONN: case UDP_ACT_INIT_CONN: