Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPv6 forwarding and random CIDR #275

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e1d49fb
IPv6 test ref #253
Apr 5, 2021
faaea53
IPv6: pseudo random id generator #259 #253
Apr 12, 2021
a2e566b
IPv6 port forwarding: #259 #253
Apr 16, 2021
fcb7f2e
handle protocol version in api: #253 #259
pfandl Sep 11, 2021
6a6e469
add --ipv6-random flag: #259
pfandl Sep 11, 2021
6430d31
use strnXXX functions: #259
pfandl Sep 11, 2021
6d6396f
try read mac of tap0 and fallback to /dev/Xrandom: #259
pfandl Sep 11, 2021
a27216a
man: nsenter -U -> nsenter -U --preserve-credentials
AkihiroSuda Apr 23, 2021
ba09f87
README.md: mention nerdctl
AkihiroSuda Apr 23, 2021
17a642e
CI: bump libslirp to v4.5.0
AkihiroSuda May 20, 2021
8e5becc
v1.1.10
AkihiroSuda May 20, 2021
3ac3c51
v1.1.10+dev
AkihiroSuda May 20, 2021
3b70fdc
CI: bump libslirp to v4.6.0
AkihiroSuda Jun 15, 2021
4234e52
v1.1.11
AkihiroSuda Jun 15, 2021
c53452f
v1.1.11+dev
AkihiroSuda Jun 15, 2021
09e4298
README.md: fix a dead link
AkihiroSuda Jun 16, 2021
62f1e3b
Explicitly support DHCP + add tests + update libslirp to v4.6.1
AkihiroSuda Jun 18, 2021
9972623
tests: use TEST_SKIP_EXIT_CODE_SKIP
AkihiroSuda Jun 19, 2021
8222ff4
tests: use $(nsenter_flags $child)
AkihiroSuda Jun 19, 2021
24b7d53
tests: s/tun/tap/g to reflect reality
AkihiroSuda Jun 19, 2021
acd631c
Makefile.am: fix format
AkihiroSuda Jun 19, 2021
7b41a54
tests: split test-slirp4netns.sh
AkihiroSuda Jun 19, 2021
6cc943b
tests: refactor slirp4netns-no-unmount.sh
AkihiroSuda Jun 19, 2021
421610b
tests: shfmt -l -w *.sh
AkihiroSuda Jun 19, 2021
c5a6374
parson: update to v1.1.3
AkihiroSuda Aug 3, 2021
3af47e5
v1.1.12
AkihiroSuda Aug 3, 2021
be6109f
v1.1.12+dev
AkihiroSuda Aug 3, 2021
a0095d1
man page and bump libslirp veresion: #259
pfandl Sep 11, 2021
d1c501b
Merge branch 'master' into ipv6
pfandl Sep 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ noinst_LIBRARIES = libparson.a
AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)"
TESTS = tests/test-slirp4netns-api-socket.sh \
tests/test-slirp4netns-cidr.sh \
tests/test-slirp4netns-cidr6.sh \
tests/test-slirp4netns-configure.sh \
tests/test-slirp4netns-dhcp.sh \
tests/test-slirp4netns-disable-dns.sh \
tests/test-slirp4netns-disable-host-loopback.sh \
tests/test-slirp4netns-exit-fd.sh \
tests/test-slirp4netns-hostfwd.sh \
tests/test-slirp4netns-hostfwd4.sh \
tests/test-slirp4netns-hostfwd6.sh \
tests/test-slirp4netns-ipv6.sh \
tests/test-slirp4netns-macaddress.sh \
tests/test-slirp4netns-nspath.sh \
tests/test-slirp4netns-outbound-addr.sh \
Expand Down Expand Up @@ -47,7 +52,7 @@ libparson_a_CFLAGS = $(AM_CFLAGS) -I$(abs_top_builddir)/vendor/parson
libparson_a_SOURCES = vendor/parson/parson.c

slirp4netns_SOURCES = main.c slirp4netns.c api.c sandbox.c seccompfilter.c
slirp4netns_LDADD = libparson.a @GLIB_LIBS@ @SLIRP_LIBS@ @LIBSECCOMP_LIBS@ -lpthread
slirp4netns_LDADD = libparson.a @GLIB_LIBS@ @SLIRP_LIBS@ @LIBSECCOMP_LIBS@ -lpthread -lcrypto
man1_MANS = slirp4netns.1

