pasta: Allow specifying paths and names of namespaces

Based on a patch from Giuseppe Scrivano, this adds the ability to:

- specify paths and names of target namespaces to join, instead of
  a PID, also for user namespaces, with --userns

- request to join or create a network namespace only, without
  entering or creating a user namespace, with --netns-only

- specify the base directory for netns mountpoints, with --nsrun-dir

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
[sbrivio: reworked logic to actually join the given namespaces when
 they're not created, implemented --netns-only and --nsrun-dir,
 updated pasta demo script and man page]
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2021-09-29 16:11:06 +02:00 committed by Stefano Brivio
parent ab32838022
commit 9a175cc2ce
12 changed files with 240 additions and 79 deletions

View file

@ -1,6 +1,7 @@
CFLAGS += -Wall -Wextra -pedantic CFLAGS += -Wall -Wextra -pedantic
CFLAGS += -DRLIMIT_STACK_VAL=$(shell ulimit -s) CFLAGS += -DRLIMIT_STACK_VAL=$(shell ulimit -s)
CFLAGS += -DPAGE_SIZE=$(shell getconf PAGE_SIZE) CFLAGS += -DPAGE_SIZE=$(shell getconf PAGE_SIZE)
CFLAGS += -DNETNS_RUN_DIR=\"/run/netns\"
prefix ?= /usr/local prefix ?= /usr/local

157
conf.c
View file

