The configuration for how to forward ports in and out of the guest/ns is divided between several different variables. For each connect direction and protocol we have a mode in the udp/tcp context structure, a bitmap of which ports to forward also in the context structure and an array of deltas to apply if the outward facing and inward facing port numbers are different. This last is a separate global variable, rather than being in the context structure, for no particular reason. UDP also requires an additional array which has the reverse mapping used for return packets. Consolidate these into a re-used substructure in the context structure. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- conf.c | 74 ++++++++++++++++++++++++++-------------------------- port_fwd.h | 12 +++++++++ tcp.c | 42 ++++++++++++++--------------- tcp.h | 15 +++++------ tcp_splice.c | 4 +-- udp.c | 30 +++++++++------------ udp.h | 27 ++++++++++++------- 7 files changed, 106 insertions(+), 98 deletions(-) diff --git a/conf.c b/conf.c index 1ff43b7..f74a32f 100644 --- a/conf.c +++ b/conf.c @@ -52,15 +52,15 @@ void get_bound_ports(struct ctx *c, int ns, uint8_t proto) uint8_t *udp_map, *udp_excl, *tcp_map, *tcp_excl; if (ns) { - udp_map = c->udp.port_to_tap; - udp_excl = c->udp.port_to_init; - tcp_map = c->tcp.port_to_tap; - tcp_excl = c->tcp.port_to_init; + udp_map = c->udp.fwd_in.f.map; + udp_excl = c->udp.fwd_out.f.map; + tcp_map = c->tcp.fwd_in.map; + tcp_excl = c->tcp.fwd_out.map; } else { - udp_map = c->udp.port_to_init; - udp_excl = c->udp.port_to_tap; - tcp_map = c->tcp.port_to_init; - tcp_excl = c->tcp.port_to_tap; + udp_map = c->udp.fwd_out.f.map; + udp_excl = c->udp.fwd_in.f.map; + tcp_map = c->tcp.fwd_out.map; + tcp_excl = c->tcp.fwd_in.map; } if (proto == IPPROTO_UDP) { @@ -120,23 +120,23 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg, { 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; - void (*remap)(in_port_t port, in_port_t delta); + void (*remap)(struct ctx *c, in_port_t port, in_port_t delta); char buf[BUFSIZ], *sep, *spec, *p; port_fwd_map exclude = { 0 }; sa_family_t af = AF_UNSPEC; uint8_t *map; if (optname == 't') { - map = c->tcp.port_to_tap; + map = c->tcp.fwd_in.map; remap = tcp_remap_to_tap; } else if (optname == 'T') { - map = c->tcp.port_to_init; + map = c->tcp.fwd_out.map; remap = tcp_remap_to_init; } else if (optname == 'u') { - map = c->udp.port_to_tap; + map = c->udp.fwd_in.f.map; remap = udp_remap_to_tap; } else if (optname == 'U') { - map = c->udp.port_to_init; + map = c->udp.fwd_out.f.map; remap = udp_remap_to_init; } else { /* For gcc -O3 */ return 0; @@ -365,8 +365,8 @@ static int conf_ports(struct ctx *c, char optname, const char *optarg, if (start_dst != -1) { /* 80:8080 or 22-80:8080:8080 */ - remap(i, (in_port_t)(start_dst - - start_src)); + remap(c, i, (in_port_t)(start_dst - + start_src)); } if (optname == 't') @@ -1095,8 +1095,8 @@ 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; + c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = 0; + c->udp.fwd_in.f.mode = c->udp.fwd_out.f.mode = 0; do { const char *optstring; @@ -1563,13 +1563,13 @@ void conf(struct ctx *c, int argc, char **argv) case 'T': case 'U': if (name == 't') - fwd = &c->tcp.fwd_mode_in; + fwd = &c->tcp.fwd_in.mode; else if (name == 'T') - fwd = &c->tcp.fwd_mode_out; + fwd = &c->tcp.fwd_out.mode; else if (name == 'u') - fwd = &c->udp.fwd_mode_in; + fwd = &c->udp.fwd_in.f.mode; else if (name == 'U') - fwd = &c->udp.fwd_mode_out; + fwd = &c->udp.fwd_out.f.mode; if (!optarg || conf_ports(c, name, optarg, fwd)) usage(argv[0]); @@ -1606,33 +1606,33 @@ void conf(struct ctx *c, int argc, char **argv) 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 (!c->tcp.fwd_mode_in || c->tcp.fwd_mode_in == FWD_AUTO) { - c->tcp.fwd_mode_in = FWD_AUTO; + if (!c->tcp.fwd_in.mode || c->tcp.fwd_in.mode == FWD_AUTO) { + c->tcp.fwd_in.mode = FWD_AUTO; ns_ports_arg.proto = IPPROTO_TCP; NS_CALL(get_bound_ports_ns, &ns_ports_arg); } - if (!c->udp.fwd_mode_in || c->udp.fwd_mode_in == FWD_AUTO) { - c->udp.fwd_mode_in = FWD_AUTO; + if (!c->udp.fwd_in.f.mode || c->udp.fwd_in.f.mode == FWD_AUTO) { + c->udp.fwd_in.f.mode = FWD_AUTO; ns_ports_arg.proto = IPPROTO_UDP; NS_CALL(get_bound_ports_ns, &ns_ports_arg); } - if (!c->tcp.fwd_mode_out || c->tcp.fwd_mode_out == FWD_AUTO) { - c->tcp.fwd_mode_out = FWD_AUTO; + if (!c->tcp.fwd_out.mode || c->tcp.fwd_out.mode == FWD_AUTO) { + c->tcp.fwd_out.mode = FWD_AUTO; get_bound_ports(c, 0, IPPROTO_TCP); } - if (!c->udp.fwd_mode_out || c->udp.fwd_mode_out == FWD_AUTO) { - c->udp.fwd_mode_out = FWD_AUTO; + if (!c->udp.fwd_out.f.mode || c->udp.fwd_out.f.mode == FWD_AUTO) { + c->udp.fwd_out.f.mode = 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->tcp.fwd_in.mode) + c->tcp.fwd_in.mode = FWD_NONE; + if (!c->tcp.fwd_out.mode) + c->tcp.fwd_out.mode = FWD_NONE; + if (!c->udp.fwd_in.f.mode) + c->udp.fwd_in.f.mode = FWD_NONE; + if (!c->udp.fwd_out.f.mode) + c->udp.fwd_out.f.mode = FWD_NONE; } if (!c->quiet) diff --git a/port_fwd.h b/port_fwd.h index 5f6ad7e..5507bf2 100644 --- a/port_fwd.h +++ b/port_fwd.h @@ -16,4 +16,16 @@ enum port_fwd_mode { typedef uint8_t port_fwd_map[DIV_ROUND_UP(USHRT_MAX, 8)]; +/** + * port_fwd - Describes port forwarding for one protocol and direction + * @mode: Overall forwarding mode (all, none, auto, specific ports) + * @map: Bitmap describing which ports are forwarded + * @delta: Offset between the original destination and mapped port number + */ +struct port_fwd { + enum port_fwd_mode mode; + port_fwd_map map; + in_port_t delta[USHRT_MAX]; +}; + #endif /* PORT_FWD_H */ diff --git a/tcp.c b/tcp.c index 0bdef7f..e44177f 100644 --- a/tcp.c +++ b/tcp.c @@ -546,10 +546,6 @@ static const char *tcp_flag_str[] __attribute((__unused__)) = { "ACK_TO_TAP_DUE", "ACK_FROM_TAP_DUE", }; -/* Port re-mappings as delta, indexed by original destination port */ -static in_port_t tcp_port_delta_to_tap [USHRT_MAX]; -static in_port_t tcp_port_delta_to_init [USHRT_MAX]; - /* Listening sockets, used for automatic port forwarding in pasta mode only */ static int tcp_sock_init_lo [USHRT_MAX][IP_VERSIONS]; static int tcp_sock_init_ext [USHRT_MAX][IP_VERSIONS]; @@ -954,22 +950,24 @@ static void conn_event_do(const struct ctx *c, struct tcp_conn *conn, /** * tcp_remap_to_tap() - Set delta for port translation toward guest/tap + * @c: Execution context * @port: Original destination port, host order * @delta: Delta to be added to original destination port */ -void tcp_remap_to_tap(in_port_t port, in_port_t delta) +void tcp_remap_to_tap(struct ctx *c, in_port_t port, in_port_t delta) { - tcp_port_delta_to_tap[port] = delta; + c->tcp.fwd_in.delta[port] = delta; } /** * tcp_remap_to_tap() - Set delta for port translation toward init namespace + * @c: Execution context * @port: Original destination port, host order * @delta: Delta to be added to original destination port */ -void tcp_remap_to_init(in_port_t port, in_port_t delta) +void tcp_remap_to_init(struct ctx *c, in_port_t port, in_port_t delta) { - tcp_port_delta_to_init[port] = delta; + c->tcp.fwd_out.delta[port] = delta; } /** @@ -3109,11 +3107,9 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, int s; if (ns) { - tref.tcp.index = (in_port_t)(port + - tcp_port_delta_to_init[port]); + tref.tcp.index = (in_port_t)(port + c->tcp.fwd_out.delta[port]); } else { - tref.tcp.index = (in_port_t)(port + - tcp_port_delta_to_tap[port]); + tref.tcp.index = (in_port_t)(port + c->tcp.fwd_in.delta[port]); } if (af == AF_INET || af == AF_UNSPEC) { @@ -3133,7 +3129,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, else s = -1; - if (c->tcp.fwd_mode_in == FWD_AUTO) + if (c->tcp.fwd_in.mode == FWD_AUTO) tcp_sock_init_ext[port][V4] = s; } @@ -3148,7 +3144,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, else s = -1; - if (c->tcp.fwd_mode_out == FWD_AUTO) { + if (c->tcp.fwd_out.mode == FWD_AUTO) { if (ns) tcp_sock_ns[port][V4] = s; else @@ -3174,7 +3170,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, else s = -1; - if (c->tcp.fwd_mode_in == FWD_AUTO) + if (c->tcp.fwd_in.mode == FWD_AUTO) tcp_sock_init_ext[port][V6] = s; } @@ -3189,7 +3185,7 @@ void tcp_sock_init(const struct ctx *c, int ns, sa_family_t af, else s = -1; - if (c->tcp.fwd_mode_out == FWD_AUTO) { + if (c->tcp.fwd_out.mode == FWD_AUTO) { if (ns) tcp_sock_ns[port][V6] = s; else @@ -3213,7 +3209,7 @@ static int tcp_sock_init_ns(void *arg) ns_enter(c); for (port = 0; port < USHRT_MAX; port++) { - if (!bitmap_isset(c->tcp.port_to_init, port)) + if (!bitmap_isset(c->tcp.fwd_out.map, port)) continue; tcp_sock_init(c, 1, AF_UNSPEC, NULL, port); @@ -3413,7 +3409,7 @@ static int tcp_port_rebind(void *arg) ns_enter(a->c); for (port = 0; port < USHRT_MAX; port++) { - if (!bitmap_isset(a->c->tcp.port_to_init, port)) { + if (!bitmap_isset(a->c->tcp.fwd_out.map, port)) { if (tcp_sock_ns[port][V4] >= 0) { close(tcp_sock_ns[port][V4]); tcp_sock_ns[port][V4] = -1; @@ -3428,7 +3424,7 @@ static int tcp_port_rebind(void *arg) } /* Don't loop back our own ports */ - if (bitmap_isset(a->c->tcp.port_to_tap, port)) + if (bitmap_isset(a->c->tcp.fwd_in.map, port)) continue; if ((a->c->ifi4 && tcp_sock_ns[port][V4] == -1) || @@ -3437,7 +3433,7 @@ static int tcp_port_rebind(void *arg) } } else { for (port = 0; port < USHRT_MAX; port++) { - if (!bitmap_isset(a->c->tcp.port_to_tap, port)) { + if (!bitmap_isset(a->c->tcp.fwd_in.map, port)) { if (tcp_sock_init_ext[port][V4] >= 0) { close(tcp_sock_init_ext[port][V4]); tcp_sock_init_ext[port][V4] = -1; @@ -3461,7 +3457,7 @@ static int tcp_port_rebind(void *arg) } /* Don't loop back our own ports */ - if (bitmap_isset(a->c->tcp.port_to_init, port)) + if (bitmap_isset(a->c->tcp.fwd_out.map, port)) continue; if ((a->c->ifi4 && tcp_sock_init_ext[port][V4] == -1) || @@ -3489,14 +3485,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.fwd_mode_in == FWD_AUTO) { + if (c->tcp.fwd_in.mode == 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.fwd_mode_out == FWD_AUTO) { + if (c->tcp.fwd_out.mode == 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 58989db..502b096 100644 --- a/tcp.h +++ b/tcp.h @@ -29,8 +29,8 @@ void tcp_defer_handler(struct ctx *c); void tcp_sock_set_bufsize(const struct ctx *c, int s); void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, const uint32_t *ip_da); -void tcp_remap_to_tap(in_port_t port, in_port_t delta); -void tcp_remap_to_init(in_port_t port, in_port_t delta); +void tcp_remap_to_tap(struct ctx *c, in_port_t port, in_port_t delta); +void tcp_remap_to_init(struct ctx *c, in_port_t port, in_port_t delta); /** * union tcp_epoll_ref - epoll reference portion for TCP connections @@ -58,9 +58,8 @@ 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 - * @fwd_mode_in: Port forwarding mode for inbound packets - * @port_to_init: Ports bound namespace-side, spliced to init - * @fwd_mode_out: Port forwarding mode for outbound packets + * @fwd_in: Port forwarding configuration for inbound packets + * @fwd_out: Port forwarding configuration 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 +68,8 @@ struct tcp_ctx { uint64_t hash_secret[2]; int conn_count; int splice_conn_count; - port_fwd_map port_to_tap; - enum port_fwd_mode fwd_mode_in; - port_fwd_map port_to_init; - enum port_fwd_mode fwd_mode_out; + struct port_fwd fwd_in; + struct port_fwd fwd_out; struct timespec timer_run; #ifdef HAS_SND_WND int kernel_snd_wnd; diff --git a/tcp_splice.c b/tcp_splice.c index 61e9b23..edbcfd4 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -514,7 +514,7 @@ static int tcp_splice_new(const struct ctx *c, struct tcp_splice_conn *conn, struct tcp_splice_connect_ns_arg ns_arg = { c, conn, port, 0 }; int *p, i, s = -1; - if (bitmap_isset(c->tcp.port_to_tap, port)) + if (bitmap_isset(c->tcp.fwd_in.map, port)) p = CONN_V6(conn) ? ns_sock_pool6 : ns_sock_pool4; else p = CONN_V6(conn) ? init_sock_pool6 : init_sock_pool4; @@ -525,7 +525,7 @@ static int tcp_splice_new(const struct ctx *c, struct tcp_splice_conn *conn, break; } - if (s < 0 && bitmap_isset(c->tcp.port_to_tap, port)) { + if (s < 0 && bitmap_isset(c->tcp.fwd_in.map, port)) { NS_CALL(tcp_splice_connect_ns, &ns_arg); return ns_arg.ret; } diff --git a/udp.c b/udp.c index 0b4e134..38bb8d8 100644 --- a/udp.c +++ b/udp.c @@ -166,12 +166,6 @@ struct udp_splice_port { static struct udp_tap_port udp_tap_map [IP_VERSIONS][USHRT_MAX]; static struct udp_splice_port udp_splice_map [IP_VERSIONS][USHRT_MAX]; -/* Port re-mappings as delta, indexed by original destination port */ -static in_port_t udp_port_delta_to_tap [USHRT_MAX]; -static in_port_t udp_port_delta_from_tap [USHRT_MAX]; -static in_port_t udp_port_delta_to_init [USHRT_MAX]; -static in_port_t udp_port_delta_from_init[USHRT_MAX]; - enum udp_act_type { UDP_ACT_TAP, UDP_ACT_NS_CONN, @@ -265,24 +259,26 @@ static struct mmsghdr udp_mmh_sendto [UDP_SPLICE_FRAMES]; /** * udp_remap_to_tap() - Set delta for port translation to/from guest/tap + * @c: Execution context * @port: Original destination port, host order * @delta: Delta to be added to original destination port */ -void udp_remap_to_tap(in_port_t port, in_port_t delta) +void udp_remap_to_tap(struct ctx *c, in_port_t port, in_port_t delta) { - udp_port_delta_to_tap[port] = delta; - udp_port_delta_from_tap[port + delta] = USHRT_MAX - delta; + c->udp.fwd_in.f.delta[port] = delta; + c->udp.fwd_in.rdelta[port + delta] = USHRT_MAX - delta; } /** * udp_remap_to_init() - Set delta for port translation to/from init namespace + * @c: Execution context * @port: Original destination port, host order * @delta: Delta to be added to original destination port */ -void udp_remap_to_init(in_port_t port, in_port_t delta) +void udp_remap_to_init(struct ctx *c, in_port_t port, in_port_t delta) { - udp_port_delta_to_init[port] = delta; - udp_port_delta_from_init[port + delta] = USHRT_MAX - delta; + c->udp.fwd_out.f.delta[port] = delta; + c->udp.fwd_out.rdelta[port + delta] = USHRT_MAX - delta; } /** @@ -583,7 +579,7 @@ static void udp_sock_handler_splice(const struct ctx *c, union epoll_ref ref, switch (ref.r.p.udp.udp.splice) { case UDP_TO_NS: - src += udp_port_delta_from_init[src]; + src += c->udp.fwd_out.rdelta[src]; if (!(s = udp_splice_map[v6][src].ns_conn_sock)) { struct udp_splice_connect_ns_arg arg = { @@ -603,7 +599,7 @@ static void udp_sock_handler_splice(const struct ctx *c, union epoll_ref ref, send_dst = udp_splice_map[v6][dst].init_dst_port; break; case UDP_TO_INIT: - src += udp_port_delta_from_tap[src]; + src += c->udp.fwd_in.rdelta[src]; if (!(s = udp_splice_map[v6][src].init_conn_sock)) { s = udp_splice_connect(c, v6, ref.r.s, src, dst, @@ -1121,10 +1117,10 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af, if (ns) { uref.udp.port = (in_port_t)(port + - udp_port_delta_to_init[port]); + c->udp.fwd_out.f.delta[port]); } else { uref.udp.port = (in_port_t)(port + - udp_port_delta_to_tap[port]); + c->udp.fwd_in.f.delta[port]); } if (af == AF_INET || af == AF_UNSPEC) { @@ -1209,7 +1205,7 @@ int udp_sock_init_ns(void *arg) return 0; for (dst = 0; dst < USHRT_MAX; dst++) { - if (!bitmap_isset(c->udp.port_to_init, dst)) + if (!bitmap_isset(c->udp.fwd_out.f.map, dst)) continue; udp_sock_init(c, 1, AF_UNSPEC, NULL, dst); diff --git a/udp.h b/udp.h index 0283ce6..cfd1a97 100644 --- a/udp.h +++ b/udp.h @@ -18,8 +18,8 @@ int udp_init(const struct ctx *c); void udp_timer(struct ctx *c, const struct timespec *ts); void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s, const uint32_t *ip_da); -void udp_remap_to_tap(in_port_t port, in_port_t delta); -void udp_remap_to_init(in_port_t port, in_port_t delta); +void udp_remap_to_tap(struct ctx *c, in_port_t port, in_port_t delta); +void udp_remap_to_init(struct ctx *c, in_port_t port, in_port_t delta); /** * union udp_epoll_ref - epoll reference portion for TCP connections @@ -44,19 +44,26 @@ union udp_epoll_ref { uint32_t u32; }; + +/** + * udp_port_fwd - UDP specific port forwarding configuration + * @f: Generic forwarding configuration + * @rdelta: Reversed delta map to translate source ports on return packets + */ +struct udp_port_fwd { + struct port_fwd f; + in_port_t rdelta[USHRT_MAX]; +}; + /** * struct udp_ctx - Execution context for UDP - * @port_to_tap: Ports bound host-side, data to tap or ns L4 socket - * @fwd_mode_in: Port forwarding mode for inbound packets - * @port_to_init: Ports bound namespace-side, data to init L4 socket - * @fwd_mode_out: Port forwarding mode for outbound packets + * @fwd_in: Port forwarding configuration for inbound packets + * @fwd_out: Port forwarding configuration for outbound packets * @timer_run: Timestamp of most recent timer run */ struct udp_ctx { - port_fwd_map port_to_tap; - enum port_fwd_mode fwd_mode_in; - port_fwd_map port_to_init; - enum port_fwd_mode fwd_mode_out; + struct udp_port_fwd fwd_in; + struct udp_port_fwd fwd_out; struct timespec timer_run; }; -- 2.37.3