generate-man:
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# slirp4netns: User-mode networking for unprivileged network namespaces
# slirp4netns: User-mode networking for unprivileged network namespaces

slirp4netns provides user-mode networking ("slirp") for unprivileged network namespaces.

Expand Down Expand Up @@ -73,7 +73,7 @@ Also available as a package on almost all Linux distributions:
* [Arch Linux](https://www.archlinux.org/packages/community/x86_64/slirp4netns/)
* [openSUSE (since Leap 15.0)](https://build.opensuse.org/package/show/openSUSE%3AFactory/slirp4netns)
* [SUSE Linux Enterprise (since 15)](https://build.opensuse.org/package/show/devel%3Akubic/slirp4netns)
* [Debian GNU/Linux (since 10.0)](https://packages.debian.org/buster/slirp4netns)
* [Debian GNU/Linux (since 10.0)](https://packages.debian.org/buster/slirp4netns)
* [Ubuntu (since 19.04)](https://packages.ubuntu.com/search?keywords=slirp4netns)
* [NixOS](https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/networking/slirp4netns)
* [Gentoo Linux](https://packages.gentoo.org/packages/app-emulation/slirp4netns)
Expand Down Expand Up @@ -126,7 +126,7 @@ starting slirp, MTU=65520
link/ether c2:28:0c:0e:29:06 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.100/24 brd 10.0.2.255 scope global tap0
valid_lft forever preferred_lft forever
inet6 fe80::c028:cff:fe0e:2906/64 scope link
inet6 fe80::c028:cff:fe0e:2906/64 scope link
valid_lft forever preferred_lft forever
(namespace)$ echo "nameserver 10.0.2.3" > /tmp/resolv.conf
(namespace)$ mount --bind /tmp/resolv.conf /etc/resolv.conf
Expand Down Expand Up @@ -187,7 +187,7 @@ $ make
$ sudo make install
```

* [libslirp](https://gitlab.freedesktop.org/slirp/libslirp) needs to be v4.1.0 or later.
* [libslirp](https://gitlab.freedesktop.org/slirp/libslirp) needs to be v4.4.0.57 or later.
* To build `slirp4netns` as a static binary, run `./configure` with `LDFLAGS=-static`.
* If you set `--prefix` to `$HOME`, you don't need to run `make install` with `sudo`.

Expand Down
227 changes: 181 additions & 46 deletions api.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,13 @@ int api_bindlisten(const char *api_socket)
struct api_hostfwd {
int id;
int is_udp;
struct in_addr host_addr;
int is_ipv4;
int is_ipv6;
struct sockaddr_in host;
struct sockaddr_in guest;
struct sockaddr_in6 host6;
struct sockaddr_in6 guest6;
int host_port;
struct in_addr guest_addr;
int guest_port;
};

Expand Down Expand Up @@ -107,9 +111,9 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx,
exit(EXIT_FAILURE);
}
fwd->is_udp = -1; /* TODO: support SCTP */
if (strcmp(proto_s, "udp") == 0) {
if (strncmp(proto_s, "udp", 3) == 0) {
fwd->is_udp = 1;
} else if (strcmp(proto_s, "tcp") == 0) {
} else if (strncmp(proto_s, "tcp", 3) == 0) {
fwd->is_udp = 0;
}
if (fwd->is_udp == -1) {
Expand All @@ -119,16 +123,59 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx,
free(fwd);
goto finish;
}
int flags = (fwd->is_udp ? SLIRP_HOSTFWD_UDP : 0);

if (host_addr_s == NULL || host_addr_s[0] == '\0') {
host_addr_s = "0.0.0.0";
}
if (inet_pton(AF_INET, host_addr_s, &fwd->host_addr) != 1) {
const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.host_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
if (strcmp("0.0.0.0", host_addr_s) == 0 ||
strcmp("::", host_addr_s) == 0 ||
strcmp("::0", host_addr_s) == 0) {
fwd->is_ipv4 = 1;
fwd->is_ipv6 = ctx->cfg->enable_ipv6;
host_addr_s = "0.0.0.0";
} else {
if (strchr(host_addr_s, '.')) {
fwd->is_ipv4 = 1;
}
else if (strchr(host_addr_s, ':')) {
if (!ctx->cfg->enable_ipv6) {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.host_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
fwd->is_ipv6 = 1;
}
}

if (strlen(proto_s) == 4) {
if (proto_s[3] == '4') {
fwd->is_ipv4 = 1;
fwd->is_ipv6 = 0;
} else if (proto_s[3] == '6') {
if (!ctx->cfg->enable_ipv6) {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.proto\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
fwd->is_ipv4 = 0;
fwd->is_ipv6 = 1;
} else {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.proto\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
}

fwd->host_port = (int)json_object_dotget_number(jo, "arguments.host_port");
if (fwd->host_port == 0) {
const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
Expand All @@ -137,16 +184,6 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx,
free(fwd);
goto finish;
}

if (guest_addr_s == NULL || guest_addr_s[0] == '\0') {
fwd->guest_addr = ctx->cfg->recommended_vguest;
} else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest_addr) != 1) {
const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.guest_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
fwd->guest_port =
(int)json_object_dotget_number(jo, "arguments.guest_port");
if (fwd->guest_port == 0) {
Expand All @@ -156,13 +193,77 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx,
free(fwd);
goto finish;
}
if (slirp_add_hostfwd(slirp, fwd->is_udp, fwd->host_addr, fwd->host_port,
fwd->guest_addr, fwd->guest_port) < 0) {
const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"slirp_add_hostfwd failed\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;

if (fwd->is_ipv4) {
fwd->host.sin_family = AF_INET;
fwd->guest.sin_family = AF_INET;
fwd->host.sin_port = htons(fwd->host_port);
fwd->guest.sin_port = htons(fwd->guest_port);
if (guest_addr_s == NULL || guest_addr_s[0] == '\0') {
fwd->guest.sin_addr = ctx->cfg->recommended_vguest;
} else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest.sin_addr) != 1) {
const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.guest_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
if (inet_pton(AF_INET, host_addr_s, &fwd->host.sin_addr) != 1) {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.host_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
if (slirp_add_hostxfwd(slirp,
(const struct sockaddr*)&fwd->host, sizeof(fwd->host),
(const struct sockaddr*)&fwd->guest, sizeof(fwd->guest), flags) < 0) {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"slirp_add_hostxfwd failed\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
}

if (fwd->is_ipv6) {
fwd->host6.sin6_family = AF_INET6;
fwd->guest6.sin6_family = AF_INET6;
fwd->host6.sin6_port = htons(fwd->host_port);
fwd->guest6.sin6_port = htons(fwd->guest_port);
if (guest_addr_s == NULL || guest_addr_s[0] == '\0') {
fwd->guest6.sin6_addr = ctx->cfg->recommended_vguest6;
} else if (inet_pton(AF_INET6, guest_addr_s, &fwd->guest6.sin6_addr) != 1) {
const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.guest_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
if (strcmp(host_addr_s, "0.0.0.0") == 0) {
host_addr_s = "::";
}
if (inet_pton(AF_INET6, host_addr_s, &fwd->host6.sin6_addr) != 1) {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"bad arguments.host_addr\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
flags |= SLIRP_HOSTFWD_V6ONLY;
if (slirp_add_hostxfwd(slirp,
(const struct sockaddr*)&fwd->host6, sizeof(fwd->host6),
(const struct sockaddr*)&fwd->guest6, sizeof(fwd->guest6), flags) < 0) {
const char *err =
"{\"error\":{\"desc\":\"bad request: add_hostfwd: "
"slirp_add_hostxfwd failed\"}}";
wrc = write(fd, err, strlen(err));
free(fwd);
goto finish;
}
}
fwd->id = ctx->hostfwds_nextid;
ctx->hostfwds_nextid++;
Expand All @@ -185,21 +286,46 @@ static void api_handle_req_list_hostfwd_foreach(gpointer data,
JSON_Value *entry_value = json_value_init_object();
JSON_Object *entry_object = json_value_get_object(entry_value);
char host_addr[INET_ADDRSTRLEN], guest_addr[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &fwd->host_addr, host_addr, sizeof(host_addr)) ==
NULL) {
perror("fatal: inet_ntop");
exit(EXIT_FAILURE);
char host_addr6[INET6_ADDRSTRLEN], guest_addr6[INET6_ADDRSTRLEN];
if (fwd->is_ipv4) {
if (inet_ntop(AF_INET, &fwd->host.sin_addr, host_addr, sizeof(host_addr)) ==
NULL) {
perror("fatal: inet_ntop");
exit(EXIT_FAILURE);
}
if (inet_ntop(AF_INET, &fwd->guest.sin_addr, guest_addr, sizeof(guest_addr)) ==
NULL) {
perror("fatal: inet_ntop");
exit(EXIT_FAILURE);
}
}
if (inet_ntop(AF_INET, &fwd->guest_addr, guest_addr, sizeof(guest_addr)) ==
NULL) {
perror("fatal: inet_ntop");
exit(EXIT_FAILURE);
if (fwd->is_ipv6) {
if (inet_ntop(AF_INET6, &fwd->host6.sin6_addr, host_addr6, sizeof(host_addr6)) ==
NULL) {
perror("fatal: inet_ntop");
exit(EXIT_FAILURE);
}
if (inet_ntop(AF_INET6, &fwd->guest6.sin6_addr, guest_addr6, sizeof(guest_addr6)) ==
NULL) {
perror("fatal: inet_ntop");
exit(EXIT_FAILURE);
}
}
json_object_set_number(entry_object, "id", fwd->id);
json_object_set_string(entry_object, "proto", fwd->is_udp ? "udp" : "tcp");
json_object_set_string(entry_object, "host_addr", host_addr);
if (fwd->is_ipv4) {
json_object_set_string(entry_object, "host_addr", host_addr);
}
if (fwd->is_ipv6) {
json_object_set_string(entry_object, "host_addr6", host_addr6);
}
json_object_set_number(entry_object, "host_port", fwd->host_port);
json_object_set_string(entry_object, "guest_addr", guest_addr);
if (fwd->is_ipv4) {
json_object_set_string(entry_object, "guest_addr", guest_addr);
}
if (fwd->is_ipv6) {
json_object_set_string(entry_object, "guest_addr6", guest_addr6);
}
json_object_set_number(entry_object, "guest_port", fwd->guest_port);
/* json_array_append_value does not copy passed value */
if (json_array_append_value(entries_array, entry_value) != JSONSuccess) {
Expand Down Expand Up @@ -257,16 +383,25 @@ static int api_handle_req_remove_hostfwd(Slirp *slirp, int fd,
} else {
struct api_hostfwd *fwd = found->data;
const char *api_ok = "{\"return\":{}}";
if (slirp_remove_hostfwd(slirp, fwd->is_udp, fwd->host_addr,
fwd->host_port) < 0) {
const char *err = "{\"error\":{\"desc\":\"bad request: "
"remove_hostfwd: slirp_remove_hostfwd failed\"}}";
wrc = write(fd, err, strlen(err));
} else {
ctx->hostfwds = g_list_remove(ctx->hostfwds, fwd);
g_free(fwd);
wrc = write(fd, api_ok, strlen(api_ok));
if (fwd->is_ipv4) {
if (slirp_remove_hostxfwd(slirp,
(const struct sockaddr*)&fwd->host, sizeof(fwd->host), 0) < 0) {
const char *err = "{\"error\":{\"desc\":\"bad request: "
"remove_hostfwd: slirp_remove_hostxfwd failed\"}}";
return write(fd, err, strlen(err));
}
}
if (fwd->is_ipv6) {
if (slirp_remove_hostxfwd(slirp,
(const struct sockaddr*)&fwd->host6, sizeof(fwd->host6), 0) < 0) {
const char *err = "{\"error\":{\"desc\":\"bad request: "
"remove_hostfwd: slirp_remove_hostxfwd failed\"}}";
return write(fd, err, strlen(err));
}
}
ctx->hostfwds = g_list_remove(ctx->hostfwds, fwd);
g_free(fwd);
wrc = write(fd, api_ok, strlen(api_ok));
}
return wrc;
}
Expand Down
3 changes: 2 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
AC_PREREQ([2.69])
AC_INIT([slirp4netns], [1.1.12+dev], [https://github.com/rootless-containers/slirp4netns/issues])
AC_INIT([slirp4netns], [1.1.13+dev], [https://github.com/rootless-containers/slirp4netns/issues])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])

Expand Down Expand Up @@ -36,6 +36,7 @@ PKG_CHECK_MODULES(GLIB, glib-2.0)
PKG_CHECK_MODULES(SLIRP, slirp >= 4.1.0)
PKG_CHECK_MODULES(LIBCAP, libcap)
PKG_CHECK_MODULES(LIBSECCOMP, libseccomp)
PKG_CHECK_MODULES(LIBCRYPTO, libcrypto)

AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Loading