aboutgitcodebugslistschat
path: root/udp.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2021-07-26 14:10:29 +0200
committerStefano Brivio <sbrivio@redhat.com>2021-07-26 14:10:29 +0200
commit86b273150a47c6f5783db865d1385675f5c4e5a6 (patch)
treebc0011bc64f00a519817eb7b74a7d20664f8e3fb /udp.c
parentf4aaa471a1d304b0b6c767ef4b2fb88b45c02ef1 (diff)
downloadpasst-86b273150a47c6f5783db865d1385675f5c4e5a6.tar
passt-86b273150a47c6f5783db865d1385675f5c4e5a6.tar.gz
passt-86b273150a47c6f5783db865d1385675f5c4e5a6.tar.bz2
passt-86b273150a47c6f5783db865d1385675f5c4e5a6.tar.lz
passt-86b273150a47c6f5783db865d1385675f5c4e5a6.tar.xz
passt-86b273150a47c6f5783db865d1385675f5c4e5a6.tar.zst
passt-86b273150a47c6f5783db865d1385675f5c4e5a6.zip
tcp, udp: Allow binding ports in init namespace to both tap and loopback
Traffic with loopback source address will be forwarded to the direct loopback connection in the namespace, and the tap interface is used for the rest. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'udp.c')
-rw-r--r--udp.c105
1 files changed, 71 insertions, 34 deletions
diff --git a/udp.c b/udp.c
index 00a34a9..92f21d3 100644
--- a/udp.c
+++ b/udp.c
@@ -125,11 +125,13 @@
* @sock: Socket bound to source port used as index
* @ts: Activity timestamp from tap, used for socket aging
* @ts_local: Timestamp of tap packet to gateway address, aging for local bind
+ * @loopback: Whether local bind should use loopback address as source
*/
struct udp_tap_port {
int sock;
time_t ts;
time_t ts_local;
+ int loopback;
};
/**
@@ -201,7 +203,7 @@ udp4_l2_buf[UDP_TAP_FRAMES] = {
};
/**
- * udp4_l2_buf_t - Pre-cooked IPv6 packet buffers for tap connections
+ * udp6_l2_buf_t - Pre-cooked IPv6 packet buffers for tap connections
* @s_in6: Source socket address, filled in by recvmmsg()
* @vnet_len: 4-byte qemu vnet buffer length descriptor, only for passt mode
* @eh: Pre-filled Ethernet header
@@ -644,19 +646,25 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
b->ip6h.payload_len = htons(udp6_l2_mh_sock[i].msg_len +
sizeof(b->uh));
- if (IN6_IS_ADDR_LOOPBACK(&b->s_in6.sin6_addr) ||
- !memcmp(&b->s_in6.sin6_addr, &c->addr6_seen,
- sizeof(c->addr6))) {
+ if (IN6_IS_ADDR_LINKLOCAL(&b->s_in6.sin6_addr)) {
+ b->ip6h.daddr = c->addr6_ll_seen;
+ b->ip6h.saddr = 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,
+ sizeof(c->addr6))) {
in_port_t src = htons(b->s_in6.sin6_port);
- b->ip6h.daddr = c->addr6_seen;
+ b->ip6h.daddr = c->addr6_ll_seen;
b->ip6h.saddr = c->gw6;
udp_tap_map[V6][src].ts_local = now->tv_sec;
+
+ if (IN6_IS_ADDR_LOOPBACK(&b->s_in6.sin6_addr))
+ udp_tap_map[V6][src].loopback = 1;
+ else
+ udp_tap_map[V6][src].loopback = 0;
+
bitmap_set(udp_act[V6][UDP_ACT_TAP], src);
- } else if (IN6_IS_ADDR_LINKLOCAL(&b->s_in6.sin6_addr)) {
- b->ip6h.daddr = c->addr6_ll_seen;
- b->ip6h.saddr = b->s_in6.sin6_addr;
} else {
b->ip6h.daddr = c->addr6_seen;
b->ip6h.saddr = b->s_in6.sin6_addr;
@@ -733,6 +741,12 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
b->iph.saddr = c->gw4;
udp_tap_map[V4][src].ts_local = now->tv_sec;
+
+ if (b->s_in.sin_addr.s_addr == c->addr4_seen)
+ udp_tap_map[V4][src].loopback = 0;
+ else
+ udp_tap_map[V4][src].loopback = 1;
+
bitmap_set(udp_act[V4][UDP_ACT_TAP], src);
} else {
b->iph.saddr = b->s_in.sin_addr.s_addr;
@@ -840,8 +854,12 @@ int udp_tap_handler(struct ctx *c, int af, void *addr,
udp_tap_map[V4][src].ts = now->tv_sec;
if (s_in.sin_addr.s_addr == c->gw4 &&
- udp_tap_map[V4][dst].ts_local)
- s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ udp_tap_map[V4][dst].ts_local) {
+ if (udp_tap_map[V4][dst].loopback)
+ s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ else
+ s_in.sin_addr.s_addr = c->addr4_seen;
+ }
} else {
s_in6 = (struct sockaddr_in6) {
.sin6_family = AF_INET6,
@@ -868,8 +886,12 @@ int udp_tap_handler(struct ctx *c, int af, void *addr,
udp_tap_map[V6][src].ts = now->tv_sec;
if (!memcmp(addr, &c->gw6, sizeof(c->gw6)) &&
- udp_tap_map[V6][dst].ts_local)
- s_in6.sin6_addr = in6addr_loopback;
+ udp_tap_map[V6][dst].ts_local) {
+ if (udp_tap_map[V6][dst].loopback)
+ s_in6.sin6_addr = in6addr_loopback;
+ else
+ s_in6.sin6_addr = c->addr6_seen;
+ }
}
for (i = 0; i < count; i++) {
@@ -911,7 +933,8 @@ int udp_sock_init_ns(void *arg)
continue;
uref.port = port;
- sock_l4(c, AF_INET, IPPROTO_UDP, port, 1, uref.u32);
+ sock_l4(c, AF_INET, IPPROTO_UDP, port, BIND_LOOPBACK,
+ uref.u32);
}
}
@@ -922,7 +945,8 @@ int udp_sock_init_ns(void *arg)
continue;
uref.port = port;
- sock_l4(c, AF_INET6, IPPROTO_UDP, port, 1, uref.u32);
+ sock_l4(c, AF_INET6, IPPROTO_UDP, port, BIND_LOOPBACK,
+ uref.u32);
}
}
@@ -992,24 +1016,31 @@ int udp_sock_init(struct ctx *c)
{
union udp_epoll_ref uref = { .bound = 1 };
char ns_fn_stack[NS_FN_STACK_SIZE];
+ enum bind_type tap_bind;
in_port_t port;
int s;
if (c->v4) {
uref.v6 = 0;
for (port = 0; port < USHRT_MAX; port++) {
- if (bitmap_isset(c->udp.port4_to_ns, port))
+ uref.port = port;
+
+ if (bitmap_isset(c->udp.port4_to_ns, port)) {
uref.splice = UDP_TO_NS;
- else if (bitmap_isset(c->udp.port4_to_tap, port))
- uref.splice = 0;
- else
- continue;
+ sock_l4(c, AF_INET, IPPROTO_UDP, port,
+ BIND_LOOPBACK, uref.u32);
+ tap_bind = BIND_EXT;
+ } else {
+ tap_bind = BIND_ANY;
+ }
- uref.port = port;
- s = sock_l4(c, AF_INET, IPPROTO_UDP, port,
- uref.splice == UDP_TO_NS, uref.u32);
- if (!uref.splice && s > 0)
- udp_tap_map[V4][port].sock = s;
+ if (bitmap_isset(c->udp.port4_to_tap, port)) {
+ uref.splice = 0;
+ s = sock_l4(c, AF_INET, IPPROTO_UDP, port,
+ tap_bind, uref.u32);
+ if (s > 0)
+ udp_tap_map[V4][port].sock = s;
+ }
}
udp_sock4_iov_init();
@@ -1018,18 +1049,24 @@ int udp_sock_init(struct ctx *c)
if (c->v6) {
uref.v6 = 1;
for (port = 0; port < USHRT_MAX; port++) {
- if (bitmap_isset(c->udp.port6_to_ns, port))
+ uref.port = port;
+
+ if (bitmap_isset(c->udp.port6_to_ns, port)) {
uref.splice = UDP_TO_NS;
- else if (bitmap_isset(c->udp.port6_to_tap, port))
- uref.splice = 0;
- else
- continue;
+ sock_l4(c, AF_INET6, IPPROTO_UDP, port,
+ BIND_LOOPBACK, uref.u32);
+ tap_bind = BIND_EXT;
+ } else {
+ tap_bind = BIND_ANY;
+ }
- uref.port = port;
- s = sock_l4(c, AF_INET6, IPPROTO_UDP, port,
- uref.splice == UDP_TO_NS, uref.u32);
- if (!uref.splice && s > 0)
- udp_tap_map[V6][port].sock = s;
+ if (bitmap_isset(c->udp.port6_to_tap, port)) {
+ uref.splice = 0;
+ s = sock_l4(c, AF_INET6, IPPROTO_UDP, port,
+ tap_bind, uref.u32);
+ if (s > 0)
+ udp_tap_map[V6][port].sock = s;
+ }
}
udp_sock6_iov_init();