Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- implement forwarding
- implement random CIDR

Signed-off-by: fassl <[email protected]>
  • Loading branch information
pfandl committed Sep 11, 2021
1 parent 631f361 commit 7dce49c
Show file tree
Hide file tree
Showing 18 changed files with 977 additions and 78 deletions.
2 changes: 1 addition & 1 deletion Dockerfile.artifact
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ARG DEBIAN_VERSION=10

FROM --platform=$TARGETPLATFORM debian:${DEBIAN_VERSION} AS build
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev libssl-dev git ninja-build python3-pip
RUN pip3 install meson
RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
WORKDIR /libslirp
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.buildtests
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ARG LIBSLIRP_COMMIT=v4.6.1

# Alpine
FROM alpine:3 AS buildtest-alpine3-static
RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static libcap-static libcap-dev libseccomp-dev libseccomp-static git meson
RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static libcap-static libcap-dev libseccomp-dev openssl-dev openssl-libs-static libseccomp-static git meson
RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
WORKDIR /libslirp
ARG LIBSLIRP_COMMIT
Expand All @@ -14,7 +14,7 @@ RUN ./autogen.sh && ./configure LDFLAGS="-static" && make && cp -f slirp4netns /
# Ubuntu
FROM ubuntu:18.04 AS buildtest-ubuntu1804-common
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev libssl-dev git ninja-build python3-pip
RUN pip3 install meson
RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
WORKDIR /libslirp
Expand All @@ -32,7 +32,7 @@ RUN ./configure && make && cp -f slirp4netns /

# openSUSE (dynamic only)
FROM opensuse/leap:15 AS buildtest-opensuse15-common
RUN zypper install -y --no-recommends autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel ninja python3-pip
RUN zypper install -y --no-recommends autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel libopenssl-devel ninja python3-pip
RUN pip3 install meson
RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
WORKDIR /libslirp
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.tests
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ARG LIBSLIRP_COMMIT=v4.6.1

FROM ubuntu:20.04 AS build
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev libssl-dev git ninja-build python3-pip
RUN pip3 install meson
RUN git clone https://gitlab.freedesktop.org/slirp/libslirp.git /libslirp
WORKDIR /libslirp
Expand Down
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
Loading

0 comments on commit 7dce49c

Please sign in to comment.