@ -96,7 +96,7 @@ static int get_bound_ports_ns(void *arg)
struct get_bound_ports_ns_arg *a = (struct get_bound_ports_ns_arg *)arg; struct get_bound_ports_ns_arg *a = (struct get_bound_ports_ns_arg *)arg;
struct ctx *c = a->c; struct ctx *c = a->c;
if (!c->pasta_pid || ns_enter(c->pasta_pid)) if (!c->pasta_netns_fd || ns_enter(c))
return 0; return 0;
get_bound_ports(c, 1, a->proto); get_bound_ports(c, 1, a->proto);
@ -588,6 +588,104 @@ out:
warn("Couldn't get any nameserver address"); warn("Couldn't get any nameserver address");
} }
/**
* conf_ns_check() - Check if we can enter configured namespaces
* @arg: Execution context
*
* Return: 0
*/
static int conf_ns_check(void *arg)
{
struct ctx *c = (struct ctx *)arg;
if ((!c->netns_only && setns(c->pasta_userns_fd, 0)) ||
setns(c->pasta_netns_fd, 0))
c->pasta_userns_fd = c->pasta_netns_fd = -1;
return 0;
}
/**
* conf_ns_opt() - Open network, user namespaces descriptors from configuration
* @c: Execution context
* @nsdir: --nsrun-dir argument, can be an empty string
* @conf_userns: --userns argument, can be an empty string
* @optarg: PID, path or name of namespace
*
* Return: 0 on success, negative error code otherwise
*/
static int conf_ns_opt(struct ctx *c,
char *nsdir, char *conf_userns, const char *optarg)
{
char userns[PATH_MAX], netns[PATH_MAX];
int ufd = 0, nfd = 0, try, ret;
char *endptr;
pid_t pid;
if (c->netns_only && *conf_userns) {
err("Both --userns and --netns-only given");
return -EINVAL;
}
/* It might be a PID, a netns path, or a netns name */
for (try = 0; try < 3; try++) {
if (try == 0) {
pid = strtol(optarg, &endptr, 10);
if (*endptr || pid > INT_MAX)
continue;
if (!*conf_userns && !c->netns_only) {
ret = snprintf(userns, PATH_MAX,
"/proc/%i/ns/user", pid);
if (ret <= 0 || ret > (int)sizeof(userns))
continue;
}
ret = snprintf(netns, PATH_MAX, "/proc/%i/ns/net", pid);
if (ret <= 0 || ret > (int)sizeof(netns))
continue;
} else if (try == 1) {
if (!*conf_userns)
c->netns_only = 1;
ret = snprintf(netns, PATH_MAX, "%s", optarg);
if (ret <= 0 || ret > (int)sizeof(userns))
continue;
} else if (try == 2) {
ret = snprintf(netns, PATH_MAX, "%s/%s",
*nsdir ? nsdir : NETNS_RUN_DIR, optarg);
if (ret <= 0 || ret > (int)sizeof(netns))
continue;
}
if (!c->netns_only) {
if (*conf_userns)
ufd = open(conf_userns, O_RDONLY);
else if (*userns)
ufd = open(userns, O_RDONLY);
}
nfd = open(netns, O_RDONLY);
if (nfd >= 0 && ufd >= 0) {
c->pasta_netns_fd = nfd;
c->pasta_userns_fd = ufd;
NS_CALL(conf_ns_check, c);
if (c->pasta_netns_fd >= 0)
return 0;
}
if (nfd > 0)
close(nfd);
if (ufd > 0)
close(ufd);
}
return -ENOENT;
}
/** /**
* usage() - Print usage and exit * usage() - Print usage and exit
* @name: Executable name * @name: Executable name
@ -595,10 +693,10 @@ out:
static void usage(const char *name) static void usage(const char *name)
{ {
if (strstr(name, "pasta") || strstr(name, "passt4netns")) { if (strstr(name, "pasta") || strstr(name, "passt4netns")) {
info("Usage: %s [OPTION]... [TARGET_PID]", name); info("Usage: %s [OPTION]... [PID|PATH|NAME]", name);
info(""); info("");
info("Without TARGET_PID, enter a user and network namespace,"); info("Without PID|PATH|NAME, run the default shell in a new");
info("run the default shell and connect it via pasta."); info("network and user namespace, and connect it via pasta.");
} else { } else {
info("Usage: %s [OPTION]...", name); info("Usage: %s [OPTION]...", name);
} }
@ -670,7 +768,7 @@ static void usage(const char *name)
info( " -6, --ipv6-only Enable IPv6 operation only"); info( " -6, --ipv6-only Enable IPv6 operation only");
if (strstr(name, "pasta") || strstr(name, "passt4netns")) if (strstr(name, "pasta") || strstr(name, "passt4netns"))
goto pasta_ports; goto pasta_opts;
info( " -t, --tcp-ports SPEC TCP port forwarding to guest"); info( " -t, --tcp-ports SPEC TCP port forwarding to guest");
info( " can be specified multiple times"); info( " can be specified multiple times");
@ -692,7 +790,7 @@ static void usage(const char *name)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
pasta_ports: pasta_opts:
info( " -t, --tcp-ports SPEC TCP port forwarding to namespace"); info( " -t, --tcp-ports SPEC TCP port forwarding to namespace");
info( " can be specified multiple times"); info( " can be specified multiple times");
info( " SPEC can be:"); info( " SPEC can be:");
@ -721,6 +819,11 @@ pasta_ports:
info( " -U, --udp-ns SPEC UDP port forwarding to init namespace"); info( " -U, --udp-ns SPEC UDP port forwarding to init namespace");
info( " SPEC is as described above"); info( " SPEC is as described above");
info( " default: auto"); info( " default: auto");
info( " --userns NSPATH Target user namespace to join");
info( " --netns-only Don't join or create user namespace");
info( " implied if PATH or NAME are given without --userns");
info( " --nsrun-dir Directory for nsfs mountpoints");
info( " default: " NETNS_RUN_DIR);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -839,9 +942,13 @@ void conf(struct ctx *c, int argc, char **argv)
{"udp-ports", required_argument, NULL, 'u' }, {"udp-ports", required_argument, NULL, 'u' },
{"tcp-ns", required_argument, NULL, 'T' }, {"tcp-ns", required_argument, NULL, 'T' },
{"udp-ns", required_argument, NULL, 'U' }, {"udp-ns", required_argument, NULL, 'U' },
{"userns", required_argument, NULL, 2 },
{"netns-only", no_argument, &c->netns_only, 1 },
{"nsrun-dir", required_argument, NULL, 3 },
{ 0 }, { 0 },
}; };
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c }; struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
char nsdir[PATH_MAX] = { 0 }, userns[PATH_MAX] = { 0 };
enum conf_port_type tcp_tap = 0, tcp_init = 0; enum conf_port_type tcp_tap = 0, tcp_init = 0;
enum conf_port_type udp_tap = 0, udp_init = 0; enum conf_port_type udp_tap = 0, udp_init = 0;
struct fqdn *dnss = c->dns_search; struct fqdn *dnss = c->dns_search;
@ -863,10 +970,7 @@ void conf(struct ctx *c, int argc, char **argv)
if ((name == 'p' || name == 'D' || name == 'S') && !optarg && if ((name == 'p' || name == 'D' || name == 'S') && !optarg &&
optind < argc && *argv[optind] && *argv[optind] != '-') { optind < argc && *argv[optind] && *argv[optind] != '-') {
if (c->mode == MODE_PASTA) { if (c->mode == MODE_PASTA) {
char *endptr; if (conf_ns_opt(c, nsdir, userns, argv[optind]))
strtol(argv[optind], &endptr, 10);
if (*endptr)
optarg = argv[optind++]; optarg = argv[optind++];
} else { } else {
optarg = argv[optind++]; optarg = argv[optind++];
@ -877,6 +981,30 @@ void conf(struct ctx *c, int argc, char **argv)
case -1: case -1:
case 0: case 0:
break; break;
case 2:
if (c->mode != MODE_PASTA) {
err("--userns is for pasta mode only");
usage(argv[0]);
}
ret = snprintf(userns, sizeof(userns), "%s", optarg);
if (ret <= 0 || ret >= (int)sizeof(userns)) {
err("Invalid userns: %s", optarg);
usage(argv[0]);
}
break;
case 3:
if (c->mode != MODE_PASTA) {
err("--nsrun-dir is for pasta mode only");
usage(argv[0]);
}
ret = snprintf(nsdir, sizeof(nsdir), "%s", optarg);
if (ret <= 0 || ret >= (int)sizeof(nsdir)) {
err("Invalid nsrun-dir: %s", optarg);
usage(argv[0]);
}
break;
case 'd': case 'd':
if (c->debug) { if (c->debug) {
err("Multiple --debug options given"); err("Multiple --debug options given");
@ -1129,9 +1257,14 @@ void conf(struct ctx *c, int argc, char **argv)
} while (name != -1); } while (name != -1);
if (c->mode == MODE_PASTA && optind + 1 == argc) { if (c->mode == MODE_PASTA && optind + 1 == argc) {
c->pasta_pid = strtol(argv[optind], NULL, 0); ret = conf_ns_opt(c, nsdir, userns, argv[optind]);
if (c->pasta_pid < 0 || errno) if (ret == -ENOENT)
err("Namespace %s not found", argv[optind]);
if (ret < 0)
usage(argv[0]); usage(argv[0]);
} else if (c->mode == MODE_PASTA && *userns && optind == argc) {
err("--userns requires PID, PATH or NAME");
usage(argv[0]);
} else if (optind != argc) { } else if (optind != argc) {
usage(argv[0]); usage(argv[0]);
} }

30
passt.1
View file

@ -12,7 +12,7 @@
[\fIOPTION\fR]... [\fIOPTION\fR]...
.br .br
.B pasta .B pasta
[\fIOPTION\fR]... [\fITARGET_PID\fR] [\fIOPTION\fR]... [\fIPID\fR|\fIPATH\fR|\fINAME\fR]
.SH DESCRIPTION .SH DESCRIPTION
@ -56,11 +56,10 @@ or with the \fBqrap\fR(1) wrapper.
equivalent functionality to network namespaces, as the one offered by equivalent functionality to network namespaces, as the one offered by
\fBpasst\fR for virtual machines. \fBpasst\fR for virtual machines.
If TARGET_PID is given, \fBpasta\fR associates to the user and network namespace If PID, PATH or NAME are given, \fBpasta\fR associates to an existing user and
of the corresponding process. Otherwise, \fBpasta\fR creates a new user and network namespace. Otherwise, \fBpasta\fR creates a new user and network
network namespace, and spawns an interactive shell within this context. A namespace, and spawns an interactive shell within this context. A \fItap\fR
\fItap\fR device within the network namespace is created to provide network device within the network namespace is created to provide network connectivity.
connectivity.
For local TCP and UDP traffic only, \fBpasta\fR also implements a bypass path For local TCP and UDP traffic only, \fBpasta\fR also implements a bypass path
directly mapping Layer-4 sockets between \fIinit\fR and target namespaces, directly mapping Layer-4 sockets between \fIinit\fR and target namespaces,
@ -357,6 +356,25 @@ Configure UDP port forwarding from target namespace to init namespace.
Default is \fBauto\fR. Default is \fBauto\fR.
.TP
.BR \-\-userns " " \fIspec
Target user namespace to join, as path or name (i.e. suffix for --nsrun-dir). If
PID is given, without this option, the user namespace will be the one of the
corresponding process.
This option requires PID, PATH or NAME to be specified.
.TP
.BR \-\-netns-only
Join or create only the network namespace, not a user namespace. This is implied
if PATH or NAME are given without \-\-userns.
.TP
.BR \-\-nsrun-dir " " \fIpath
Directory for nsfs mountpoints, used as path prefix for names of namespaces.
The default path is shown with --help.
.SH EXAMPLES .SH EXAMPLES
.SS \fBpasta .SS \fBpasta

59
passt.c
View file

@ -242,18 +242,34 @@ static void pasta_child_handler(int signal)
/** /**
* pasta_wait_for_ns() - Busy loop until we can enter the target namespace * pasta_wait_for_ns() - Busy loop until we can enter the target namespace
* @target_pid: PID of process associated with target namespace * @arg: Execution context
* *
* Return: 0 * Return: 0
*/ */
static int pasta_wait_for_ns(void *target_pid) static int pasta_wait_for_ns(void *arg)
{ {
while (ns_enter(*(int *)target_pid)); struct ctx *c = (struct ctx *)arg;
char ns[PATH_MAX];
if (c->netns_only)
goto netns;
snprintf(ns, PATH_MAX, "/proc/%i/ns/user", pasta_child_pid);
do
while ((c->pasta_userns_fd = open(ns, O_RDONLY)) < 0);
while (setns(c->pasta_userns_fd, 0) && !close(c->pasta_userns_fd));
netns:
snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid);
do
while ((c->pasta_netns_fd = open(ns, O_RDONLY)) < 0);
while (setns(c->pasta_netns_fd, 0) && !close(c->pasta_netns_fd));
return 0; return 0;
} }
/** /**
* pasta_start_ns() - Fork shell in new namespace if target PID is not given * pasta_start_ns() - Fork shell in new namespace if target ns is not given
* @c: Execution context * @c: Execution context
*/ */
static void pasta_start_ns(struct ctx *c) static void pasta_start_ns(struct ctx *c)
@ -266,34 +282,36 @@ static void pasta_start_ns(struct ctx *c)
if (!c->debug) if (!c->debug)
c->quiet = 1; c->quiet = 1;
if ((c->pasta_pid = fork()) == -1) { if ((pasta_child_pid = fork()) == -1) {
perror("fork"); perror("fork");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if ((pasta_child_pid = c->pasta_pid)) { if (pasta_child_pid) {
NS_CALL(pasta_wait_for_ns, &pasta_child_pid); NS_CALL(pasta_wait_for_ns, c);
return; return;
} }
if (unshare(CLONE_NEWNET | CLONE_NEWUSER)) { if (unshare(CLONE_NEWNET | (c->netns_only ? 0 : CLONE_NEWUSER))) {
perror("unshare"); perror("unshare");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
snprintf(buf, BUFSIZ, "%u %u %u", 0, euid, 1); if (!c->netns_only) {
snprintf(buf, BUFSIZ, "%u %u %u", 0, euid, 1);
fd = open("/proc/self/uid_map", O_WRONLY); fd = open("/proc/self/uid_map", O_WRONLY);
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
close(fd); close(fd);
fd = open("/proc/self/setgroups", O_WRONLY); fd = open("/proc/self/setgroups", O_WRONLY);
write(fd, "deny", sizeof("deny")); write(fd, "deny", sizeof("deny"));
close(fd); close(fd);
fd = open("/proc/self/gid_map", O_WRONLY); fd = open("/proc/self/gid_map", O_WRONLY);
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
close(fd); close(fd);
}
fd = open("/proc/sys/net/ipv4/ping_group_range", O_WRONLY); fd = open("/proc/sys/net/ipv4/ping_group_range", O_WRONLY);
write(fd, "0 0", strlen("0 0")); write(fd, "0 0", strlen("0 0"));
@ -352,11 +370,12 @@ int main(int argc, char **argv)
if (!c.debug && (c.stderr || isatty(fileno(stdout)))) if (!c.debug && (c.stderr || isatty(fileno(stdout))))
openlog(log_name, LOG_PERROR, LOG_DAEMON); openlog(log_name, LOG_PERROR, LOG_DAEMON);
if (c.mode == MODE_PASTA && !c.pasta_pid) { if (c.mode == MODE_PASTA && !c.pasta_netns_fd) {
char proc_path[PATH_MAX]; char proc_path[PATH_MAX];
pasta_start_ns(&c); pasta_start_ns(&c);
snprintf(proc_path, PATH_MAX, "/proc/%i/ns/net", c.pasta_pid); snprintf(proc_path, PATH_MAX, "/proc/%i/ns/net",
pasta_child_pid);
readlink(proc_path, pasta_child_ns, PATH_MAX); readlink(proc_path, pasta_child_ns, PATH_MAX);
} }

View file

@ -85,13 +85,15 @@ enum passt_modes {
/** /**
* struct ctx - Execution context * struct ctx - Execution context
* @mode: Operation mode, qemu/UNIX domain socket or namespace/tap * @mode: Operation mode, qemu/UNIX domain socket or namespace/tap
* @pasta_pid: Target PID of namespace for pasta mode
* @debug: Enable debug mode * @debug: Enable debug mode
* @quiet: Don't print informational messages * @quiet: Don't print informational messages
* @foreground: Run in foreground, don't log to stderr by default * @foreground: Run in foreground, don't log to stderr by default
* @stderr: Force logging to stderr * @stderr: Force logging to stderr
* @sock_path: Path for UNIX domain socket * @sock_path: Path for UNIX domain socket
* @pcap: Path for packet capture file * @pcap: Path for packet capture file
* @pasta_netns_fd: File descriptor for network namespace in pasta mode
* @pasta_userns_fd: File descriptor for user namespace in pasta mode
* @netns_only: In pasta mode, don't join or create a user namespace
* @epollfd: File descriptor for epoll instance * @epollfd: File descriptor for epoll instance
* @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any * @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any
* @fd_tap: File descriptor for AF_UNIX socket or tuntap device * @fd_tap: File descriptor for AF_UNIX socket or tuntap device
@ -131,7 +133,6 @@ enum passt_modes {
*/ */
struct ctx { struct ctx {
enum passt_modes mode; enum passt_modes mode;
int pasta_pid;
int debug; int debug;
int quiet; int quiet;
int foreground; int foreground;
@ -139,6 +140,10 @@ struct ctx {
char sock_path[UNIX_PATH_MAX]; char sock_path[UNIX_PATH_MAX];
char pcap[PATH_MAX]; char pcap[PATH_MAX];
int pasta_netns_fd;
int pasta_userns_fd;
int netns_only;
int epollfd; int epollfd;
int fd_tap_listen; int fd_tap_listen;
int fd_tap; int fd_tap;

2
pcap.c
View file

@ -153,7 +153,7 @@ void pcapmm(struct mmsghdr *mmh, unsigned int vlen)
/** /**
* pcap_init() - Initialise pcap file * pcap_init() - Initialise pcap file
* @c: Execution context * @c: Execution context
* @index: pcap name index: passt instance number or pasta target pid * @index: pcap name index: passt instance number or pasta netns socket
*/ */
void pcap_init(struct ctx *c, int index) void pcap_init(struct ctx *c, int index)
{ {

15
tap.c
View file

@ -845,13 +845,13 @@ static int tun_ns_fd = -1;
/** /**
* tap_sock_init_tun_ns() - Create tuntap fd in namespace, bring up loopback * tap_sock_init_tun_ns() - Create tuntap fd in namespace, bring up loopback
* @target_pid: Pointer to target PID * @c: Execution context
*/ */
static int tap_sock_init_tun_ns(void *target_pid) static int tap_sock_init_tun_ns(void *c)
{ {
int fd; int fd;
if (ns_enter(*(int *)target_pid)) if (ns_enter((struct ctx *)c))
goto fail; goto fail;
if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0) if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
@ -883,12 +883,10 @@ fail:
/** /**
* struct tap_sock_if_up_ns_arg - Arguments for tap_sock_if_up_ns() * struct tap_sock_if_up_ns_arg - Arguments for tap_sock_if_up_ns()
* @c: Execution context * @c: Execution context
* @target_pid: Target namespace PID
* @ifname: Interface name of tap device * @ifname: Interface name of tap device
*/ */
struct tap_sock_if_up_ns_arg { struct tap_sock_if_up_ns_arg {
struct ctx *c; struct ctx *c;
int target_pid;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
}; };
@ -906,7 +904,7 @@ static int tap_sock_if_up_ns(void *arg)
a = (struct tap_sock_if_up_ns_arg *)arg; a = (struct tap_sock_if_up_ns_arg *)arg;
if (ns_enter(a->target_pid)) if (ns_enter(a->c))
return 0; return 0;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
@ -955,7 +953,7 @@ static void tap_sock_init_tun(struct ctx *c)
struct ifreq ifr = { .ifr_flags = IFF_TAP | IFF_NO_PI }; struct ifreq ifr = { .ifr_flags = IFF_TAP | IFF_NO_PI };
struct tap_sock_if_up_ns_arg ifup_arg; struct tap_sock_if_up_ns_arg ifup_arg;
NS_CALL(tap_sock_init_tun_ns, &c->pasta_pid); NS_CALL(tap_sock_init_tun_ns, c);
if (tun_ns_fd == -1) { if (tun_ns_fd == -1) {
err("Failed to open tun socket in namespace"); err("Failed to open tun socket in namespace");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -968,11 +966,10 @@ static void tap_sock_init_tun(struct ctx *c)
} }
strncpy(ifup_arg.ifname, c->pasta_ifn, IFNAMSIZ); strncpy(ifup_arg.ifname, c->pasta_ifn, IFNAMSIZ);
ifup_arg.target_pid = c->pasta_pid;
ifup_arg.c = c; ifup_arg.c = c;
NS_CALL(tap_sock_if_up_ns, (void *)&ifup_arg); NS_CALL(tap_sock_if_up_ns, (void *)&ifup_arg);
pcap_init(c, c->pasta_pid); pcap_init(c, c->pasta_netns_fd);
c->fd_tap = tun_ns_fd; c->fd_tap = tun_ns_fd;
} }

10
tcp.c
View file

@ -2828,7 +2828,7 @@ static int tcp_splice_connect_ns(void *arg)
struct tcp_splice_connect_ns_arg *a; struct tcp_splice_connect_ns_arg *a;
a = (struct tcp_splice_connect_ns_arg *)arg; a = (struct tcp_splice_connect_ns_arg *)arg;
ns_enter(a->c->pasta_pid); ns_enter(a->c);
a->ret = tcp_splice_connect(a->c, a->conn, -1, a->v6, a->port); a->ret = tcp_splice_connect(a->c, a->conn, -1, a->v6, a->port);
return 0; return 0;
} }
@ -3431,7 +3431,7 @@ static int tcp_sock_init_ns(void *arg)
struct ctx *c = (struct ctx *)arg; struct ctx *c = (struct ctx *)arg;
in_port_t port; in_port_t port;
ns_enter(c->pasta_pid); ns_enter(c);
for (port = 0; port < USHRT_MAX; port++) { for (port = 0; port < USHRT_MAX; port++) {
if (!bitmap_isset(c->tcp.port_to_init, port)) if (!bitmap_isset(c->tcp.port_to_init, port))
@ -3491,7 +3491,7 @@ static int tcp_sock_refill(void *arg)
int i, *p4, *p6; int i, *p4, *p6;
if (a->ns) { if (a->ns) {
if (ns_enter(a->c->pasta_pid)) if (ns_enter(a->c))
return 0; return 0;
p4 = ns_sock_pool4; p4 = ns_sock_pool4;
p6 = ns_sock_pool6; p6 = ns_sock_pool6;
@ -3676,7 +3676,7 @@ static int tcp_port_detect(void *arg)
struct tcp_port_detect_arg *a = (struct tcp_port_detect_arg *)arg; struct tcp_port_detect_arg *a = (struct tcp_port_detect_arg *)arg;
if (a->detect_in_ns) { if (a->detect_in_ns) {
ns_enter(a->c->pasta_pid); ns_enter(a->c);
get_bound_ports(a->c, 1, IPPROTO_TCP); get_bound_ports(a->c, 1, IPPROTO_TCP);
} else { } else {
@ -3708,7 +3708,7 @@ static int tcp_port_rebind(void *arg)
in_port_t port; in_port_t port;
if (a->bind_in_ns) { if (a->bind_in_ns) {
ns_enter(a->c->pasta_pid); ns_enter(a->c);
for (port = 0; port < USHRT_MAX; port++) { for (port = 0; port < USHRT_MAX; port++) {
if (!bitmap_isset(a->c->tcp.port_to_init, port)) { if (!bitmap_isset(a->c->tcp.port_to_init, port)) {

View file

@ -46,7 +46,7 @@ hostb n
sleep 10 sleep 10
nl nl
say without TARGET_PID, it will create a namespace. say without PID, it will create a namespace.
sleep 3 sleep 3
passt cd __TEMPDIR__/passt passt cd __TEMPDIR__/passt
passt ./pasta passt ./pasta

4
udp.c
View file

@ -516,7 +516,7 @@ static int udp_splice_connect_ns(void *arg)
a = (struct udp_splice_connect_ns_arg *)arg; a = (struct udp_splice_connect_ns_arg *)arg;
ns_enter(a->c->pasta_pid); ns_enter(a->c);
a->s = udp_splice_connect(a->c, a->v6, a->bound_sock, a->src, a->dst, a->s = udp_splice_connect(a->c, a->v6, a->bound_sock, a->src, a->dst,
UDP_BACK_TO_INIT); UDP_BACK_TO_INIT);
@ -1004,7 +1004,7 @@ int udp_sock_init_ns(void *arg)
struct ctx *c = (struct ctx *)arg; struct ctx *c = (struct ctx *)arg;
in_port_t dst; in_port_t dst;
ns_enter(c->pasta_pid); ns_enter(c);
for (dst = 0; dst < USHRT_MAX; dst++) { for (dst = 0; dst < USHRT_MAX; dst++) {
if (!bitmap_isset(c->udp.port_to_init, dst)) if (!bitmap_isset(c->udp.port_to_init, dst))

28
util.c
View file

@ -32,6 +32,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <errno.h>
#include "util.h" #include "util.h"
#include "passt.h" #include "passt.h"
@ -327,31 +328,18 @@ void procfs_scan_listen(char *name, uint8_t *map, uint8_t *exclude)
} }
/** /**
* ns_enter() - Enter user and network namespaces of process with given PID * ns_enter() - Enter configured network and user namespaces
* @target_pid: Process PID * @c: Execution context
* *
* Return: 0 on success, -1 on failure * Return: 0 on success, -1 on failure
*/ */
int ns_enter(int target_pid) int ns_enter(struct ctx *c)
{ {
char ns[PATH_MAX]; if (!c->netns_only && setns(c->pasta_userns_fd, 0))
int fd; return -errno;
snprintf(ns, PATH_MAX, "/proc/%i/ns/user", target_pid); if (setns(c->pasta_netns_fd, 0))
if ((fd = open(ns, O_RDONLY)) < 0 || setns(fd, 0)) return -errno;
goto fail;
close(fd);
snprintf(ns, PATH_MAX, "/proc/%i/ns/net", target_pid);
if ((fd = open(ns, O_RDONLY)) < 0 || setns(fd, 0))
goto fail;
close(fd);
return 0; return 0;
fail:
if (fd != -1)
close(fd);
return -1;
} }

2
util.h
View file

@ -143,4 +143,4 @@ 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, uint8_t *exclude); void procfs_scan_listen(char *name, uint8_t *map, uint8_t *exclude);
int ns_enter(int target_pid); int ns_enter(struct ctx *c);