net: support owning interfaces with libnl too

This commit is contained in:
Robert Swiecki 2018-05-31 14:45:44 +02:00
parent 7d57fc81be
commit 47c8cf7a01
2 changed files with 73 additions and 35 deletions

View File

@ -145,7 +145,7 @@ struct custom_option custom_opts[] = {
{ { "cgroup_cpu_mount", required_argument, NULL, 0x0822 }, "Location of cpu cgroup FS (default: '/sys/fs/cgroup/net_cls')" },
{ { "cgroup_cpu_parent", required_argument, NULL, 0x0833 }, "Which pre-existing cpu cgroup to use as a parent (default: 'NSJAIL')" },
{ { "iface_no_lo", no_argument, NULL, 0x700 }, "Don't bring the 'lo' interface up" },
{ { "iface_own", required_argument, NULL, 0x704 }, "Move this existing network interface into the new NET namespace" },
{ { "iface_own", required_argument, NULL, 0x704 }, "Move this existing network interface into the new NET namespace. Can be specified multiple times" },
{ { "macvlan_iface", required_argument, NULL, 'I' }, "Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs'" },
{ { "macvlan_vs_ip", required_argument, NULL, 0x701 }, "IP of the 'vs' interface (e.g. \"192.168.0.1\")" },
{ { "macvlan_vs_nm", required_argument, NULL, 0x702 }, "Netmask of the 'vs' interface (e.g. \"255.255.255.0\")" },

106
net.cc
View File

@ -54,19 +54,75 @@ namespace net {
#include <netlink/route/link.h>
#include <netlink/route/link/macvlan.h>
static bool cloneIface(
nsjconf_t* nsjconf, struct nl_sock* sk, struct nl_cache* link_cache, int pid) {
struct rtnl_link* rmv = rtnl_link_macvlan_alloc();
if (rmv == NULL) {
LOG_E("rtnl_link_macvlan_alloc()");
return false;
}
int err;
int master_index = rtnl_link_name2i(link_cache, nsjconf->iface_vs.c_str());
if (!master_index) {
LOG_E("rtnl_link_name2i(): Did not find '%s' interface", nsjconf->iface_vs.c_str());
rtnl_link_put(rmv);
return false;
}
rtnl_link_set_name(rmv, IFACE_NAME);
rtnl_link_set_link(rmv, master_index);
rtnl_link_set_ns_pid(rmv, pid);
if ((err = rtnl_link_add(sk, rmv, NLM_F_CREATE)) < 0) {
LOG_E("rtnl_link_add(name:'%s' link:'%s'): %s", IFACE_NAME,
nsjconf->iface_vs.c_str(), nl_geterror(err));
rtnl_link_put(rmv);
return false;
}
rtnl_link_put(rmv);
return true;
}
static bool moveToNs(
const std::string& iface, struct nl_sock* sk, struct nl_cache* link_cache, pid_t pid) {
LOG_D("Moving interface '%s' into netns=%d", iface.c_str(), (int)pid);
struct rtnl_link* orig_link = rtnl_link_get_by_name(link_cache, iface.c_str());
if (!orig_link) {
LOG_E("Couldn't find interface '%s'", iface.c_str());
return false;
}
struct rtnl_link* new_link = rtnl_link_alloc();
if (!new_link) {
LOG_E("Couldn't allocate new link");
rtnl_link_put(orig_link);
return false;
}
rtnl_link_set_ns_pid(new_link, pid);
int err = rtnl_link_change(sk, orig_link, new_link, RTM_SETLINK);
if (err < 0) {
LOG_E("rtnl_link_change(): set NS of interface '%s' to PID=%d: %s", iface.c_str(),
(int)pid, nl_geterror(err));
rtnl_link_put(new_link);
rtnl_link_put(orig_link);
return false;
}
rtnl_link_put(new_link);
rtnl_link_put(orig_link);
return true;
}
bool initNsFromParent(nsjconf_t* nsjconf, int pid) {
if (!nsjconf->clone_newnet) {
return true;
}
if (nsjconf->iface_vs.empty()) {
return true;
}
LOG_D("Putting iface:'%s' into namespace of PID:%d (with libnl3)",
nsjconf->iface_vs.c_str(), pid);
struct nl_sock* sk = nl_socket_alloc();
if (sk == NULL) {
if (!sk) {
LOG_E("Could not allocate socket with nl_socket_alloc()");
return false;
}
@ -78,51 +134,33 @@ bool initNsFromParent(nsjconf_t* nsjconf, int pid) {
return false;
}
struct rtnl_link* rmv = rtnl_link_macvlan_alloc();
if (rmv == NULL) {
LOG_E("rtnl_link_macvlan_alloc(): %s", nl_geterror(err));
nl_socket_free(sk);
return false;
}
struct nl_cache* link_cache;
if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
LOG_E("rtnl_link_alloc_cache(): %s", nl_geterror(err));
rtnl_link_put(rmv);
nl_socket_free(sk);
return false;
}
int master_index = rtnl_link_name2i(link_cache, nsjconf->iface_vs.c_str());
if (master_index == 0) {
LOG_E("rtnl_link_name2i(): Did not find '%s' interface", nsjconf->iface_vs.c_str());
nl_cache_free(link_cache);
rtnl_link_put(rmv);
nl_socket_free(sk);
return false;
for (const auto& iface : nsjconf->ifaces) {
if (!moveToNs(iface, sk, link_cache, pid)) {
nl_cache_free(link_cache);
nl_socket_free(sk);
return false;
}
}
rtnl_link_set_name(rmv, IFACE_NAME);
rtnl_link_set_link(rmv, master_index);
rtnl_link_set_ns_pid(rmv, pid);
if ((err = rtnl_link_add(sk, rmv, NLM_F_CREATE)) < 0) {
LOG_E("rtnl_link_add(name:'%s' link:'%s'): %s", IFACE_NAME,
nsjconf->iface_vs.c_str(), nl_geterror(err));
if (!nsjconf->iface_vs.empty() && !cloneIface(nsjconf, sk, link_cache, pid)) {
nl_cache_free(link_cache);
rtnl_link_put(rmv);
nl_socket_free(sk);
return false;
}
nl_cache_free(link_cache);
rtnl_link_put(rmv);
nl_socket_free(sk);
return true;
}
#else // defined(NSJAIL_NL3_WITH_MACVLAN)
bool moveToNs(const std::string& iface, pid_t pid) {
static bool moveToNs(const std::string& iface, pid_t pid) {
const std::vector<std::string> argv{
"/sbin/ip", "link", "set", iface, "netns", std::to_string(pid)};
if (subproc::systemExe(argv, environ) != 0) {