conf, tcp: Periodic detection of bound ports for pasta port forwarding
Detecting bound ports at start-up time isn't terribly useful: do this periodically instead, if configured. This is only implemented for TCP at the moment, UDP is somewhat more complicated: leave a TODO there. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
e69e13671d
commit
9657b6ed05
8 changed files with 316 additions and 97 deletions
85
conf.c
85
conf.c
|
@ -39,6 +39,42 @@
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_bound_ports() - Get maps of ports with bound sockets
|
||||||
|
* @c: Execution context
|
||||||
|
* @ns: If set, set bitmaps for ports to tap/ns -- to init otherwise
|
||||||
|
* @proto: Protocol number (IPPROTO_TCP or IPPROTO_UDP)
|
||||||
|
*/
|
||||||
|
void get_bound_ports(struct ctx *c, int ns, uint8_t proto)
|
||||||
|
{
|
||||||
|
uint8_t *udp_map, *udp_exclude, *tcp_map, *tcp_exclude;
|
||||||
|
|
||||||
|
if (ns) {
|
||||||
|
udp_map = c->udp.port_to_tap;
|
||||||
|
udp_exclude = c->udp.port_to_init;
|
||||||
|
tcp_map = c->tcp.port_to_tap;
|
||||||
|
tcp_exclude = c->tcp.port_to_init;
|
||||||
|
} else {
|
||||||
|
udp_map = c->udp.port_to_init;
|
||||||
|
udp_exclude = c->udp.port_to_tap;
|
||||||
|
tcp_map = c->tcp.port_to_init;
|
||||||
|
tcp_exclude = c->tcp.port_to_tap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto == IPPROTO_UDP) {
|
||||||
|
memset(udp_map, 0, USHRT_MAX / 8);
|
||||||
|
procfs_scan_listen("udp", udp_map, udp_exclude);
|
||||||
|
procfs_scan_listen("udp6", udp_map, udp_exclude);
|
||||||
|
|
||||||
|
procfs_scan_listen("tcp", udp_map, udp_exclude);
|
||||||
|
procfs_scan_listen("tcp6", udp_map, udp_exclude);
|
||||||
|
} else if (proto == IPPROTO_TCP) {
|
||||||
|
memset(tcp_map, 0, USHRT_MAX / 8);
|
||||||
|
procfs_scan_listen("tcp", tcp_map, tcp_exclude);
|
||||||
|
procfs_scan_listen("tcp6", tcp_map, tcp_exclude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct get_bound_ports_ns_arg - Arguments for get_bound_ports_ns()
|
* struct get_bound_ports_ns_arg - Arguments for get_bound_ports_ns()
|
||||||
* @c: Execution context
|
* @c: Execution context
|
||||||
|
@ -50,7 +86,7 @@ struct get_bound_ports_ns_arg {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get_bound_ports_ns() - Get maps of ports namespace with bound sockets
|
* get_bound_ports_ns() - Get maps of ports in namespace with bound sockets
|
||||||
* @arg: See struct get_bound_ports_ns_arg
|
* @arg: See struct get_bound_ports_ns_arg
|
||||||
*
|
*
|
||||||
* Return: 0
|
* Return: 0
|
||||||
|
@ -63,39 +99,11 @@ static int get_bound_ports_ns(void *arg)
|
||||||
if (!c->pasta_pid || ns_enter(c->pasta_pid))
|
if (!c->pasta_pid || ns_enter(c->pasta_pid))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (a->proto == IPPROTO_UDP) {
|
get_bound_ports(c, 1, a->proto);
|
||||||
procfs_scan_listen("udp", c->udp.port_to_tap);
|
|
||||||
procfs_scan_listen("udp6", c->udp.port_to_tap);
|
|
||||||
|
|
||||||
procfs_scan_listen("tcp", c->udp.port_to_tap);
|
|
||||||
procfs_scan_listen("tcp6", c->udp.port_to_tap);
|
|
||||||
} else if (a->proto == IPPROTO_TCP) {
|
|
||||||
procfs_scan_listen("tcp", c->tcp.port_to_tap);
|
|
||||||
procfs_scan_listen("tcp6", c->tcp.port_to_tap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* get_bound_ports() - Get maps of ports in init namespace with bound sockets
|
|
||||||
* @c: Execution context
|
|
||||||
* @proto: Protocol number (IPPROTO_TCP or IPPROTO_UDP)
|
|
||||||
*/
|
|
||||||
static void get_bound_ports(struct ctx *c, uint8_t proto)
|
|
||||||
{
|
|
||||||
if (proto == IPPROTO_UDP) {
|
|
||||||
procfs_scan_listen("udp", c->udp.port_to_init);
|
|
||||||
procfs_scan_listen("udp6", c->udp.port_to_init);
|
|
||||||
|
|
||||||
procfs_scan_listen("tcp", c->udp.port_to_init);
|
|
||||||
procfs_scan_listen("tcp6", c->udp.port_to_init);
|
|
||||||
} else if (proto == IPPROTO_TCP) {
|
|
||||||
procfs_scan_listen("tcp", c->tcp.port_to_init);
|
|
||||||
procfs_scan_listen("tcp6", c->tcp.port_to_init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum conf_port_type {
|
enum conf_port_type {
|
||||||
PORT_SPEC = 1,
|
PORT_SPEC = 1,
|
||||||
PORT_NONE,
|
PORT_NONE,
|
||||||
|
@ -1172,19 +1180,28 @@ void conf(struct ctx *c, int argc, char **argv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
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) {
|
||||||
if (!tcp_tap || tcp_tap == PORT_AUTO) {
|
if (!tcp_tap || tcp_tap == PORT_AUTO) {
|
||||||
|
c->tcp.ns_detect_ports = 1;
|
||||||
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 (!udp_tap || udp_tap == PORT_AUTO) {
|
||||||
|
c->udp.ns_detect_ports = 1;
|
||||||
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 (!tcp_init || tcp_init == PORT_AUTO) {
|
||||||
get_bound_ports(c, IPPROTO_TCP);
|
c->tcp.init_detect_ports = 1;
|
||||||
if (!udp_init || udp_init == PORT_AUTO)
|
get_bound_ports(c, 0, IPPROTO_TCP);
|
||||||
get_bound_ports(c, IPPROTO_UDP);
|
}
|
||||||
|
if (!udp_init || udp_init == PORT_AUTO) {
|
||||||
|
c->udp.init_detect_ports = 1;
|
||||||
|
get_bound_ports(c, 0, IPPROTO_UDP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conf_print(c);
|
conf_print(c);
|
||||||
|
|
1
conf.h
1
conf.h
|
@ -1 +1,2 @@
|
||||||
void conf(struct ctx *c, int argc, char **argv);
|
void conf(struct ctx *c, int argc, char **argv);
|
||||||
|
void get_bound_ports(struct ctx *c, int ns, uint8_t proto);
|
||||||
|
|
15
passt.1
15
passt.1
|
@ -297,9 +297,9 @@ Don't forward any ports
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR auto
|
.BR auto
|
||||||
Forward all ports currently bound in the namespace. The list of ports is derived
|
Dynamically forward ports bound in the namespace. The list of ports is
|
||||||
from listening sockets reported by \fI/proc/net/tcp\fR and \fI/proc/net/tcp6\fR,
|
periodically derived (every second) from listening sockets reported by
|
||||||
see \fBproc\fR(5).
|
\fI/proc/net/tcp\fR and \fI/proc/net/tcp6\fR, see \fBproc\fR(5).
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR ports
|
.BR ports
|
||||||
|
@ -331,9 +331,10 @@ Default is \fBauto\fR.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-u ", " \-\-udp-ports " " \fIspec
|
.BR \-u ", " \-\-udp-ports " " \fIspec
|
||||||
Configure UDP port forwarding to guest. \fIspec\fR is as described for TCP
|
Configure UDP port forwarding to namespace. \fIspec\fR is as described for TCP
|
||||||
above, and the list of ports is derived from listening sockets reported by
|
above, and the list of ports is derived from listening sockets reported by
|
||||||
\fI/proc/net/udp\fR and \fI/proc/net/udp6\fR, see \fBproc\fR(5).
|
\fI/proc/net/udp\fR and \fI/proc/net/udp6\fR, see \fBproc\fR(5),
|
||||||
|
when \fBpasta\fR starts (not periodically).
|
||||||
|
|
||||||
Note: unless overridden, UDP ports with numbers corresponding to forwarded TCP
|
Note: unless overridden, UDP ports with numbers corresponding to forwarded TCP
|
||||||
port numbers are forwarded too, without, however, any port translation.
|
port numbers are forwarded too, without, however, any port translation.
|
||||||
|
@ -345,14 +346,14 @@ Default is \fBauto\fR.
|
||||||
.TP
|
.TP
|
||||||
.BR \-T ", " \-\-tcp-ns " " \fIspec
|
.BR \-T ", " \-\-tcp-ns " " \fIspec
|
||||||
Configure TCP port forwarding from target namespace to init namespace.
|
Configure TCP port forwarding from target namespace to init namespace.
|
||||||
\fIspec\fR is as described above.
|
\fIspec\fR is as described above for TCP.
|
||||||
|
|
||||||
Default is \fBauto\fR.
|
Default is \fBauto\fR.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-U ", " \-\-udp-ns " " \fIspec
|
.BR \-U ", " \-\-udp-ns " " \fIspec
|
||||||
Configure UDP port forwarding from target namespace to init namespace.
|
Configure UDP port forwarding from target namespace to init namespace.
|
||||||
\fIspec\fR is as described above.
|
\fIspec\fR is as described above for UDP.
|
||||||
|
|
||||||
Default is \fBauto\fR.
|
Default is \fBauto\fR.
|
||||||
|
|
||||||
|
|
292
tcp.c
292
tcp.c
|
@ -334,6 +334,7 @@
|
||||||
#include "tap.h"
|
#include "tap.h"
|
||||||
#include "siphash.h"
|
#include "siphash.h"
|
||||||
#include "pcap.h"
|
#include "pcap.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
#define MAX_TAP_CONNS (128 * 1024)
|
#define MAX_TAP_CONNS (128 * 1024)
|
||||||
#define MAX_SPLICE_CONNS (128 * 1024)
|
#define MAX_SPLICE_CONNS (128 * 1024)
|
||||||
|
@ -363,6 +364,8 @@
|
||||||
#define TCP_SPLICE_PIPE_POOL_SIZE 256
|
#define TCP_SPLICE_PIPE_POOL_SIZE 256
|
||||||
#define REFILL_INTERVAL 1000
|
#define REFILL_INTERVAL 1000
|
||||||
|
|
||||||
|
#define PORT_DETECT_INTERVAL 1000
|
||||||
|
|
||||||
/* We need to include <linux/tcp.h> for tcpi_bytes_acked, instead of
|
/* We need to include <linux/tcp.h> for tcpi_bytes_acked, instead of
|
||||||
* <netinet/tcp.h>, but that doesn't include a definition for SOL_TCP
|
* <netinet/tcp.h>, but that doesn't include a definition for SOL_TCP
|
||||||
*/
|
*/
|
||||||
|
@ -525,6 +528,11 @@ struct tcp_splice_conn {
|
||||||
static in_port_t tcp_port_delta_to_tap [USHRT_MAX];
|
static in_port_t tcp_port_delta_to_tap [USHRT_MAX];
|
||||||
static in_port_t tcp_port_delta_to_init [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];
|
||||||
|
static int tcp_sock_ns [USHRT_MAX][IP_VERSIONS];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tcp_remap_to_tap() - Set delta for port translation toward guest/tap
|
* tcp_remap_to_tap() - Set delta for port translation toward guest/tap
|
||||||
* @port: Original destination port, host order
|
* @port: Original destination port, host order
|
||||||
|
@ -3001,6 +3009,93 @@ smaller:
|
||||||
goto smaller;
|
goto smaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tcp_sock_init_one() - Initialise listening sockets for a given port
|
||||||
|
* @c: Execution context
|
||||||
|
* @ns: In pasta mode, if set, bind with loopback address in namespace
|
||||||
|
* @port: Port, host order
|
||||||
|
*/
|
||||||
|
static void tcp_sock_init_one(struct ctx *c, int ns, in_port_t port)
|
||||||
|
{
|
||||||
|
union tcp_epoll_ref tref = { .listen = 1 };
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if (ns)
|
||||||
|
tref.index = (in_port_t)(port + tcp_port_delta_to_init[port]);
|
||||||
|
else
|
||||||
|
tref.index = (in_port_t)(port + tcp_port_delta_to_tap[port]);
|
||||||
|
|
||||||
|
if (c->v4) {
|
||||||
|
tref.v6 = 0;
|
||||||
|
|
||||||
|
tref.splice = 0;
|
||||||
|
if (!ns) {
|
||||||
|
s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
|
||||||
|
c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
|
||||||
|
tref.u32);
|
||||||
|
if (s > 0)
|
||||||
|
tcp_sock_set_bufsize(s);
|
||||||
|
else
|
||||||
|
s = -1;
|
||||||
|
|
||||||
|
if (c->tcp.init_detect_ports)
|
||||||
|
tcp_sock_init_ext[port][V4] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->mode == MODE_PASTA) {
|
||||||
|
tref.splice = 1;
|
||||||
|
s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
|
||||||
|
BIND_LOOPBACK, tref.u32);
|
||||||
|
if (s > 0)
|
||||||
|
tcp_sock_set_bufsize(s);
|
||||||
|
else
|
||||||
|
s = -1;
|
||||||
|
|
||||||
|
if (c->tcp.ns_detect_ports) {
|
||||||
|
if (ns)
|
||||||
|
tcp_sock_ns[port][V4] = s;
|
||||||
|
else
|
||||||
|
tcp_sock_init_lo[port][V4] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->v6) {
|
||||||
|
tref.v6 = 1;
|
||||||
|
|
||||||
|
tref.splice = 0;
|
||||||
|
if (!ns) {
|
||||||
|
s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
|
||||||
|
c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
|
||||||
|
tref.u32);
|
||||||
|
if (s > 0)
|
||||||
|
tcp_sock_set_bufsize(s);
|
||||||
|
else
|
||||||
|
s = -1;
|
||||||
|
|
||||||
|
if (c->tcp.init_detect_ports)
|
||||||
|
tcp_sock_init_ext[port][V6] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->mode == MODE_PASTA) {
|
||||||
|
tref.splice = 1;
|
||||||
|
s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
|
||||||
|
BIND_LOOPBACK, tref.u32);
|
||||||
|
if (s > 0)
|
||||||
|
tcp_sock_set_bufsize(s);
|
||||||
|
else
|
||||||
|
s = -1;
|
||||||
|
|
||||||
|
if (c->tcp.ns_detect_ports) {
|
||||||
|
if (ns)
|
||||||
|
tcp_sock_ns[port][V6] = s;
|
||||||
|
else
|
||||||
|
tcp_sock_init_lo[port][V6] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tcp_sock_init_ns() - Bind sockets in namespace for inbound connections
|
* tcp_sock_init_ns() - Bind sockets in namespace for inbound connections
|
||||||
* @arg: Execution context
|
* @arg: Execution context
|
||||||
|
@ -3009,10 +3104,8 @@ smaller:
|
||||||
*/
|
*/
|
||||||
static int tcp_sock_init_ns(void *arg)
|
static int tcp_sock_init_ns(void *arg)
|
||||||
{
|
{
|
||||||
union tcp_epoll_ref tref = { .listen = 1, .splice = 1 };
|
|
||||||
struct ctx *c = (struct ctx *)arg;
|
struct ctx *c = (struct ctx *)arg;
|
||||||
in_port_t port;
|
in_port_t port;
|
||||||
int s;
|
|
||||||
|
|
||||||
ns_enter(c->pasta_pid);
|
ns_enter(c->pasta_pid);
|
||||||
|
|
||||||
|
@ -3020,21 +3113,7 @@ static int tcp_sock_init_ns(void *arg)
|
||||||
if (!bitmap_isset(c->tcp.port_to_init, port))
|
if (!bitmap_isset(c->tcp.port_to_init, port))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tref.index = (in_port_t)(port + tcp_port_delta_to_init[port]);
|
tcp_sock_init_one(c, 1, port);
|
||||||
|
|
||||||
if (c->v4) {
|
|
||||||
tref.v6 = 0;
|
|
||||||
s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
|
|
||||||
BIND_LOOPBACK, tref.u32);
|
|
||||||
tcp_sock_set_bufsize(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->v6) {
|
|
||||||
tref.v6 = 1;
|
|
||||||
s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
|
|
||||||
BIND_LOOPBACK, tref.u32);
|
|
||||||
tcp_sock_set_bufsize(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3128,9 +3207,7 @@ static int tcp_sock_refill(void *arg)
|
||||||
int tcp_sock_init(struct ctx *c, struct timespec *now)
|
int tcp_sock_init(struct ctx *c, struct timespec *now)
|
||||||
{
|
{
|
||||||
struct tcp_sock_refill_arg refill_arg = { c, 0 };
|
struct tcp_sock_refill_arg refill_arg = { c, 0 };
|
||||||
union tcp_epoll_ref tref = { .listen = 1 };
|
|
||||||
in_port_t port;
|
in_port_t port;
|
||||||
int s;
|
|
||||||
|
|
||||||
getrandom(&c->tcp.hash_secret, sizeof(c->tcp.hash_secret), GRND_RANDOM);
|
getrandom(&c->tcp.hash_secret, sizeof(c->tcp.hash_secret), GRND_RANDOM);
|
||||||
|
|
||||||
|
@ -3138,40 +3215,7 @@ int tcp_sock_init(struct ctx *c, struct timespec *now)
|
||||||
if (!bitmap_isset(c->tcp.port_to_tap, port))
|
if (!bitmap_isset(c->tcp.port_to_tap, port))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tref.index = (in_port_t)(port + tcp_port_delta_to_tap[port]);
|
tcp_sock_init_one(c, 0, port);
|
||||||
if (c->v4) {
|
|
||||||
tref.v6 = 0;
|
|
||||||
|
|
||||||
tref.splice = 0;
|
|
||||||
s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
|
|
||||||
c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
|
|
||||||
tref.u32);
|
|
||||||
tcp_sock_set_bufsize(s);
|
|
||||||
|
|
||||||
if (c->mode == MODE_PASTA) {
|
|
||||||
tref.splice = 1;
|
|
||||||
s = sock_l4(c, AF_INET, IPPROTO_TCP, port,
|
|
||||||
BIND_LOOPBACK, tref.u32);
|
|
||||||
tcp_sock_set_bufsize(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->v6) {
|
|
||||||
tref.v6 = 1;
|
|
||||||
|
|
||||||
tref.splice = 0;
|
|
||||||
s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
|
|
||||||
c->mode == MODE_PASTA ? BIND_EXT : BIND_ANY,
|
|
||||||
tref.u32);
|
|
||||||
tcp_sock_set_bufsize(s);
|
|
||||||
|
|
||||||
if (c->mode == MODE_PASTA) {
|
|
||||||
tref.splice = 1;
|
|
||||||
s = sock_l4(c, AF_INET6, IPPROTO_TCP, port,
|
|
||||||
BIND_LOOPBACK, tref.u32);
|
|
||||||
tcp_sock_set_bufsize(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->v4)
|
if (c->v4)
|
||||||
|
@ -3190,6 +3234,8 @@ int tcp_sock_init(struct ctx *c, struct timespec *now)
|
||||||
refill_arg.ns = 1;
|
refill_arg.ns = 1;
|
||||||
NS_CALL(tcp_sock_refill, &refill_arg);
|
NS_CALL(tcp_sock_refill, &refill_arg);
|
||||||
tcp_splice_pipe_refill(c);
|
tcp_splice_pipe_refill(c);
|
||||||
|
|
||||||
|
c->tcp.port_detect_ts = *now;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3283,6 +3329,122 @@ static void tcp_timer_one(struct ctx *c, struct tcp_tap_conn *conn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct tcp_port_detect_arg - Arguments for tcp_port_detect()
|
||||||
|
* @c: Execution context
|
||||||
|
* @detect_in_ns: Detect ports bound in namespace, not in init
|
||||||
|
*/
|
||||||
|
struct tcp_port_detect_arg {
|
||||||
|
struct ctx *c;
|
||||||
|
int detect_in_ns;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tcp_port_detect() - Detect ports bound in namespace or init
|
||||||
|
* @arg: See struct tcp_port_detect_arg
|
||||||
|
*
|
||||||
|
* Return: 0
|
||||||
|
*/
|
||||||
|
static int tcp_port_detect(void *arg)
|
||||||
|
{
|
||||||
|
struct tcp_port_detect_arg *a = (struct tcp_port_detect_arg *)arg;
|
||||||
|
|
||||||
|
if (a->detect_in_ns) {
|
||||||
|
ns_enter(a->c->pasta_pid);
|
||||||
|
|
||||||
|
get_bound_ports(a->c, 1, IPPROTO_TCP);
|
||||||
|
} else {
|
||||||
|
get_bound_ports(a->c, 0, IPPROTO_TCP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct tcp_port_rebind_arg - Arguments for tcp_port_rebind()
|
||||||
|
* @c: Execution context
|
||||||
|
* @bind_in_ns: Rebind ports in namespace, not in init
|
||||||
|
*/
|
||||||
|
struct tcp_port_rebind_arg {
|
||||||
|
struct ctx *c;
|
||||||
|
int bind_in_ns;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tcp_port_rebind() - Rebind ports in namespace or init
|
||||||
|
* @arg: See struct tcp_port_rebind_arg
|
||||||
|
*
|
||||||
|
* Return: 0
|
||||||
|
*/
|
||||||
|
static int tcp_port_rebind(void *arg)
|
||||||
|
{
|
||||||
|
struct tcp_port_rebind_arg *a = (struct tcp_port_rebind_arg *)arg;
|
||||||
|
in_port_t port;
|
||||||
|
|
||||||
|
if (a->bind_in_ns) {
|
||||||
|
ns_enter(a->c->pasta_pid);
|
||||||
|
|
||||||
|
for (port = 0; port < USHRT_MAX; port++) {
|
||||||
|
if (!bitmap_isset(a->c->tcp.port_to_init, port)) {
|
||||||
|
if (tcp_sock_ns[port][V4] > 0) {
|
||||||
|
close(tcp_sock_ns[port][V4]);
|
||||||
|
tcp_sock_ns[port][V4] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_sock_ns[port][V6] > 0) {
|
||||||
|
close(tcp_sock_ns[port][V6]);
|
||||||
|
tcp_sock_ns[port][V6] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't loop back our own ports */
|
||||||
|
if (bitmap_isset(a->c->tcp.port_to_tap, port))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((a->c->v4 && !tcp_sock_ns[port][V4]) ||
|
||||||
|
(a->c->v6 && !tcp_sock_ns[port][V6]))
|
||||||
|
tcp_sock_init_one(a->c, 1, port);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (port = 0; port < USHRT_MAX; port++) {
|
||||||
|
if (!bitmap_isset(a->c->tcp.port_to_tap, port)) {
|
||||||
|
if (tcp_sock_init_ext[port][V4] > 0) {
|
||||||
|
close(tcp_sock_init_ext[port][V4]);
|
||||||
|
tcp_sock_init_ext[port][V4] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_sock_init_ext[port][V6] > 0) {
|
||||||
|
close(tcp_sock_init_ext[port][V6]);
|
||||||
|
tcp_sock_init_ext[port][V6] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_sock_init_lo[port][V4] > 0) {
|
||||||
|
close(tcp_sock_init_lo[port][V4]);
|
||||||
|
tcp_sock_init_lo[port][V4] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_sock_init_lo[port][V6] > 0) {
|
||||||
|
close(tcp_sock_init_lo[port][V6]);
|
||||||
|
tcp_sock_init_lo[port][V6] = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't loop back our own ports */
|
||||||
|
if (bitmap_isset(a->c->tcp.port_to_init, port))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((a->c->v4 && !tcp_sock_init_ext[port][V4]) ||
|
||||||
|
(a->c->v6 && !tcp_sock_init_ext[port][V6]))
|
||||||
|
tcp_sock_init_one(a->c, 0, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tcp_timer() - Scan activity bitmap for sockets waiting for timed events
|
* tcp_timer() - Scan activity bitmap for sockets waiting for timed events
|
||||||
* @c: Execution context
|
* @c: Execution context
|
||||||
|
@ -3293,6 +3455,30 @@ void tcp_timer(struct ctx *c, struct timespec *now)
|
||||||
struct tcp_sock_refill_arg refill_arg = { c, 0 };
|
struct tcp_sock_refill_arg refill_arg = { c, 0 };
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (c->mode == MODE_PASTA) {
|
||||||
|
if (timespec_diff_ms(now, &c->tcp.port_detect_ts) >
|
||||||
|
PORT_DETECT_INTERVAL) {
|
||||||
|
struct tcp_port_detect_arg detect_arg = { c, 0 };
|
||||||
|
struct tcp_port_rebind_arg rebind_arg = { c, 0 };
|
||||||
|
|
||||||
|
if (c->tcp.init_detect_ports) {
|
||||||
|
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) {
|
||||||
|
detect_arg.detect_in_ns = 1;
|
||||||
|
NS_CALL(tcp_port_detect, &detect_arg);
|
||||||
|
rebind_arg.bind_in_ns = 0;
|
||||||
|
tcp_port_rebind(&rebind_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
c->tcp.port_detect_ts = *now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (timespec_diff_ms(now, &c->tcp.refill_ts) > REFILL_INTERVAL) {
|
if (timespec_diff_ms(now, &c->tcp.refill_ts) > REFILL_INTERVAL) {
|
||||||
tcp_sock_refill(&refill_arg);
|
tcp_sock_refill(&refill_arg);
|
||||||
if (c->mode == MODE_PASTA) {
|
if (c->mode == MODE_PASTA) {
|
||||||
|
|
6
tcp.h
6
tcp.h
|
@ -43,22 +43,28 @@ union tcp_epoll_ref {
|
||||||
* @tap_conn_count: Count of tap connections in connection table
|
* @tap_conn_count: Count of tap connections 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
|
||||||
* @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
|
||||||
* @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
|
||||||
* @refill_ts: Time of last refill operation for pools of sockets/pipes
|
* @refill_ts: Time of last refill operation for pools of sockets/pipes
|
||||||
|
* @port_detect_ts: Time of last TCP port detection/rebind, if enabled
|
||||||
*/
|
*/
|
||||||
struct tcp_ctx {
|
struct tcp_ctx {
|
||||||
uint64_t hash_secret[2];
|
uint64_t hash_secret[2];
|
||||||
int tap_conn_count;
|
int tap_conn_count;
|
||||||
int splice_conn_count;
|
int splice_conn_count;
|
||||||
uint8_t port_to_tap [USHRT_MAX / 8];
|
uint8_t port_to_tap [USHRT_MAX / 8];
|
||||||
|
int init_detect_ports;
|
||||||
uint8_t port_to_init [USHRT_MAX / 8];
|
uint8_t port_to_init [USHRT_MAX / 8];
|
||||||
|
int ns_detect_ports;
|
||||||
struct timespec timer_run;
|
struct timespec timer_run;
|
||||||
int kernel_snd_wnd;
|
int kernel_snd_wnd;
|
||||||
size_t pipe_size;
|
size_t pipe_size;
|
||||||
struct timespec refill_ts;
|
struct timespec refill_ts;
|
||||||
|
struct timespec port_detect_ts;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* TCP_H */
|
#endif /* TCP_H */
|
||||||
|
|
4
udp.h
4
udp.h
|
@ -40,12 +40,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)
|
||||||
* @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
|
||||||
* @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 [USHRT_MAX / 8];
|
uint8_t port_to_tap [USHRT_MAX / 8];
|
||||||
|
int init_detect_ports;
|
||||||
uint8_t port_to_init [USHRT_MAX / 8];
|
uint8_t port_to_init [USHRT_MAX / 8];
|
||||||
|
int ns_detect_ports;
|
||||||
struct timespec timer_run;
|
struct timespec timer_run;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
6
util.c
6
util.c
|
@ -266,8 +266,9 @@ int bitmap_isset(uint8_t *map, int bit)
|
||||||
* procfs_scan_listen() - Set bits for listening TCP or UDP sockets from procfs
|
* procfs_scan_listen() - Set bits for listening TCP or UDP sockets from procfs
|
||||||
* @name: Corresponding name of file under /proc/net/
|
* @name: Corresponding name of file under /proc/net/
|
||||||
* @map: Bitmap where numbers of ports in listening state will be set
|
* @map: Bitmap where numbers of ports in listening state will be set
|
||||||
|
* @exclude: Bitmap of ports to exclude from setting (and clear)
|
||||||
*/
|
*/
|
||||||
void procfs_scan_listen(char *name, uint8_t *map)
|
void procfs_scan_listen(char *name, uint8_t *map, uint8_t *exclude)
|
||||||
{
|
{
|
||||||
char line[200], path[PATH_MAX];
|
char line[200], path[PATH_MAX];
|
||||||
unsigned long port;
|
unsigned long port;
|
||||||
|
@ -288,6 +289,9 @@ void procfs_scan_listen(char *name, uint8_t *map)
|
||||||
(strstr(name, "udp") && state != 0x07))
|
(strstr(name, "udp") && state != 0x07))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (bitmap_isset(exclude, port))
|
||||||
|
bitmap_clear(map, port);
|
||||||
|
else
|
||||||
bitmap_set(map, port);
|
bitmap_set(map, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
util.h
2
util.h
|
@ -137,5 +137,5 @@ int timespec_diff_ms(struct timespec *a, struct timespec *b);
|
||||||
void bitmap_set(uint8_t *map, int bit);
|
void bitmap_set(uint8_t *map, int bit);
|
||||||
void bitmap_clear(uint8_t *map, int bit);
|
void bitmap_clear(uint8_t *map, int bit);
|
||||||
int bitmap_isset(uint8_t *map, int bit);
|
int bitmap_isset(uint8_t *map, int bit);
|
||||||
void procfs_scan_listen(char *name, uint8_t *map);
|
void procfs_scan_listen(char *name, uint8_t *map, uint8_t *exclude);
|
||||||
int ns_enter(int target_pid);
|
int ns_enter(int target_pid);
|
||||||
|
|
Loading…
Reference in a new issue