aboutgitcodebugslistschat
path: root/port_fwd.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2023-11-21 17:18:26 +0100
committerStefano Brivio <sbrivio@redhat.com>2023-11-22 07:19:36 +0100
commit4117bd94f967709074ff1f310d7334ab1876ddae (patch)
treeea5c55cfa511a40df6b1b2a6deeaa14cb98820ee /port_fwd.c
parent4f1709db1b61c14729a6313d860323ec65772a37 (diff)
downloadpasst-4117bd94f967709074ff1f310d7334ab1876ddae.tar
passt-4117bd94f967709074ff1f310d7334ab1876ddae.tar.gz
passt-4117bd94f967709074ff1f310d7334ab1876ddae.tar.bz2
passt-4117bd94f967709074ff1f310d7334ab1876ddae.tar.lz
passt-4117bd94f967709074ff1f310d7334ab1876ddae.tar.xz
passt-4117bd94f967709074ff1f310d7334ab1876ddae.tar.zst
passt-4117bd94f967709074ff1f310d7334ab1876ddae.zip
port_fwd, util: Don't bind UDP ports with opposite-side bound TCP ports
When pasta periodically scans bound ports and binds them on the other side in order to forward traffic, we bind UDP ports for corresponding TCP port numbers, too, to support protocols and applications such as iperf3 which use UDP port numbers matching the ones used by the TCP data connection. If we scan UDP ports in order to bind UDP ports, we skip detection of the UDP ports we already bound ourselves, to avoid looping back our own ports. Same with scanning and binding TCP ports. But if we scan for TCP ports in order to bind UDP ports, we need to skip bound TCP ports too, otherwise, as David pointed out: - we find a bound TCP port on side A, and bind the corresponding TCP and UDP ports on side B - at the next periodic scan, we find that UDP port bound on side B, and we bind the corresponding UDP port on side A - at this point, we unbind that UDP port on side B: we would otherwise loop back our own port. To fix this, we need to avoid binding UDP ports that we already bound, on the other side, as a consequence of finding a corresponding bound TCP port. Reproducing this issue is straightforward: ./pasta -- iperf3 -s # Wait one second, then from another terminal: iperf3 -c ::1 -u Reported-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> Analysed-by: David Gibson <david@gibson.dropbear.id.au> Fixes: 457ff122e33c ("udp,pasta: Periodically scan for ports to automatically forward") Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'port_fwd.c')
-rw-r--r--port_fwd.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/port_fwd.c b/port_fwd.c
index eac8d2f..7943a30 100644
--- a/port_fwd.c
+++ b/port_fwd.c
@@ -86,22 +86,33 @@ void port_fwd_scan_tcp(struct port_fwd *fwd, const struct port_fwd *rev)
* port_fwd_scan_tcp() - Scan /proc to update TCP forwarding map
* @fwd: Forwarding information to update
* @rev: Forwarding information for the reverse direction
- * @tcp: Corresponding TCP forwarding information
+ * @tcp_fwd: Corresponding TCP forwarding information
+ * @tcp_rev: TCP forwarding information for the reverse direction
*/
void port_fwd_scan_udp(struct port_fwd *fwd, const struct port_fwd *rev,
- const struct port_fwd *tcp)
+ const struct port_fwd *tcp_fwd,
+ const struct port_fwd *tcp_rev)
{
+ uint8_t exclude[PORT_BITMAP_SIZE];
+
+ bitmap_or(exclude, PORT_BITMAP_SIZE, rev->map, tcp_rev->map);
+
memset(fwd->map, 0, PORT_BITMAP_SIZE);
- procfs_scan_listen(fwd->scan4, UDP_LISTEN, fwd->map, rev->map);
- procfs_scan_listen(fwd->scan6, UDP_LISTEN, fwd->map, rev->map);
+ procfs_scan_listen(fwd->scan4, UDP_LISTEN, fwd->map, exclude);
+ procfs_scan_listen(fwd->scan6, UDP_LISTEN, fwd->map, exclude);
/* Also forward UDP ports with the same numbers as bound TCP ports.
* This is useful for a handful of protocols (e.g. iperf3) where a TCP
* control port is used to set up transfers on a corresponding UDP
* port.
+ *
+ * This means we need to skip numbers of TCP ports bound on the other
+ * side, too. Otherwise, we would detect corresponding UDP ports as
+ * bound and try to forward them from the opposite side, but it's
+ * already us handling them.
*/
- procfs_scan_listen(tcp->scan4, TCP_LISTEN, fwd->map, rev->map);
- procfs_scan_listen(tcp->scan6, TCP_LISTEN, fwd->map, rev->map);
+ procfs_scan_listen(tcp_fwd->scan4, TCP_LISTEN, fwd->map, exclude);
+ procfs_scan_listen(tcp_fwd->scan6, TCP_LISTEN, fwd->map, exclude);
}
/**
@@ -126,7 +137,7 @@ void port_fwd_init(struct ctx *c)
c->udp.fwd_in.f.scan4 = open_in_ns(c, "/proc/net/udp", flags);
c->udp.fwd_in.f.scan6 = open_in_ns(c, "/proc/net/udp6", flags);
port_fwd_scan_udp(&c->udp.fwd_in.f, &c->udp.fwd_out.f,
- &c->tcp.fwd_in);
+ &c->tcp.fwd_in, &c->tcp.fwd_out);
}
if (c->tcp.fwd_out.mode == FWD_AUTO) {
c->tcp.fwd_out.scan4 = open("/proc/net/tcp", flags);
@@ -137,6 +148,6 @@ void port_fwd_init(struct ctx *c)
c->udp.fwd_out.f.scan4 = open("/proc/net/udp", flags);
c->udp.fwd_out.f.scan6 = open("/proc/net/udp6", flags);
port_fwd_scan_udp(&c->udp.fwd_out.f, &c->udp.fwd_in.f,
- &c->tcp.fwd_out);
+ &c->tcp.fwd_out, &c->tcp.fwd_in);
}
}