A crude way of cloning an eth interface

This commit is contained in:
Jagger 2015-05-28 03:37:08 +02:00
parent 470bbb9a5d
commit 9960304cab
6 changed files with 75 additions and 1 deletions

View File

@ -198,6 +198,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
{{"silent", no_argument, NULL, 0x0504}, "Redirect child's fd:0/1/2 to /dev/null (default: false)"},
{{"bindmount", required_argument, NULL, 'B'}, "List of mountpoints to be mounted --bind inside the container. Can be specified multiple times (default: none)"},
{{"tmpfsmount", required_argument, NULL, 'T'}, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times (default: none)"},
{{"iface", required_argument, NULL, 'I'}, "Interface which will be cloned (MACVTAP) and put inside the subprocess' namespace"},
{{0, 0, 0, 0}, NULL},
};
/* *INDENT-ON* */
@ -209,7 +210,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
int opt_index = 0;
for (;;) {
int c = getopt_long(argc, argv, "H:c:p:i:u:g:l:t:M:Ndveh?B:T:", opts, &opt_index);
int c = getopt_long(argc, argv, "H:c:p:i:u:g:l:t:M:Ndveh?B:T:I:", opts, &opt_index);
if (c == -1) {
break;
}
@ -356,6 +357,9 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
break;
}
break;
case 'I':
nsjconf->iface = optarg;
break;
default:
cmdlineUsage(argv[0], custom_opts);
return false;

View File

@ -81,6 +81,7 @@ struct nsjconf_t {
bool is_silent;
struct mountfs_t *bindmountpts;
struct mountfs_t *tmpfsmountpts;
char *iface;
uid_t initial_uid;
gid_t initial_gid;
unsigned int max_conns_per_ip;

63
net.c
View File

@ -30,12 +30,75 @@
#include <strings.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "log.h"
static bool netSystem(const char *bin, char *const *argv)
{
int pid = fork();
if (pid == -1) {
PLOG_E("fork()");
return false;
}
if (pid == 0) {
execv(bin, argv);
PLOG_E("execve('%s')", bin);
_exit(1);
}
for (;;) {
int status;
while (wait4(pid, &status, __WALL, NULL) != pid) ;
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) {
return true;
}
LOG_W("'%s' returned with exit status: %d", bin, WEXITSTATUS(status));
return false;
}
if (WIFSIGNALED(status)) {
LOG_W("'%s' killed with signal: %d", bin, WTERMSIG(status));
return false;
}
LOG_E("Unknown exit status for '%s' (pid=%d): %d", bin, pid, status);
kill(pid, SIGKILL);
}
}
bool netCloneMacVtapAndNS(struct nsjconf_t * nsjconf, int pid)
{
if (nsjconf->iface == NULL) {
return true;
}
char iface[512];
snprintf(iface, sizeof(iface), "%s.ns.%d", nsjconf->iface, pid);
#define SBIN_IP_PATH "/sbin/ip"
char *const argv_add[] =
{ SBIN_IP_PATH, "link", "add", "link", nsjconf->iface, iface, "type", "macvtap", NULL };
if (netSystem(SBIN_IP_PATH, argv_add) == false) {
LOG_E("Couldn't create MACVTAP interface for '%s'", nsjconf->iface);
return false;
}
char pid_str[512];
snprintf(pid_str, sizeof(pid_str), "%d", pid);
char *const argv_netns[] = { SBIN_IP_PATH, "link", "set", "dev", iface, "netns", pid_str, NULL };
if (netSystem(SBIN_IP_PATH, argv_netns) == false) {
LOG_E("Couldn't put interface '%s' into NS of PID '%d'", iface, pid);
return false;
}
return true;
}
static bool netIsSocket(int fd)
{
int optval;

1
net.h
View File

@ -26,6 +26,7 @@
#include "common.h"
bool netCloneMacVtapAndNS(struct nsjconf_t *nsjconf, int pid);
bool netLimitConns(struct nsjconf_t *nsjconf, int connsock);
int netGetRecvSocket(int port);
int netAcceptConn(int listenfd);

View File

@ -187,6 +187,7 @@ int main(int argc, char *argv[])
.is_silent = false,
.bindmountpts = NULL,
.tmpfsmountpts = NULL,
.iface = NULL,
.initial_uid = getuid(),
.initial_gid = getgid(),
.max_conns_per_ip = 0,

View File

@ -223,6 +223,10 @@ void subprocRunChild(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_er
return;
}
if (netCloneMacVtapAndNS(nsjconf, pid) == false) {
LOG_E("Couldn't create and put MACVTAP interface into NS of PID '%d'", pid);
}
char log_buf[4096];
close(pipefd[1]);