Improve types and names for port forwarding configuration

enum conf_port_type is local to conf.c and is used to track the port
forwarding mode during configuration.  We don't keep it around in the
context structure, however the 'init_detect_ports' and 'ns_detect_ports'
fields in the context are based solely on this.  Rather than changing
encoding, just include the forwarding mode into the context structure.
Move the type definition to a new port_fwd.h, which is kind of trivial at
the moment but will have more stuff later.

While we're there, "conf_port_type" doesn't really convey that this enum is
describing how port forwarding is configured.  Rename it to port_fwd_mode.
The variables (now fields) of this type also have mildly confusing names
since it's not immediately obvious whether 'ns' and 'init' refer to the
source or destination of the packets.  Use "in" (host to guest / init to
ns) and "out" (guest to host / ns to init) instead.

This has the added bonus that we no longer have locals 'udp_init' and
'tcp_init' which shadow global functions.

In addition, add a typedef 'port_fwd_map' for a bitmap of each port number,
which is used in several places.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
David Gibson 2022-09-24 19:08:16 +10:00 committed by Stefano Brivio
parent 11e285df8f
commit 1128fa03fe
7 changed files with 76 additions and 55 deletions

View file

@ -41,7 +41,7 @@ MANPAGES = passt.1 pasta.1 qrap.1
PASST_HEADERS = arch.h arp.h checksum.h conf.h dhcp.h dhcpv6.h icmp.h \ PASST_HEADERS = arch.h arp.h checksum.h conf.h dhcp.h dhcpv6.h icmp.h \
isolation.h lineread.h ndp.h netlink.h packet.h passt.h pasta.h \ isolation.h lineread.h ndp.h netlink.h packet.h passt.h pasta.h \
pcap.h siphash.h tap.h tcp.h tcp_splice.h udp.h util.h pcap.h port_fwd.h siphash.h tap.h tcp.h tcp_splice.h udp.h util.h
HEADERS = $(PASST_HEADERS) seccomp.h HEADERS = $(PASST_HEADERS) seccomp.h
# On gcc 11.2, with -O2 and -flto, tcp_hash() and siphash_20b(), if inlined, # On gcc 11.2, with -O2 and -flto, tcp_hash() and siphash_20b(), if inlined,

73
conf.c
View file

