Skip to content

Commit

Permalink
Merge pull request #200 from 5eraph/master
Browse files Browse the repository at this point in the history
Support v2 and v3 options from libslirp
  • Loading branch information
AkihiroSuda authored May 5, 2020
2 parents 4367de7 + 70af0e8 commit 56e0b81
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ AM_CFLAGS = @GLIB_CFLAGS@ @SLIRP_CFLAGS@ @LIBCAP_CFLAGS@ @LIBSECCOMP_CFLAGS@
noinst_LIBRARIES = libparson.a

AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)"
TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh
TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh tests/test-slirp4netns-outbound-addr.sh tests/test-slirp4netns-disable-dns.sh

EXTRA_DIST = \
slirp4netns.1.md \
Expand Down
174 changes: 167 additions & 7 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <regex.h>
#include <libslirp.h>
#include "slirp4netns.h"
#include <ifaddrs.h>

#define DEFAULT_MTU (1500)
#define DEFAULT_CIDR ("10.0.2.0/24")
Expand Down Expand Up @@ -271,6 +272,19 @@ static int parent(int sock, int ready_fd, int exit_fd, const char *api_socket,
if (api_socket != NULL) {
printf("* API Socket: %s\n", api_socket);
}
#if SLIRP_CONFIG_VERSION_MAX >= 2
if (cfg->enable_outbound_addr) {
printf("* Outbound IPv4: %s\n",
inet_ntoa(cfg->outbound_addr.sin_addr));
}
if (cfg->enable_outbound_addr6) {
char str[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, &cfg->outbound_addr6.sin6_addr, str,
INET6_ADDRSTRLEN) != NULL) {
printf("* Outbound IPv6: %s\n", str);
}
}
#endif
if (!cfg->disable_host_loopback) {
printf(
"WARNING: 127.0.0.1:* on the host is accessible as %s (set "
Expand Down Expand Up @@ -332,6 +346,17 @@ static void usage(const char *argv0)
"caps except CAP_NET_BIND_SERVICE if running as the root)\n");
printf("--enable-seccomp enable seccomp to limit syscalls "
"(experimental)\n");
/* v1.1.0 */
#if SLIRP_CONFIG_VERSION_MAX >= 2
printf("--outbound-addr=IPv4 sets outbound ipv4 address to bound to "
"(experimental)\n");
printf("--outbound-addr6=IPv6 sets outbound ipv6 address to bound to "
"(experimental)\n");
#endif
#if SLIRP_CONFIG_VERSION_MAX >= 3
printf("--disable-dns disables 10.0.2.3 (or configured internal "
"ip) to host dns redirect (experimental)\n");
#endif
/* others */
printf("-h, --help show this help and exit\n");
printf("-v, --version show version and exit\n");
Expand All @@ -345,24 +370,28 @@ static void version()
printf("commit: %s\n", COMMIT);
#endif
printf("libslirp: %s\n", slirp_version_string());
printf("SLIRP_CONFIG_VERSION_MAX: %d\n", SLIRP_CONFIG_VERSION_MAX);
}

struct options {
pid_t target_pid; // argv[1]
char *tapname; // argv[2]
bool do_config_network; // -c
int exit_fd; // -e
int ready_fd; // -r
unsigned int mtu; // -m
bool disable_host_loopback; // --disable-host-loopback
char *cidr; // --cidr
bool enable_ipv6; // -6
char *api_socket; // -a
char *netns_type; // argv[1]
char *netns_path; // --netns-path
char *userns_path; // --userns-path
char *outbound_addr; // --outbound-addr
char *outbound_addr6; // --outbound-addr6
pid_t target_pid; // argv[1]
int exit_fd; // -e
int ready_fd; // -r
unsigned int mtu; // -m
bool do_config_network; // -c
bool disable_host_loopback; // --disable-host-loopback
bool enable_ipv6; // -6
bool enable_sandbox; // --enable-sandbox
bool enable_seccomp; // --enable-seccomp
bool disable_dns; // --disable-dns
};

static void options_init(struct options *options)
Expand Down Expand Up @@ -398,6 +427,14 @@ static void options_destroy(struct options *options)
free(options->userns_path);
options->userns_path = NULL;
}
if (options->outbound_addr != NULL) {
free(options->outbound_addr);
options->outbound_addr = NULL;
}
if (options->outbound_addr6 != NULL) {
free(options->outbound_addr6);
options->outbound_addr6 = NULL;
}
}

