diff --git a/Makefile b/Makefile index 4ccca67..42bc0ac 100644 --- a/Makefile +++ b/Makefile @@ -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 \ 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 # On gcc 11.2, with -O2 and -flto, tcp_hash() and siphash_20b(), if inlined, diff --git a/conf.c b/conf.c index 7ecfa1e..8b1437d 100644 --- a/conf.c +++ b/conf.c @@ -64,14 +64,14 @@ void get_bound_ports(struct ctx *c, int ns, uint8_t proto) } 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, V6, 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); } 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, V6, ns, tcp_map, tcp_excl); } @@ -106,31 +106,25 @@ static int get_bound_ports_ns(void *arg) 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 * @c: Execution context * @optname: Short option name, t, T, u, or U * @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 */ 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; 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); + uint8_t exclude[PORT_BITMAP_SIZE] = { 0 }; char buf[BUFSIZ], *sep, *spec, *p; sa_family_t af = AF_UNSPEC; + uint8_t *map; if (optname == 't') { 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 (*set) return -EINVAL; - *set = PORT_NONE; + *set = FWD_NONE; return 0; } if (!strcmp(optarg, "auto")) { if (*set || c->mode != MODE_PASTA) return -EINVAL; - *set = PORT_AUTO; + *set = FWD_AUTO; return 0; } @@ -167,7 +161,7 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg, if (*set || c->mode != MODE_PASST) return -EINVAL; - *set = PORT_ALL; + *set = FWD_ALL; memset(map, 0xff, PORT_EPHEMERAL_MIN / 8); 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; } - if (*set > PORT_SPEC) + if (*set > FWD_SPEC) return -EINVAL; - *set = PORT_SPEC; + *set = FWD_SPEC; 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 }; 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; struct in6_addr *dns6 = c->ip6.dns; struct fqdn *dnss = c->dns_search; @@ -1103,6 +1095,9 @@ void conf(struct ctx *c, int argc, char **argv) if (c->mode == MODE_PASTA) 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 { const char *optstring; @@ -1553,7 +1548,7 @@ void conf(struct ctx *c, int argc, char **argv) /* Now we can process port configuration options */ optind = 1; do { - enum conf_port_type *set = NULL; + enum port_fwd_mode *fwd = NULL; const char *optstring; if (c->mode == MODE_PASST) @@ -1568,15 +1563,15 @@ void conf(struct ctx *c, int argc, char **argv) case 'T': case 'U': if (name == 't') - set = &tcp_tap; + fwd = &c->tcp.fwd_mode_in; else if (name == 'T') - set = &tcp_init; + fwd = &c->tcp.fwd_mode_out; else if (name == 'u') - set = &udp_tap; + fwd = &c->udp.fwd_mode_in; 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]); break; @@ -1605,33 +1600,39 @@ void conf(struct ctx *c, int argc, char **argv) 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) { 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_udp[V4][0] = c->proc_net_udp[V4][1] = -1; c->proc_net_udp[V6][0] = c->proc_net_udp[V6][1] = -1; - if (!tcp_tap || tcp_tap == PORT_AUTO) { - c->tcp.ns_detect_ports = 1; + if (!c->tcp.fwd_mode_in || c->tcp.fwd_mode_in == FWD_AUTO) { + c->tcp.fwd_mode_in = FWD_AUTO; ns_ports_arg.proto = IPPROTO_TCP; NS_CALL(get_bound_ports_ns, &ns_ports_arg); } - if (!udp_tap || udp_tap == PORT_AUTO) { - c->udp.ns_detect_ports = 1; + if (!c->udp.fwd_mode_in || c->udp.fwd_mode_in == FWD_AUTO) { + c->udp.fwd_mode_in = FWD_AUTO; ns_ports_arg.proto = IPPROTO_UDP; NS_CALL(get_bound_ports_ns, &ns_ports_arg); } - if (!tcp_init || tcp_init == PORT_AUTO) { - c->tcp.init_detect_ports = 1; + if (!c->tcp.fwd_mode_out || c->tcp.fwd_mode_out == FWD_AUTO) { + c->tcp.fwd_mode_out = FWD_AUTO; get_bound_ports(c, 0, IPPROTO_TCP); } - if (!udp_init || udp_init == PORT_AUTO) { - c->udp.init_detect_ports = 1; + if (!c->udp.fwd_mode_out || c->udp.fwd_mode_out == FWD_AUTO) { + c->udp.fwd_mode_out = FWD_AUTO; 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) diff --git a/passt.h b/passt.h index 8c8d710..48e1096 100644 --- a/passt.h +++ b/passt.h @@ -33,6 +33,7 @@ union epoll_ref; #include "packet.h" #include "icmp.h" +#include "port_fwd.h" #include "tcp.h" #include "udp.h" diff --git a/port_fwd.h b/port_fwd.h new file mode 100644 index 0000000..b938022 --- /dev/null +++ b/port_fwd.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later + * Copyright Red Hat + * Author: Stefano Brivio + * Author: David Gibson + */ + +#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 */ diff --git a/tcp.c b/tcp.c index ec8c32e..0bdef7f 100644 --- a/tcp.c +++ b/tcp.c @@ -3133,7 +3133,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, else s = -1; - if (c->tcp.init_detect_ports) + if (c->tcp.fwd_mode_in == FWD_AUTO) 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 s = -1; - if (c->tcp.ns_detect_ports) { + if (c->tcp.fwd_mode_out == FWD_AUTO) { if (ns) tcp_sock_ns[port][V4] = s; else @@ -3174,7 +3174,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, else s = -1; - if (c->tcp.init_detect_ports) + if (c->tcp.fwd_mode_in == FWD_AUTO) 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 s = -1; - if (c->tcp.ns_detect_ports) { + if (c->tcp.fwd_mode_out == FWD_AUTO) { if (ns) tcp_sock_ns[port][V6] = s; 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_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; tcp_port_detect(&detect_arg); rebind_arg.bind_in_ns = 1; 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; NS_CALL(tcp_port_detect, &detect_arg); rebind_arg.bind_in_ns = 0; diff --git a/tcp.h b/tcp.h index 6431b75..ed797d9 100644 --- a/tcp.h +++ b/tcp.h @@ -58,9 +58,9 @@ union tcp_epoll_ref { * @conn_count: Count of connections (not spliced) 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 - * @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 - * @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 * @kernel_snd_wnd: Kernel reports sending window (with commit 8f7baad7f035) * @pipe_size: Size of pipes for spliced connections @@ -69,10 +69,10 @@ struct tcp_ctx { uint64_t hash_secret[2]; int conn_count; int splice_conn_count; - uint8_t port_to_tap [DIV_ROUND_UP(USHRT_MAX, 8)]; - int init_detect_ports; - uint8_t port_to_init [DIV_ROUND_UP(USHRT_MAX, 8)]; - int ns_detect_ports; + uint8_t port_to_tap [PORT_BITMAP_SIZE]; + enum port_fwd_mode fwd_mode_in; + uint8_t port_to_init [PORT_BITMAP_SIZE]; + enum port_fwd_mode fwd_mode_out; struct timespec timer_run; #ifdef HAS_SND_WND int kernel_snd_wnd; diff --git a/udp.h b/udp.h index 8f82842..706306c 100644 --- a/udp.h +++ b/udp.h @@ -47,16 +47,16 @@ union udp_epoll_ref { /** * struct udp_ctx - Execution context for UDP * @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 - * @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 */ struct udp_ctx { - uint8_t port_to_tap [DIV_ROUND_UP(USHRT_MAX, 8)]; - int init_detect_ports; - uint8_t port_to_init [DIV_ROUND_UP(USHRT_MAX, 8)]; - int ns_detect_ports; + uint8_t port_to_tap [PORT_BITMAP_SIZE]; + enum port_fwd_mode fwd_mode_in; + uint8_t port_to_init [PORT_BITMAP_SIZE]; + enum port_fwd_mode fwd_mode_out; struct timespec timer_run; };