@ -64,14 +64,14 @@ void get_bound_ports(struct ctx *c, int ns, uint8_t proto)
} }
if (proto == IPPROTO_UDP) { if (proto == IPPROTO_UDP) {
memset(udp_map, 0, USHRT_MAX / 8); memset(udp_map, 0, PORT_BITMAP_SIZE);
procfs_scan_listen(c, IPPROTO_UDP, V4, ns, udp_map, udp_excl); procfs_scan_listen(c, IPPROTO_UDP, V4, ns, udp_map, udp_excl);
procfs_scan_listen(c, IPPROTO_UDP, V6, ns, udp_map, udp_excl); procfs_scan_listen(c, IPPROTO_UDP, V6, ns, udp_map, udp_excl);
procfs_scan_listen(c, IPPROTO_TCP, V4, ns, udp_map, udp_excl); procfs_scan_listen(c, IPPROTO_TCP, V4, ns, udp_map, udp_excl);
procfs_scan_listen(c, IPPROTO_TCP, V6, ns, udp_map, udp_excl); procfs_scan_listen(c, IPPROTO_TCP, V6, ns, udp_map, udp_excl);
} else if (proto == IPPROTO_TCP) { } else if (proto == IPPROTO_TCP) {
memset(tcp_map, 0, USHRT_MAX / 8); memset(tcp_map, 0, PORT_BITMAP_SIZE);
procfs_scan_listen(c, IPPROTO_TCP, V4, ns, tcp_map, tcp_excl); procfs_scan_listen(c, IPPROTO_TCP, V4, ns, tcp_map, tcp_excl);
procfs_scan_listen(c, IPPROTO_TCP, V6, ns, tcp_map, tcp_excl); procfs_scan_listen(c, IPPROTO_TCP, V6, ns, tcp_map, tcp_excl);
} }
@ -106,31 +106,25 @@ static int get_bound_ports_ns(void *arg)
return 0; return 0;
} }
enum conf_port_type {
PORT_SPEC = 1,
PORT_NONE,
PORT_AUTO,
PORT_ALL,
};
/** /**
* conf_ports() - Parse port configuration options, initialise UDP/TCP sockets * conf_ports() - Parse port configuration options, initialise UDP/TCP sockets
* @c: Execution context * @c: Execution context
* @optname: Short option name, t, T, u, or U * @optname: Short option name, t, T, u, or U
* @optarg: Option argument (port specification) * @optarg: Option argument (port specification)
* @set: Pointer to @conf_port_type to be set (port binding type) * @set: Pointer to @port_fwd_mode to be set (port forwarding mode)
* *
* Return: -EINVAL on parsing error, 0 otherwise * Return: -EINVAL on parsing error, 0 otherwise
*/ */
static int conf_ports(struct ctx *c, char optname, const char *optarg, static int conf_ports(struct ctx *c, char optname, const char *optarg,
enum conf_port_type *set) enum port_fwd_mode *set)
{ {
int start_src, end_src, start_dst, end_dst, exclude_only = 1, i, port; int start_src, end_src, start_dst, end_dst, exclude_only = 1, i, port;
char addr_buf[sizeof(struct in6_addr)] = { 0 }, *addr = addr_buf; char addr_buf[sizeof(struct in6_addr)] = { 0 }, *addr = addr_buf;
uint8_t *map, exclude[DIV_ROUND_UP(USHRT_MAX, 8)] = { 0 };
void (*remap)(in_port_t port, in_port_t delta); void (*remap)(in_port_t port, in_port_t delta);
uint8_t exclude[PORT_BITMAP_SIZE] = { 0 };
char buf[BUFSIZ], *sep, *spec, *p; char buf[BUFSIZ], *sep, *spec, *p;
sa_family_t af = AF_UNSPEC; sa_family_t af = AF_UNSPEC;
uint8_t *map;
if (optname == 't') { if (optname == 't') {
map = c->tcp.port_to_tap; map = c->tcp.port_to_tap;
@ -151,14 +145,14 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
if (!strcmp(optarg, "none")) { if (!strcmp(optarg, "none")) {
if (*set) if (*set)
return -EINVAL; return -EINVAL;
*set = PORT_NONE; *set = FWD_NONE;
return 0; return 0;
} }
if (!strcmp(optarg, "auto")) { if (!strcmp(optarg, "auto")) {
if (*set || c->mode != MODE_PASTA) if (*set || c->mode != MODE_PASTA)
return -EINVAL; return -EINVAL;
*set = PORT_AUTO; *set = FWD_AUTO;
return 0; return 0;
} }
@ -167,7 +161,7 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
if (*set || c->mode != MODE_PASST) if (*set || c->mode != MODE_PASST)
return -EINVAL; return -EINVAL;
*set = PORT_ALL; *set = FWD_ALL;
memset(map, 0xff, PORT_EPHEMERAL_MIN / 8); memset(map, 0xff, PORT_EPHEMERAL_MIN / 8);
for (i = 0; i < PORT_EPHEMERAL_MIN; i++) { for (i = 0; i < PORT_EPHEMERAL_MIN; i++) {
@ -180,10 +174,10 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg,
return 0; return 0;
} }
if (*set > PORT_SPEC) if (*set > FWD_SPEC)
return -EINVAL; return -EINVAL;
*set = PORT_SPEC; *set = FWD_SPEC;
strncpy(buf, optarg, sizeof(buf) - 1); strncpy(buf, optarg, sizeof(buf) - 1);
@ -1088,8 +1082,6 @@ void conf(struct ctx *c, int argc, char **argv)
}; };
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c }; struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 }; char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 };
enum conf_port_type tcp_tap = 0, tcp_init = 0;
enum conf_port_type udp_tap = 0, udp_init = 0;
bool v4_only = false, v6_only = false; bool v4_only = false, v6_only = false;
struct in6_addr *dns6 = c->ip6.dns; struct in6_addr *dns6 = c->ip6.dns;
struct fqdn *dnss = c->dns_search; struct fqdn *dnss = c->dns_search;
@ -1103,6 +1095,9 @@ void conf(struct ctx *c, int argc, char **argv)
if (c->mode == MODE_PASTA) if (c->mode == MODE_PASTA)
c->no_dhcp_dns = c->no_dhcp_dns_search = 1; c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
c->tcp.fwd_mode_in = c->tcp.fwd_mode_out = 0;
c->udp.fwd_mode_in = c->udp.fwd_mode_out = 0;
do { do {
const char *optstring; const char *optstring;
@ -1553,7 +1548,7 @@ void conf(struct ctx *c, int argc, char **argv)
/* Now we can process port configuration options */ /* Now we can process port configuration options */
optind = 1; optind = 1;
do { do {
enum conf_port_type *set = NULL; enum port_fwd_mode *fwd = NULL;
const char *optstring; const char *optstring;
if (c->mode == MODE_PASST) if (c->mode == MODE_PASST)
@ -1568,15 +1563,15 @@ void conf(struct ctx *c, int argc, char **argv)
case 'T': case 'T':
case 'U': case 'U':
if (name == 't') if (name == 't')
set = &tcp_tap; fwd = &c->tcp.fwd_mode_in;
else if (name == 'T') else if (name == 'T')
set = &tcp_init; fwd = &c->tcp.fwd_mode_out;
else if (name == 'u') else if (name == 'u')
set = &udp_tap; fwd = &c->udp.fwd_mode_in;
else if (name == 'U') else if (name == 'U')
set = &udp_init; fwd = &c->udp.fwd_mode_out;
if (!optarg || conf_ports(c, name, optarg, set)) if (!optarg || conf_ports(c, name, optarg, fwd))
usage(argv[0]); usage(argv[0]);
break; break;
@ -1605,33 +1600,39 @@ void conf(struct ctx *c, int argc, char **argv)
if_indextoname(c->ifi6, c->pasta_ifn); if_indextoname(c->ifi6, c->pasta_ifn);
} }
c->tcp.ns_detect_ports = c->udp.ns_detect_ports = 0;
c->tcp.init_detect_ports = c->udp.init_detect_ports = 0;
if (c->mode == MODE_PASTA) { if (c->mode == MODE_PASTA) {
c->proc_net_tcp[V4][0] = c->proc_net_tcp[V4][1] = -1; c->proc_net_tcp[V4][0] = c->proc_net_tcp[V4][1] = -1;
c->proc_net_tcp[V6][0] = c->proc_net_tcp[V6][1] = -1; c->proc_net_tcp[V6][0] = c->proc_net_tcp[V6][1] = -1;
c->proc_net_udp[V4][0] = c->proc_net_udp[V4][1] = -1; c->proc_net_udp[V4][0] = c->proc_net_udp[V4][1] = -1;
c->proc_net_udp[V6][0] = c->proc_net_udp[V6][1] = -1; c->proc_net_udp[V6][0] = c->proc_net_udp[V6][1] = -1;
if (!tcp_tap || tcp_tap == PORT_AUTO) { if (!c->tcp.fwd_mode_in || c->tcp.fwd_mode_in == FWD_AUTO) {
c->tcp.ns_detect_ports = 1; c->tcp.fwd_mode_in = FWD_AUTO;
ns_ports_arg.proto = IPPROTO_TCP; ns_ports_arg.proto = IPPROTO_TCP;
NS_CALL(get_bound_ports_ns, &ns_ports_arg); NS_CALL(get_bound_ports_ns, &ns_ports_arg);
} }
if (!udp_tap || udp_tap == PORT_AUTO) { if (!c->udp.fwd_mode_in || c->udp.fwd_mode_in == FWD_AUTO) {
c->udp.ns_detect_ports = 1; c->udp.fwd_mode_in = FWD_AUTO;
ns_ports_arg.proto = IPPROTO_UDP; ns_ports_arg.proto = IPPROTO_UDP;
NS_CALL(get_bound_ports_ns, &ns_ports_arg); NS_CALL(get_bound_ports_ns, &ns_ports_arg);
} }
if (!tcp_init || tcp_init == PORT_AUTO) { if (!c->tcp.fwd_mode_out || c->tcp.fwd_mode_out == FWD_AUTO) {
c->tcp.init_detect_ports = 1; c->tcp.fwd_mode_out = FWD_AUTO;
get_bound_ports(c, 0, IPPROTO_TCP); get_bound_ports(c, 0, IPPROTO_TCP);
} }
if (!udp_init || udp_init == PORT_AUTO) { if (!c->udp.fwd_mode_out || c->udp.fwd_mode_out == FWD_AUTO) {
c->udp.init_detect_ports = 1; c->udp.fwd_mode_out = FWD_AUTO;
get_bound_ports(c, 0, IPPROTO_UDP); get_bound_ports(c, 0, IPPROTO_UDP);
} }
} else {
if (!c->tcp.fwd_mode_in)
c->tcp.fwd_mode_in = FWD_NONE;
if (!c->tcp.fwd_mode_out)
c->tcp.fwd_mode_out= FWD_NONE;
if (!c->udp.fwd_mode_in)
c->udp.fwd_mode_in = FWD_NONE;
if (!c->udp.fwd_mode_out)
c->udp.fwd_mode_out = FWD_NONE;
} }
if (!c->quiet) if (!c->quiet)

View file

@ -33,6 +33,7 @@ union epoll_ref;
#include "packet.h" #include "packet.h"
#include "icmp.h" #include "icmp.h"
#include "port_fwd.h"
#include "tcp.h" #include "tcp.h"
#include "udp.h" #include "udp.h"

19
port_fwd.h Normal file
View file

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright Red Hat
* Author: Stefano Brivio <sbrivio@redhat.com>
* Author: David Gibson <david@gibson.dropbear.id.au>
*/
#ifndef PORT_FWD_H
#define PORT_FWD_H
enum port_fwd_mode {
FWD_SPEC = 1,
FWD_NONE,
FWD_AUTO,
FWD_ALL,
};
#define PORT_BITMAP_SIZE DIV_ROUND_UP(USHRT_MAX, 8)
#endif /* PORT_FWD_H */

12
tcp.c
View file

@ -3133,7 +3133,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
else else
s = -1; s = -1;
if (c->tcp.init_detect_ports) if (c->tcp.fwd_mode_in == FWD_AUTO)
tcp_sock_init_ext[port][V4] = s; tcp_sock_init_ext[port][V4] = s;
} }
@ -3148,7 +3148,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
else else
s = -1; s = -1;
if (c->tcp.ns_detect_ports) { if (c->tcp.fwd_mode_out == FWD_AUTO) {
if (ns) if (ns)
tcp_sock_ns[port][V4] = s; tcp_sock_ns[port][V4] = s;
else else
@ -3174,7 +3174,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
else else
s = -1; s = -1;
if (c->tcp.init_detect_ports) if (c->tcp.fwd_mode_in == FWD_AUTO)
tcp_sock_init_ext[port][V6] = s; tcp_sock_init_ext[port][V6] = s;
} }
@ -3189,7 +3189,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af,
else else
s = -1; s = -1;
if (c->tcp.ns_detect_ports) { if (c->tcp.fwd_mode_out == FWD_AUTO) {
if (ns) if (ns)
tcp_sock_ns[port][V6] = s; tcp_sock_ns[port][V6] = s;
else else
@ -3489,14 +3489,14 @@ void tcp_timer(struct ctx *c, const struct timespec *ts)
struct tcp_port_detect_arg detect_arg = { c, 0 }; struct tcp_port_detect_arg detect_arg = { c, 0 };
struct tcp_port_rebind_arg rebind_arg = { c, 0 }; struct tcp_port_rebind_arg rebind_arg = { c, 0 };
if (c->tcp.init_detect_ports) { if (c->tcp.fwd_mode_in == FWD_AUTO) {
detect_arg.detect_in_ns = 0; detect_arg.detect_in_ns = 0;
tcp_port_detect(&detect_arg); tcp_port_detect(&detect_arg);
rebind_arg.bind_in_ns = 1; rebind_arg.bind_in_ns = 1;
NS_CALL(tcp_port_rebind, &rebind_arg); NS_CALL(tcp_port_rebind, &rebind_arg);
} }
if (c->tcp.ns_detect_ports) { if (c->tcp.fwd_mode_out == FWD_AUTO) {
detect_arg.detect_in_ns = 1; detect_arg.detect_in_ns = 1;
NS_CALL(tcp_port_detect, &detect_arg); NS_CALL(tcp_port_detect, &detect_arg);
rebind_arg.bind_in_ns = 0; rebind_arg.bind_in_ns = 0;

12
tcp.h
View file

@ -58,9 +58,9 @@ union tcp_epoll_ref {
* @conn_count: Count of connections (not spliced) in connection table * @conn_count: Count of connections (not spliced) in connection table
* @splice_conn_count: Count of spliced connections in connection table * @splice_conn_count: Count of spliced connections in connection table
* @port_to_tap: Ports bound host-side, packets to tap or spliced * @port_to_tap: Ports bound host-side, packets to tap or spliced
* @init_detect_ports: If set, periodically detect ports bound in init * @fwd_mode_in: Port forwarding mode for inbound packets
* @port_to_init: Ports bound namespace-side, spliced to init * @port_to_init: Ports bound namespace-side, spliced to init
* @ns_detect_ports: If set, periodically detect ports bound in namespace * @fwd_mode_out: Port forwarding mode for outbound packets
* @timer_run: Timestamp of most recent timer run * @timer_run: Timestamp of most recent timer run
* @kernel_snd_wnd: Kernel reports sending window (with commit 8f7baad7f035) * @kernel_snd_wnd: Kernel reports sending window (with commit 8f7baad7f035)
* @pipe_size: Size of pipes for spliced connections * @pipe_size: Size of pipes for spliced connections
@ -69,10 +69,10 @@ struct tcp_ctx {
uint64_t hash_secret[2]; uint64_t hash_secret[2];
int conn_count; int conn_count;
int splice_conn_count; int splice_conn_count;
uint8_t port_to_tap [DIV_ROUND_UP(USHRT_MAX, 8)]; uint8_t port_to_tap [PORT_BITMAP_SIZE];
int init_detect_ports; enum port_fwd_mode fwd_mode_in;
uint8_t port_to_init [DIV_ROUND_UP(USHRT_MAX, 8)]; uint8_t port_to_init [PORT_BITMAP_SIZE];
int ns_detect_ports; enum port_fwd_mode fwd_mode_out;
struct timespec timer_run; struct timespec timer_run;
#ifdef HAS_SND_WND #ifdef HAS_SND_WND
int kernel_snd_wnd; int kernel_snd_wnd;

12
udp.h
View file

@ -47,16 +47,16 @@ union udp_epoll_ref {
/** /**
* struct udp_ctx - Execution context for UDP * struct udp_ctx - Execution context for UDP
* @port_to_tap: Ports bound host-side, data to tap or ns L4 socket * @port_to_tap: Ports bound host-side, data to tap or ns L4 socket
* @init_detect_ports: If set, periodically detect ports bound in init (TODO) * @fwd_mode_in: Port forwarding mode for inbound packets
* @port_to_init: Ports bound namespace-side, data to init L4 socket * @port_to_init: Ports bound namespace-side, data to init L4 socket
* @ns_detect_ports: If set, periodically detect ports bound in namespace * @fwd_mode_out: Port forwarding mode for outbound packets
* @timer_run: Timestamp of most recent timer run * @timer_run: Timestamp of most recent timer run
*/ */
struct udp_ctx { struct udp_ctx {
uint8_t port_to_tap [DIV_ROUND_UP(USHRT_MAX, 8)]; uint8_t port_to_tap [PORT_BITMAP_SIZE];
int init_detect_ports; enum port_fwd_mode fwd_mode_in;
uint8_t port_to_init [DIV_ROUND_UP(USHRT_MAX, 8)]; uint8_t port_to_init [PORT_BITMAP_SIZE];
int ns_detect_ports; enum port_fwd_mode fwd_mode_out;
struct timespec timer_run; struct timespec timer_run;
}; };