aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2024-08-29 19:58:47 +1000
committerStefano Brivio <sbrivio@redhat.com>2024-08-29 22:26:08 +0200
commiteedc81b6ef552736c4d1d7354837e296af081b57 (patch)
tree6f53e3b3b635d135038c5ab8d459ee96b51b1830
parent4a41dc58d67e910c3a1f505a6a20988c4555e735 (diff)
downloadpasst-eedc81b6ef552736c4d1d7354837e296af081b57.tar
passt-eedc81b6ef552736c4d1d7354837e296af081b57.tar.gz
passt-eedc81b6ef552736c4d1d7354837e296af081b57.tar.bz2
passt-eedc81b6ef552736c4d1d7354837e296af081b57.tar.lz
passt-eedc81b6ef552736c4d1d7354837e296af081b57.tar.xz
passt-eedc81b6ef552736c4d1d7354837e296af081b57.tar.zst
passt-eedc81b6ef552736c4d1d7354837e296af081b57.zip
fwd, conf: Probe host's ephemeral ports
When we forward "all" ports (-t all or -u all), or use an exclude-only range, we don't actually forward *all* ports - that wouln't leave local ports to use for outgoing connections. Rather we forward all non-ephemeral ports - those that won't be used for outgoing connections or datagrams. Currently we assume the range of ephemeral ports is that recommended by RFC 6335, 49152-65535. However, that's not the range used by default on Linux, 32768-60999 but configurable with the net.ipv4.ip_local_port_range sysctl. We can't really know what range the guest will consider ephemeral, but if it differs too much from the host it's likely to cause problems we can't avoid anyway. So, using the host's ephemeral range is a better guess than using the RFC 6335 range. Therefore, add logic to probe the host's ephemeral range, falling back to the RFC 6335 range if that fails. This has the bonus advantage of reducing the number of ports bound by -t all -u all on most Linux machines thereby reducing kernel memory usage. Specifically this reduces kernel memory usage with -t all -u all from ~380MiB to ~289MiB. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Reviewed-by: Laurent Vivier <lvivier@redhat.com> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--conf.c1
-rw-r--r--fwd.c61
-rw-r--r--fwd.h1
3 files changed, 61 insertions, 2 deletions
diff --git a/conf.c b/conf.c
index 3eb117f..b275886 100644
--- a/conf.c
+++ b/conf.c
@@ -1721,6 +1721,7 @@ void conf(struct ctx *c, int argc, char **argv)
/* Inbound port options & DNS can be parsed now (after IPv4/IPv6
* settings)
*/
+ fwd_probe_ephemeral();
udp_portmap_clear();
optind = 0;
do {
diff --git a/fwd.c b/fwd.c
index 8fa312a..a505098 100644
--- a/fwd.c
+++ b/fwd.c
@@ -28,8 +28,65 @@
#include "flow_table.h"
/* Empheral port range: values from RFC 6335 */
-static const in_port_t fwd_ephemeral_min = (1 << 15) + (1 << 14);
-static const in_port_t fwd_ephemeral_max = NUM_PORTS - 1;
+static in_port_t fwd_ephemeral_min = (1 << 15) + (1 << 14);
+static in_port_t fwd_ephemeral_max = NUM_PORTS - 1;
+
+#define PORT_RANGE_SYSCTL "/proc/sys/net/ipv4/ip_local_port_range"
+
+/** fwd_probe_ephemeral() - Determine what ports this host considers ephemeral
+ *
+ * Work out what ports the host thinks are emphemeral and record it for later
+ * use by fwd_port_is_ephemeral(). If we're unable to probe, assume the range
+ * recommended by RFC 6335.
+ */
+void fwd_probe_ephemeral(void)
+{
+ char *line, *tab, *end;
+ struct lineread lr;
+ long min, max;
+ ssize_t len;
+ int fd;
+
+ fd = open(PORT_RANGE_SYSCTL, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ warn_perror("Unable to open %s", PORT_RANGE_SYSCTL);
+ return;
+ }
+
+ lineread_init(&lr, fd);
+ len = lineread_get(&lr, &line);
+ close(fd);
+
+ if (len < 0)
+ goto parse_err;
+
+ tab = strchr(line, '\t');
+ if (!tab)
+ goto parse_err;
+ *tab = '\0';
+
+ errno = 0;
+ min = strtol(line, &end, 10);
+ if (*end || errno)
+ goto parse_err;
+
+ errno = 0;
+ max = strtol(tab + 1, &end, 10);
+ if (*end || errno)
+ goto parse_err;
+
+ if (min < 0 || min >= NUM_PORTS ||
+ max < 0 || max >= NUM_PORTS)
+ goto parse_err;
+
+ fwd_ephemeral_min = min;
+ fwd_ephemeral_max = max;
+
+ return;
+
+parse_err:
+ warn("Unable to parse %s", PORT_RANGE_SYSCTL);
+}
/**
* fwd_port_is_ephemeral() - Is port number ephemeral?
diff --git a/fwd.h b/fwd.h
index 99dd66c..3562f3c 100644
--- a/fwd.h
+++ b/fwd.h
@@ -12,6 +12,7 @@ struct flowside;
/* Number of ports for both TCP and UDP */
#define NUM_PORTS (1U << 16)
+void fwd_probe_ephemeral(void);
bool fwd_port_is_ephemeral(in_port_t port);
enum fwd_ports_mode {