On Wed, 12 Oct 2022 12:47:07 +0200 Stefano Brivio <sbrivio(a)redhat.com> wrote:[...] We currently need to process port configuration in a second step for two reasons: - we might bind ports in the detached namespace (-T, -U) - one between IPv4 and IPv6 support could be administratively disabled (operationally, who cares, we'll just fail to bind if that's the case) ...but for init/host facing ports (now: "inbound"), we don't care about the detached namespace, and we could simply call conf_ports() for -t and -u in a second step after the main loop. Sure, if we continue like this, we'll end up with O(n²) option handling, but right now it doesn't look that bad to me. I would give it a shot after I'm done reviewing your patchset (it should also look clearer after that) and re-spinning my recent ones, unless you see something wrong with it.So, I have a draft (minus man page changes), a bit more involved than I wanted but still not adding much. It's based on your patchset, so I can't really test it with Podman because of that new issue I'm facing with filesystem-bound namespaces, but it passes our tests, and it works with low ports too. I would try to figure out that other issue before posting it properly, here it comes anyway: diff --git a/conf.c b/conf.c index a22ef48..e1f42f1 100644 --- a/conf.c +++ b/conf.c @@ -1530,6 +1530,11 @@ void conf(struct ctx *c, int argc, char **argv) } } while (name != -1); + if (v4_only && v6_only) { + err("Options ipv4-only and ipv6-only are mutually exclusive"); + usage(argv[0]); + } + ret = conf_ugid(runas, &uid, &gid); if (ret) usage(argv[0]); @@ -1539,6 +1544,30 @@ void conf(struct ctx *c, int argc, char **argv) logfile, logsize); } + nl_sock_init(c, false); + if (!v6_only) + c->ifi4 = conf_ip4(ifi, &c->ip4, c->mac); + if (!v4_only) + c->ifi6 = conf_ip6(ifi, &c->ip6, c->mac); + if (!c->ifi4 && !c->ifi6) { + err("External interface not usable"); + exit(EXIT_FAILURE); + } + + /* Inbound port options can be parsed now (after IPv4/IPv6 settings) */ + optind = 1; + do { + struct port_fwd *fwd; + + name = getopt_long(argc, argv, optstring, options, NULL); + + if ((name == 't' && (fwd = &c->tcp.fwd_in)) || + (name == 'u' && (fwd = &c->udp.fwd_in.f))) { + if (!optarg || conf_ports(c, name, optarg, fwd)) + usage(argv[0]); + } + } while (name != -1); + if (c->mode == MODE_PASTA) { if (conf_pasta_ns(&netns_only, userns, netns, optind, argc, argv) < 0) @@ -1561,50 +1590,20 @@ void conf(struct ctx *c, int argc, char **argv) } } - if (nl_sock_init(c)) { - err("Failed to get netlink socket"); - exit(EXIT_FAILURE); - } - - if (v4_only && v6_only) { - err("Options ipv4-only and ipv6-only are mutually exclusive"); - usage(argv[0]); - } - if (!v6_only) - c->ifi4 = conf_ip4(ifi, &c->ip4, c->mac); - if (!v4_only) - c->ifi6 = conf_ip6(ifi, &c->ip6, c->mac); - if (!c->ifi4 && !c->ifi6) { - err("External interface not usable"); - exit(EXIT_FAILURE); - } + if (c->mode == MODE_PASTA) + nl_sock_init(c, true); - /* Now we can process port configuration options */ + /* ...and outbound port options now that namespaces are set up. */ optind = 1; do { - struct port_fwd *fwd = NULL; + struct port_fwd *fwd; name = getopt_long(argc, argv, optstring, options, NULL); - switch (name) { - case 't': - case 'u': - case 'T': - case 'U': - if (name == 't') - fwd = &c->tcp.fwd_in; - else if (name == 'T') - fwd = &c->tcp.fwd_out; - else if (name == 'u') - fwd = &c->udp.fwd_in.f; - else if (name == 'U') - fwd = &c->udp.fwd_out.f; + if ((name == 'T' && (fwd = &c->tcp.fwd_out)) || + (name == 'U' && (fwd = &c->udp.fwd_out.f))) { if (!optarg || conf_ports(c, name, optarg, fwd)) usage(argv[0]); - - break; - default: - break; } } while (name != -1); diff --git a/netlink.c b/netlink.c index 6e5a96b..3ee4d42 100644 --- a/netlink.c +++ b/netlink.c @@ -19,6 +19,7 @@ #include <sys/types.h> #include <limits.h> #include <stdlib.h> +#include <stdbool.h> #include <stdint.h> #include <unistd.h> #include <arpa/inet.h> @@ -71,25 +72,28 @@ ns: } /** - * nl_sock_init() - Call nl_sock_init_do() and check for failures + * nl_sock_init() - Call nl_sock_init_do(), won't return on failure * @c: Execution context - * - * Return: -EIO if sockets couldn't be set up, 0 otherwise + * @ns: Get socket in namespace, not in init */ -int nl_sock_init(const struct ctx *c) +void nl_sock_init(const struct ctx *c, bool ns) { - if (c->mode == MODE_PASTA) { + if (c->mode == MODE_PASTA && ns) { NS_CALL(nl_sock_init_do, c); if (nl_sock_ns == -1) - return -EIO; + goto fail; } else { nl_sock_init_do(NULL); } if (nl_sock == -1) - return -EIO; + goto fail; - return 0; + return; + +fail: + err("Failed to get netlink socket"); + exit(EXIT_FAILURE); } /** diff --git a/netlink.h b/netlink.h index 5ce5037..3c991cc 100644 --- a/netlink.h +++ b/netlink.h @@ -6,7 +6,7 @@ #ifndef NETLINK_H #define NETLINK_H -int nl_sock_init(const struct ctx *c); +void nl_sock_init(const struct ctx *c, bool ns); unsigned int nl_get_ext_if(sa_family_t af); void nl_route(int ns, unsigned int ifi, sa_family_t af, void *gw); void nl_addr(int ns, unsigned int ifi, sa_family_t af, diff --git a/tap.c b/tap.c index 77e513c..8b6d9bc 100644 --- a/tap.c +++ b/tap.c @@ -30,6 +30,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <sys/uio.h> +#include <stdbool.h> #include <stdlib.h> #include <unistd.h> #include <netinet/ip.h> -- Stefano