// * caller does not need to call options_init()
Expand All @@ -411,12 +448,17 @@ static void parse_args(int argc, char *const argv[], struct options *options)
char *optarg_netns_type = NULL;
char *optarg_userns_path = NULL;
char *optarg_api_socket = NULL;
char *optarg_outbound_addr = NULL;
char *optarg_outbound_addr6 = NULL;
#define CIDR -42
#define DISABLE_HOST_LOOPBACK -43
#define NETNS_TYPE -44
#define USERNS_PATH -45
#define ENABLE_SANDBOX -46
#define ENABLE_SECCOMP -47
#define OUTBOUND_ADDR -48
#define OUTBOUND_ADDR6 -49
#define DISABLE_DNS -50
#define _DEPRECATED_NO_HOST_LOOPBACK \
-10043 // deprecated in favor of disable-host-loopback
#define _DEPRECATED_CREATE_SANDBOX \
Expand All @@ -438,6 +480,9 @@ static void parse_args(int argc, char *const argv[], struct options *options)
{ "enable-seccomp", no_argument, NULL, ENABLE_SECCOMP },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "outbound-addr", required_argument, NULL, OUTBOUND_ADDR },
{ "outbound-addr6", required_argument, NULL, OUTBOUND_ADDR6 },
{ "disable-dns", no_argument, NULL, DISABLE_DNS },
{ 0, 0, 0, 0 },
};
options_init(options);
Expand Down Expand Up @@ -526,6 +571,17 @@ static void parse_args(int argc, char *const argv[], struct options *options)
version();
exit(EXIT_SUCCESS);
break;
case OUTBOUND_ADDR:
printf("WARNING: Support for --outbount-addr is experimental\n");
optarg_outbound_addr = optarg;
break;
case OUTBOUND_ADDR6:
printf("WARNING: Support for --outbount-addr6 is experimental\n");
optarg_outbound_addr6 = optarg;
break;
case DISABLE_DNS:
options->disable_dns = true;
break;
default:
goto error;
break;
Expand All @@ -543,13 +599,22 @@ static void parse_args(int argc, char *const argv[], struct options *options)
if (optarg_api_socket != NULL) {
options->api_socket = strdup(optarg_api_socket);
}
if (optarg_outbound_addr != NULL) {
options->outbound_addr = strdup(optarg_outbound_addr);
}
if (optarg_outbound_addr6 != NULL) {
options->outbound_addr6 = strdup(optarg_outbound_addr6);
}
#undef CIDR
#undef DISABLE_HOST_LOOPBACK
#undef NETNS_TYPE
#undef USERNS_PATH
#undef _DEPRECATED_NO_HOST_LOOPBACK
#undef ENABLE_SANDBOX
#undef ENABLE_SECCOMP
#undef OUTBOUND_ADDR
#undef OUTBOUND_ADDR6
#undef DISABLE_DNS
if (argc - optind < 2) {
goto error;
}
Expand Down Expand Up @@ -670,6 +735,36 @@ static int slirp4netns_config_from_cidr(struct slirp4netns_config *cfg,
return rc;
}

