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:
parent
ab32838022
commit
9a175cc2ce
12 changed files with 240 additions and 79 deletions
1
Makefile
1
Makefile
|
@ -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
157
conf.c
|
@ -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
30
passt.1
|
@ -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
59
passt.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
passt.h
9
passt.h
|
@ -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
2
pcap.c
|
@ -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
15
tap.c
|
@ -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
10
tcp.c
|
@ -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)) {
|
||||||
|
|
|
@ -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
4
udp.c
|
@ -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
28
util.c
|
@ -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
2
util.h
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue