Skip to content

Commit c1164aa

Browse files
author
Gabi Beyer
committed
Support specified netns and userns file paths
Allow a network namespace path to be passed instead of a PID by using the --use-netns-path argument, and passing a path as the first argument. An optional --userns-path=PATH argument can be passed that will be supersede the default user namespace path. Fixes #84 Signed-off-by: Gabi Beyer <Gabrielle.n.beyer@intel.com>
1 parent 5c48cbb commit c1164aa

File tree

3 files changed

+124
-27
lines changed

3 files changed

+124
-27
lines changed

main.c

+66-17
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,43 @@
2626
#define DEFAULT_VDHCPSTART_OFFSET (15) // 10.0.2.15
2727
#define DEFAULT_VNAMESERVER_OFFSET (3) // 10.0.2.3
2828
#define DEFAULT_RECOMMENDED_VGUEST_OFFSET (100) // 10.0.2.100
29+
#define DEFAULT_NETNS_TYPE ("pid")
2930
#define NETWORK_PREFIX_MIN (1)
3031
// >=26 is not supported because the recommended guest IP is set to network addr + 100 .
3132
#define NETWORK_PREFIX_MAX (25)
3233

33-
static int nsenter(pid_t target_pid)
34+
static int nsenter(pid_t target_pid, char *netns, char *userns)
3435
{
35-
char userns[32], netns[32];
3636
int usernsfd, netnsfd;
37-
snprintf(userns, sizeof(userns), "/proc/%d/ns/user", target_pid);
38-
snprintf(netns, sizeof(netns), "/proc/%d/ns/net", target_pid);
39-
if ((usernsfd = open(userns, O_RDONLY)) < 0) {
40-
perror(userns);
41-
return usernsfd;
37+
if (!netns) {
38+
if (asprintf(&netns, "/proc/%d/ns/net", target_pid) < 0) {
39+
perror("cannot get netns path");
40+
return -1;
41+
}
42+
}
43+
if (!userns) {
44+
if (asprintf(&userns, "/proc/%d/ns/user", target_pid) < 0) {
45+
perror("cannot get userns path");
46+
return -1;
47+
}
4248
}
4349
if ((netnsfd = open(netns, O_RDONLY)) < 0) {
4450
perror(netns);
4551
return netnsfd;
4652
}
53+
if ((usernsfd = open(userns, O_RDONLY)) < 0) {
54+
perror(userns);
55+
return usernsfd;
56+
}
4757
setns(usernsfd, CLONE_NEWUSER);
4858
if (setns(netnsfd, CLONE_NEWNET) < 0) {
4959
perror("setns(CLONE_NEWNET)");
5060
return -1;
5161
}
5262
close(usernsfd);
5363
close(netnsfd);
64+
free(netns);
65+
free(userns);
5466
return 0;
5567
}
5668

@@ -165,11 +177,11 @@ static int configure_network(const char *tapname, struct slirp4netns_config *cfg
165177
return 0;
166178
}
167179

168-
static int child(int sock, pid_t target_pid, bool do_config_network, const char *tapname, int ready_fd,
180+
static int child(int sock, pid_t target_pid, bool do_config_network, const char *tapname, int ready_fd, char *netns_path, char *userns_path,
169181
struct slirp4netns_config *cfg)
170182
{
171183
int rc, tapfd;
172-
if ((rc = nsenter(target_pid)) < 0) {
184+
if ((rc = nsenter(target_pid, netns_path, userns_path)) < 0) {
173185
return rc;
174186
}
175187
if ((tapfd = open_tap(tapname)) < 0) {
@@ -261,14 +273,16 @@ static int parent(int sock, int exit_fd, const char *api_socket, struct slirp4ne
261273

262274
static void usage(const char *argv0)
263275
{
264-
printf("Usage: %s [OPTION]... PID TAPNAME\n", argv0);
276+
printf("Usage: %s [OPTION]... PID|PATH TAPNAME\n", argv0);
265277
printf("User-mode networking for unprivileged network namespaces.\n\n");
266278
printf("-c, --configure bring up the interface\n");
267279
printf("-e, --exit-fd=FD specify the FD for terminating slirp4netns\n");
268280
printf("-r, --ready-fd=FD specify the FD to write to when the network is configured\n");
269281
printf("-m, --mtu=MTU specify MTU (default=%d, max=65521)\n", DEFAULT_MTU);
270282
printf("--cidr=CIDR specify network address CIDR (default=%s)\n", DEFAULT_CIDR);
271283
printf("--disable-host-loopback prohibit connecting to 127.0.0.1:* on the host namespace\n");
284+
printf("--netns-type=TYPE specify network namespace type ([path|pid], default=%s)\n", DEFAULT_NETNS_TYPE);
285+
printf("--userns-path=PATH specify user namespace path\n");
272286
printf("-a, --api-socket=PATH specify API socket path\n");
273287
printf("-6, --enable-ipv6 enable IPv6 (experimental)\n");
274288
printf("-h, --help show this help and exit\n");
@@ -295,6 +309,9 @@ struct options {
295309
char *cidr; // --cidr
296310
bool enable_ipv6; // -6
297311
char *api_socket; // -a
312+
char *netns_type; // argv[1]
313+
char *netns_path; // --netns-path
314+
char *userns_path; // --userns-path
298315
};
299316

300317
static void options_init(struct options *options)
@@ -318,6 +335,12 @@ static void options_destroy(struct options *options)
318335
free(options->api_socket);
319336
options->api_socket = NULL;
320337
}
338+
if (options->netns_type != NULL) {
339+
free(options->netns_type);
340+
options->netns_type = NULL;
341+
}
342+
// options->netns_path and options->userns_path are
343+
// getting freed in the nsenter function
321344
// options itself is not freed, because it can be on the stack.
322345
}
323346

@@ -329,6 +352,8 @@ static void parse_args(int argc, char *const argv[], struct options *options)
329352
int opt;
330353
#define CIDR -42
331354
#define DISABLE_HOST_LOOPBACK -43
355+
#define NETNS_TYPE -44
356+
#define USERNS_PATH -45
332357
#define _DEPRECATED_NO_HOST_LOOPBACK -10043 // deprecated in favor of disable-host-loopback
333358
const struct option longopts[] = {
334359
{"configure", no_argument, NULL, 'c'},
@@ -338,6 +363,8 @@ static void parse_args(int argc, char *const argv[], struct options *options)
338363
{"cidr", required_argument, NULL, CIDR},
339364
{"disable-host-loopback", no_argument, NULL, DISABLE_HOST_LOOPBACK},
340365
{"no-host-loopback", no_argument, NULL, _DEPRECATED_NO_HOST_LOOPBACK},
366+
{"netns-type", required_argument, NULL, NETNS_TYPE},
367+
{"userns-path", required_argument, NULL, USERNS_PATH},
341368
{"api-socket", required_argument, NULL, 'a'},
342369
{"enable-ipv6", no_argument, NULL, '6'},
343370
{"help", no_argument, NULL, 'h'},
@@ -389,6 +416,17 @@ static void parse_args(int argc, char *const argv[], struct options *options)
389416
case DISABLE_HOST_LOOPBACK:
390417
options->disable_host_loopback = true;
391418
break;
419+
case NETNS_TYPE:
420+
options->netns_type = strdup(optarg);
421+
break;
422+
case USERNS_PATH:
423+
options->userns_path = strdup(optarg);
424+
if (access(options->userns_path, F_OK) == -1) {
425+
fprintf(stderr, "userns path doesn't exist: %s\n", options->userns_path);
426+
usage(argv[0]);
427+
exit(EXIT_FAILURE);
428+
}
429+
break;
392430
case 'a':
393431
options->api_socket = strdup(optarg);
394432
break;
@@ -409,6 +447,8 @@ static void parse_args(int argc, char *const argv[], struct options *options)
409447
}
410448
#undef CIDR
411449
#undef DISABLE_HOST_LOOPBACK
450+
#undef NETNS_TYPE
451+
#undef USERNS_PATH
412452
#undef _DEPRECATED_NO_HOST_LOOPBACK
413453
if (options->ready_fd >= 0 && !options->do_config_network) {
414454
fprintf(stderr, "the option -r FD requires -c\n");
@@ -422,12 +462,21 @@ static void parse_args(int argc, char *const argv[], struct options *options)
422462
usage(argv[0]);
423463
exit(EXIT_FAILURE);
424464
}
425-
errno = 0;
426-
options->target_pid = strtol(argv[optind], NULL, 10);
427-
if (errno != 0) {
428-
perror("strtol");
429-
usage(argv[0]);
430-
exit(EXIT_FAILURE);
465+
if (!options->netns_type || strcmp(options->netns_type, DEFAULT_NETNS_TYPE) == 0) {
466+
errno = 0;
467+
options->target_pid = strtol(argv[optind], NULL, 10);
468+
if (errno != 0) {
469+
perror("strtol");
470+
usage(argv[0]);
471+
exit(EXIT_FAILURE);
472+
}
473+
} else {
474+
options->netns_path = strdup(argv[optind]);
475+
if (access(options->netns_path, F_OK) == -1) {
476+
perror("existing path expected when --netns-type=path");
477+
usage(argv[0]);
478+
exit(EXIT_FAILURE);
479+
}
431480
}
432481
options->tapname = strdup(argv[optind + 1]);
433482
}
@@ -555,7 +604,7 @@ int main(int argc, char *const argv[])
555604
goto finish;
556605
}
557606
if (child_pid == 0) {
558-
if (child(sv[1], options.target_pid, options.do_config_network, options.tapname, options.ready_fd,
607+
if (child(sv[1], options.target_pid, options.do_config_network, options.tapname, options.ready_fd, options.netns_path, options.userns_path,
559608
&slirp4netns_config) < 0) {
560609
exit_status = EXIT_FAILURE;
561610
goto finish;

slirp4netns.1

+38-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
.nh
21
.TH SLIRP4NETNS 1 "July 2018" "Rootless Containers" "User Commands"
32

43
.SH NAME
@@ -8,7 +7,7 @@ slirp4netns \- User\-mode networking for unprivileged network namespaces
87

98
.SH SYNOPSIS
109
.PP
11-
slirp4netns [OPTION]... PID TAPNAME
10+
slirp4netns [OPTION]... PID|PATH TAPNAME
1211

1312

1413
.SH DESCRIPTION
@@ -20,8 +19,6 @@ Unlike \fBveth\fP(4), slirp4netns does not require the root privileges on the ho
2019

2120
.PP
2221
Default configuration:
23-
24-
.RS
2522
.IP \(bu 2
2623
MTU: 1500
2724
.IP \(bu 2
@@ -37,8 +34,6 @@ IPv6 Gateway/Host: fd00::2
3734
.IP \(bu 2
3835
IPv6 DNS: fd00::3
3936

40-
.RE
41-
4237

4338
.SH OPTIONS
4439
.PP
@@ -73,6 +68,14 @@ API socket path
7368
\fB\-6\fP, \fB\-\-enable\-ipv6\fP
7469
enable IPv6 (experimental).
7570

71+
.PP
72+
\fB\-\-netns\-type=TYPE\fP
73+
specify network namespace type ([path|pid], default=pid)
74+
75+
.PP
76+
\fB\-\-userns\-path=PATH\fP
77+
specify user namespace path
78+
7679
.PP
7780
\fB\-h\fP, \fB\-\-help\fP
7881
show help and exit
@@ -265,8 +268,6 @@ $ echo \-n $json | nc \-U /tmp/slirp4netns.sock
265268

266269
.PP
267270
Remarks:
268-
269-
.RS
270271
.IP \(bu 2
271272
Client needs to \fBshutdown\fP the socket with \fBSHUT\_WR\fP after sending every request.
272273
i.e. No support for keep\-alive and timeout.
@@ -277,6 +278,33 @@ A request must be less than 4095 bytes.
277278
.IP \(bu 2
278279
JSON responses may contain \fBerror\fP instead of \fBreturn\fP\&.
279280

281+
282+
.SH DEFINED NAMESPACE PATHS
283+
.PP
284+
A user can define a network namespace path as opposed to the default process ID:
285+
286+
.PP
287+
.RS
288+
289+
.nf
290+
$ slirp4netns \-\-netns\-type=path ... /path/to/netns tap0
291+
292+
.fi
293+
.RE
294+
295+
.PP
296+
Currently, the \fBnetns\-type=TYPE\fP argument supports \fBpath\fP or \fBpid\fP args with the default being \fBpid\fP\&.
297+
298+
.PP
299+
Additionally, a \fB\-\-userns\-path=PATH\fP argument can be included to override any user namespace path defaults
300+
301+
.PP
302+
.RS
303+
304+
.nf
305+
$ slirp4netns \-\-netns\-type=path \-\-userns\-path=/path/to/userns /path/to/netns tap0
306+
307+
.fi
280308
.RE
281309

282310

@@ -287,4 +315,5 @@ JSON responses may contain \fBerror\fP instead of \fBreturn\fP\&.
287315

288316
.SH AVAILABILITY
289317
.PP
290-
The slirp4netns command is available from \fBhttps://github.com/rootless\-containers/slirp4netns\fP under GNU GENERAL PUBLIC LICENSE Version 2.
318+
The slirp4netns command is available from \fB
319+
\[la]https://github.com/rootless-containers/slirp4netns\[ra]\fP under GNU GENERAL PUBLIC LICENSE Version 2.

slirp4netns.1.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ slirp4netns - User-mode networking for unprivileged network namespaces
77

88
# SYNOPSIS
99

10-
slirp4netns [OPTION]... PID TAPNAME
10+
slirp4netns [OPTION]... PID|PATH TAPNAME
1111

1212
# DESCRIPTION
1313

@@ -51,6 +51,12 @@ API socket path
5151
**-6**, **--enable-ipv6**
5252
enable IPv6 (experimental).
5353

54+
**--netns-type=TYPE**
55+
specify network namespace type ([path|pid], default=pid)
56+
57+
**--userns-path=PATH**
58+
specify user namespace path
59+
5460
**-h**, **--help**
5561
show help and exit
5662

@@ -178,6 +184,19 @@ Remarks:
178184
* A request must be less than 4095 bytes.
179185
* JSON responses may contain **error** instead of **return**.
180186

187+
# DEFINED NAMESPACE PATHS
188+
A user can define a network namespace path as opposed to the default process ID:
189+
190+
```console
191+
$ slirp4netns --netns-type=path ... /path/to/netns tap0
192+
```
193+
Currently, the **netns-type=TYPE** argument supports **path** or **pid** args with the default being **pid**.
194+
195+
Additionally, a **--userns-path=PATH** argument can be included to override any user namespace path defaults
196+
```console
197+
$ slirp4netns --netns-type=path --userns-path=/path/to/userns /path/to/netns tap0
198+
```
199+
181200
# SEE ALSO
182201

183202
**network_namespaces**(7), **user_namespaces**(7), **veth**(4)

0 commit comments

Comments
 (0)