static int get_interface_addr(const char *interface, int af, void *addr)
{
struct ifaddrs *ifaddr, *ifa;
if (interface == NULL)
return -1;

if (getifaddrs(&ifaddr) == -1) {
fprintf(stderr, "getifaddrs failed to obtain interface addresses");
return -1;
}

for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL)
continue;
if (ifa->ifa_addr->sa_family == af) {
if (strcmp(ifa->ifa_name, interface) == 0) {
if (af == AF_INET) {
*(struct in_addr *)addr =
((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
} else {
*(struct in6_addr *)addr =
((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
}
return 0;
}
}
}
return -1;
}

static int slirp4netns_config_from_options(struct slirp4netns_config *cfg,
struct options *opt)
{
Expand All @@ -684,6 +779,71 @@ static int slirp4netns_config_from_options(struct slirp4netns_config *cfg,
cfg->disable_host_loopback = opt->disable_host_loopback;
cfg->enable_sandbox = opt->enable_sandbox;
cfg->enable_seccomp = opt->enable_seccomp;

#if SLIRP_CONFIG_VERSION_MAX >= 2
cfg->enable_outbound_addr = false;
cfg->enable_outbound_addr6 = false;
#endif

if (opt->outbound_addr != NULL) {
#if SLIRP_CONFIG_VERSION_MAX >= 2
cfg->outbound_addr.sin_family = AF_INET;
cfg->outbound_addr.sin_port = 0; // Any local port will do
if (inet_pton(AF_INET, opt->outbound_addr,
&cfg->outbound_addr.sin_addr) == 1) {
cfg->enable_outbound_addr = true;
} else {
if (get_interface_addr(opt->outbound_addr, AF_INET,
&cfg->outbound_addr.sin_addr) != 0) {
fprintf(stderr, "outbound-addr has to be valid ipv4 address or "
"interface name.");
rc = -1;
goto finish;
}
cfg->enable_outbound_addr = true;
}
#else
fprintf(stderr, "slirp4netns has to be compiled against libslrip 4.2.0 "
"or newer for --outbound-addr support.");
rc = -1;
goto finish;
#endif
}
if (opt->outbound_addr6 != NULL) {
#if SLIRP_CONFIG_VERSION_MAX >= 2
cfg->outbound_addr6.sin6_family = AF_INET6;
cfg->outbound_addr6.sin6_port = 0; // Any local port will do
if (inet_pton(AF_INET6, opt->outbound_addr6,
&cfg->outbound_addr6.sin6_addr) == 1) {
cfg->enable_outbound_addr6 = true;
} else {
if (get_interface_addr(opt->outbound_addr, AF_INET6,
&cfg->outbound_addr6.sin6_addr) != 0) {
fprintf(stderr, "outbound-addr has to be valid ipv4 address or "
"iterface name.");
rc = -1;
goto finish;
}
cfg->enable_outbound_addr6 = true;
}
#else
fprintf(stderr, "slirp4netns has to be compiled against libslirp 4.2.0 "
"or newer for --outbound-addr6 support.");
rc = -1;
goto finish;
#endif
}

#if SLIRP_CONFIG_VERSION_MAX >= 3
cfg->disable_dns = opt->disable_dns;
#else
if (opt->disable_dns) {
fprintf(stderr, "slirp4netns has to be compiled against libslirp 4.3.0 "
"or newer for --disable-dns support.");
rc = -1;
goto finish;
}
#endif
finish:
return rc;
}
Expand Down
29 changes: 29 additions & 0 deletions slirp4netns.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,28 @@ the capabilities except `CAP_NET_BIND_SERVICE` are dropped.
enable **seccomp(2)** to limit syscalls.
Typically used in conjunction with **--enable-sandbox**.

**--outbound-addr=IPv4** (since v1.1.0, EXPERIMENTAL)
specify outbound ipv4 address slirp should bind to

**--outbound-addr=INTERFACE** (since v1.1.0, EXPERIMENTAL)
specify outbound interface slirp should bind to (ipv4 traffic only)

**--outbound-addr=IPv6** (since v1.1.0, EXPERIMENTAL)
specify outbound ipv6 address slirp should bind to

**--outbound-addr6=INTERFACE** (since v1.1.0, EXPERIMENTAL)
specify outbound interface slirp should bind to (ipv6 traffic only)

**--disable-dns** (since v1.1.0)
disable built-in DNS (10.0.2.3 by default)

**-h**, **--help** (since v0.2.0)
show help and exit

**-v**, **--version** (since v0.2.0)
show version and exit


# EXAMPLE

Terminal 1: Create user/network/mount namespaces
Expand Down Expand Up @@ -215,6 +231,19 @@ Additionally, a **--userns-path=PATH** argument can be included to override any
$ slirp4netns --netns-type=path --userns-path=/path/to/userns /path/to/netns tap0
```

# OUTBOUND ADDRESSES
A user can defined preferred outbound ipv4 and ipv6 address in multi IP scenarios.

```console
$ slirp4netns --outbound-addr=10.2.2.10 --outbound-addr6=fe80::10 ...
```

Optionally you can use interface names instead of ip addresses.

```console
$ slirp4netns --outbound-addr=eth0 --outbound-addr6=eth0 ...
```

# BUGS

Kernel 4.20 bumped up the default value of **/proc/sys/net/ipv4/tcp_rmem** from 87380 to 131072.
Expand Down
18 changes: 18 additions & 0 deletions slirp4netns.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,24 @@ Slirp *create_slirp(void *opaque, struct slirp4netns_config *s4nn)
cfg.if_mtu = s4nn->mtu;
cfg.if_mru = s4nn->mtu;
cfg.disable_host_loopback = s4nn->disable_host_loopback;
#if SLIRP_CONFIG_VERSION_MAX >= 2
cfg.outbound_addr = NULL;
cfg.outbound_addr6 = NULL;
if (s4nn->enable_outbound_addr) {
cfg.version = 2;
cfg.outbound_addr = &s4nn->outbound_addr;
}
if (s4nn->enable_outbound_addr6) {
cfg.version = 2;
cfg.outbound_addr6 = &s4nn->outbound_addr6;
}
#endif
#if SLIRP_CONFIG_VERSION_MAX >= 3
if (s4nn->disable_dns) {
cfg.version = 3;
cfg.disable_dns = true;
}
#endif
slirp = slirp_new(&cfg, &libslirp_cb, opaque);
if (slirp == NULL) {
fprintf(stderr, "slirp_new failed\n");
Expand Down
Loading

0 comments on commit 56e0b81

Please sign in to comment.