]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/network.c
network: remove stack allocations
[mirror_lxc.git] / src / lxc / network.c
old mode 100755 (executable)
new mode 100644 (file)
index b6aaa46..249d9d4
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <arpa/inet.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
+#include "../include/netns_ifaddrs.h"
 #include "af_unix.h"
 #include "conf.h"
 #include "config.h"
+#include "file_utils.h"
 #include "log.h"
+#include "macro.h"
+#include "memory_utils.h"
 #include "network.h"
 #include "nl.h"
+#include "raw_syscalls.h"
+#include "syscall_wrappers.h"
 #include "utils.h"
 
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
 #ifndef HAVE_STRLCPY
 #include "include/strlcpy.h"
 #endif
 
-#ifndef IFLA_LINKMODE
-#define IFLA_LINKMODE 17
-#endif
-
-#ifndef IFLA_LINKINFO
-#define IFLA_LINKINFO 18
-#endif
-
-#ifndef IFLA_NET_NS_PID
-#define IFLA_NET_NS_PID 19
-#endif
-
-#ifndef IFLA_INFO_KIND
-#define IFLA_INFO_KIND 1
-#endif
-
-#ifndef IFLA_VLAN_ID
-#define IFLA_VLAN_ID 1
-#endif
-
-#ifndef IFLA_INFO_DATA
-#define IFLA_INFO_DATA 2
-#endif
-
-#ifndef VETH_INFO_PEER
-#define VETH_INFO_PEER 1
-#endif
-
-#ifndef IFLA_MACVLAN_MODE
-#define IFLA_MACVLAN_MODE 1
-#endif
-
-lxc_log_define(lxc_network, lxc);
+lxc_log_define(network, lxc);
 
 typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
 
@@ -123,15 +93,18 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
                memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
        }
 
-       snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
+       err = snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
+       if (err < 0 || (size_t)err >= sizeof(veth2buf))
+               return -1;
+
        veth2 = lxc_mkifname(veth2buf);
        if (!veth2)
                goto out_delete;
 
        err = lxc_veth_create(veth1, veth2);
        if (err) {
-               ERROR("Failed to create veth pair \"%s\" and \"%s\": %s", veth1,
-                     veth2, strerror(-err));
+               errno = -err;
+               SYSERROR("Failed to create veth pair \"%s\" and \"%s\"", veth1, veth2);
                goto out_delete;
        }
 
@@ -140,8 +113,8 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
         * of a container */
        err = setup_private_host_hw_addr(veth1);
        if (err) {
-               ERROR("Failed to change mac address of host interface \"%s\": %s",
-                     veth1, strerror(-err));
+               errno = -err;
+               SYSERROR("Failed to change mac address of host interface \"%s\"", veth1);
                goto out_delete;
        }
 
@@ -183,10 +156,11 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
                err = lxc_netdev_set_mtu(veth1, mtu);
                if (!err)
                        err = lxc_netdev_set_mtu(veth2, mtu);
+
                if (err) {
-                       ERROR("Failed to set mtu \"%d\" for veth pair \"%s\" "
-                             "and \"%s\": %s",
-                             mtu, veth1, veth2, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to set mtu \"%d\" for veth pair \"%s\" "
+                                "and \"%s\"", mtu, veth1, veth2);
                        goto out_delete;
                }
        }
@@ -194,8 +168,9 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
        if (netdev->link[0] != '\0') {
                err = lxc_bridge_attach(netdev->link, veth1);
                if (err) {
-                       ERROR("Failed to attach \"%s\" to bridge \"%s\": %s",
-                             veth1, netdev->link, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to attach \"%s\" to bridge \"%s\"",
+                                veth1, netdev->link);
                        goto out_delete;
                }
                INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
@@ -203,7 +178,8 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 
        err = lxc_netdev_up(veth1);
        if (err) {
-               ERROR("Failed to set \"%s\" up: %s", veth1, strerror(-err));
+               errno = -err;
+               SYSERROR("Failed to set \"%s\" up", veth1);
                goto out_delete;
        }
 
@@ -254,8 +230,9 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
        err = lxc_macvlan_create(netdev->link, peer,
                                 netdev->priv.macvlan_attr.mode);
        if (err) {
-               ERROR("Failed to create macvlan interface \"%s\" on \"%s\": %s",
-                     peer, netdev->link, strerror(-err));
+               errno = -err;
+               SYSERROR("Failed to create macvlan interface \"%s\" on \"%s\"",
+                        peer, netdev->link);
                goto on_error;
        }
 
@@ -307,8 +284,9 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
 
        err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
        if (err) {
-               ERROR("Failed to create vlan interface \"%s\" on \"%s\": %s",
-                     peer, netdev->link, strerror(-err));
+               errno = -err;
+               SYSERROR("Failed to create vlan interface \"%s\" on \"%s\"",
+                        peer, netdev->link);
                return -1;
        }
 
@@ -328,10 +306,12 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
                              netdev->name[0] != '\0' ? netdev->name : "(null)");
                        return -1;
                }
+
                err = lxc_netdev_set_mtu(peer, mtu);
                if (err) {
-                       ERROR("Failed to set mtu \"%s\" for \"%s\": %s",
-                             netdev->mtu, peer, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to set mtu \"%s\" for \"%s\"",
+                                netdev->mtu, peer);
                        lxc_netdev_delete_by_name(peer);
                        return -1;
                }
@@ -570,15 +550,15 @@ out:
 #define PHYSNAME "/sys/class/net/%s/phy80211/name"
 static char *is_wlan(const char *ifname)
 {
+       __do_free char *path;
        int i, ret;
        long physlen;
        size_t len;
-       char *path;
        FILE *f;
        char *physname = NULL;
 
        len = strlen(ifname) + strlen(PHYSNAME) - 1;
-       path = alloca(len + 1);
+       path = must_realloc(NULL, len + 1);
        ret = snprintf(path, len, PHYSNAME, ifname);
        if (ret < 0 || (size_t)ret >= len)
                goto bad;
@@ -982,6 +962,9 @@ int netdev_get_mtu(int ifindex)
        if (err < 0)
                goto out;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
        do {
                /* Restore the answer buffer length, it might have been
                 * overwritten by a previous receive.
@@ -1044,6 +1027,8 @@ int netdev_get_mtu(int ifindex)
                }
        } while (readmore);
 
+#pragma GCC diagnostic pop
+
        /* If we end up here, we didn't find any result, so signal an error. */
        err = -1;
 
@@ -1364,7 +1349,7 @@ static int proc_sys_net_write(const char *path, const char *value)
        if (fd < 0)
                return -errno;
 
-       if (write(fd, value, strlen(value)) < 0)
+       if (lxc_write_nointr(fd, value, strlen(value)) < 0)
                err = -errno;
 
        close(fd);
@@ -1374,15 +1359,15 @@ static int proc_sys_net_write(const char *path, const char *value)
 static int neigh_proxy_set(const char *ifname, int family, int flag)
 {
        int ret;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
 
        if (family != AF_INET && family != AF_INET6)
                return -EINVAL;
 
-       ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s",
+       ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
                       family == AF_INET ? "ipv4" : "ipv6", ifname,
                       family == AF_INET ? "proxy_arp" : "proxy_ndp");
-       if (ret < 0 || (size_t)ret >= MAXPATHLEN)
+       if (ret < 0 || (size_t)ret >= PATH_MAX)
                return -E2BIG;
 
        return proc_sys_net_write(path, flag ? "1" : "0");
@@ -1521,6 +1506,9 @@ int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, struct in_addr *bcast,
  * the given RTM_NEWADDR message. Allocates memory for the address and stores
  * that pointer in *res (so res should be an in_addr** or in6_addr**).
  */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
 static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res)
 {
        int addrlen;
@@ -1566,6 +1554,8 @@ static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res)
        return 0;
 }
 
+#pragma GCC diagnostic pop
+
 static int ip_addr_get(int family, int ifindex, void **res)
 {
        int answer_len, err;
@@ -1608,6 +1598,9 @@ static int ip_addr_get(int family, int ifindex, void **res)
        if (err < 0)
                goto out;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
        do {
                /* Restore the answer buffer length, it might have been
                 * overwritten by a previous receive.
@@ -1667,6 +1660,8 @@ static int ip_addr_get(int family, int ifindex, void **res)
                }
        } while (readmore);
 
+#pragma GCC diagnostic pop
+
        /* If we end up here, we didn't find any result, so signal an
         * error.
         */
@@ -1853,7 +1848,7 @@ static int lxc_ovs_delete_port_exec(void *data)
 int lxc_ovs_delete_port(const char *bridge, const char *nic)
 {
        int ret;
-       char cmd_output[MAXPATHLEN];
+       char cmd_output[PATH_MAX];
        struct ovs_veth_args args;
 
        args.bridge = bridge;
@@ -1881,7 +1876,7 @@ static int lxc_ovs_attach_bridge_exec(void *data)
 static int lxc_ovs_attach_bridge(const char *bridge, const char *nic)
 {
        int ret;
-       char cmd_output[MAXPATHLEN];
+       char cmd_output[PATH_MAX];
        struct ovs_veth_args args;
 
        args.bridge = bridge;
@@ -1955,49 +1950,42 @@ static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 char *lxc_mkifname(char *template)
 {
        int ret;
-       unsigned int seed;
-       FILE *urandom;
-       struct ifaddrs *ifa, *ifaddr;
+       struct netns_ifaddrs *ifa, *ifaddr;
        char name[IFNAMSIZ];
        bool exists = false;
        size_t i = 0;
+#ifdef HAVE_RAND_R
+       unsigned int seed;
+
+       seed = randseed(false);
+#else
+
+       (void)randseed(true);
+#endif
 
        if (strlen(template) >= IFNAMSIZ)
                return NULL;
 
        /* Get all the network interfaces. */
-       ret = getifaddrs(&ifaddr);
+       ret = netns_getifaddrs(&ifaddr, -1, &(bool){false});
        if (ret < 0) {
-               ERROR("%s - Failed to get network interfaces", strerror(errno));
+               SYSERROR("Failed to get network interfaces");
                return NULL;
        }
 
-       /* Initialize the random number generator. */
-       urandom = fopen("/dev/urandom", "r");
-       if (urandom != NULL) {
-               if (fread(&seed, sizeof(seed), 1, urandom) <= 0)
-                       seed = time(0);
-               fclose(urandom);
-       } else {
-               seed = time(0);
-       }
-
-#ifndef HAVE_RAND_R
-       srand(seed);
-#endif
-
        /* Generate random names until we find one that doesn't exist. */
        while (true) {
                name[0] = '\0';
-               strcpy(name, template);
+               (void)strlcpy(name, template, IFNAMSIZ);
 
                exists = false;
+
                for (i = 0; i < strlen(name); i++) {
                        if (name[i] == 'X') {
 #ifdef HAVE_RAND_R
-                               name[i] = padchar[rand_r(&seed) % (strlen(padchar) - 1)];
+                               name[i] = padchar[rand_r(&seed) % strlen(padchar)];
 #else
-                               name[i] = padchar[rand() % (strlen(padchar) - 1)];
+                               name[i] = padchar[rand() % strlen(padchar)];
 #endif
                        }
                }
@@ -2013,8 +2001,10 @@ char *lxc_mkifname(char *template)
                        break;
        }
 
-       freeifaddrs(ifaddr);
-       return strcpy(template, name);
+       netns_freeifaddrs(ifaddr);
+       (void)strlcpy(template, name, strlen(template) + 1);
+
+       return template;
 }
 
 int setup_private_host_hw_addr(char *veth1)
@@ -2097,14 +2087,15 @@ int lxc_find_gateway_addresses(struct lxc_handler *handler)
 
 #define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
 static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcname,
-                                         struct lxc_netdev *netdev, pid_t pid)
+                                         struct lxc_netdev *netdev, pid_t pid, unsigned int hooks_version)
 {
        int ret;
        pid_t child;
        int bytes, pipefd[2];
        char *token, *saveptr = NULL;
        char netdev_link[IFNAMSIZ];
-       char buffer[MAXPATHLEN] = {0};
+       char buffer[PATH_MAX] = {0};
+       size_t retlen;
 
        if (netdev->type != LXC_NET_VETH) {
                ERROR("Network type %d not support for unprivileged use", netdev->type);
@@ -2126,9 +2117,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
        }
 
        if (child == 0) {
-               int ret;
-               size_t retlen;
-               char pidstr[LXC_NUMSTRLEN64];
+               char pidstr[INTTYPE_TO_STRLEN(pid_t)];
 
                close(pipefd[0]);
 
@@ -2150,10 +2139,10 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
                        _exit(EXIT_FAILURE);
                }
 
-               ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
-               if (ret < 0 || ret >= LXC_NUMSTRLEN64)
+               ret = snprintf(pidstr, sizeof(pidstr), "%d", pid);
+               if (ret < 0 || ret >= sizeof(pidstr))
                        _exit(EXIT_FAILURE);
-               pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
+               pidstr[sizeof(pidstr) - 1] = '\0';
 
                INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
                     lxcname, pidstr, netdev_link,
@@ -2173,7 +2162,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
        /* close the write-end of the pipe */
        close(pipefd[1]);
 
-       bytes = read(pipefd[0], &buffer, MAXPATHLEN);
+       bytes = lxc_read_nointr(pipefd[0], &buffer, PATH_MAX);
        if (bytes < 0) {
                SYSERROR("Failed to read from pipe file descriptor");
                close(pipefd[0]);
@@ -2209,8 +2198,8 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
 
        ret = lxc_safe_int(token, &netdev->ifindex);
        if (ret < 0) {
-               ERROR("%s - Failed to convert string \"%s\" to integer",
-                     strerror(-ret), token);
+               errno = -ret;
+               SYSERROR("Failed to convert string \"%s\" to integer", token);
                return -1;
        }
 
@@ -2221,12 +2210,12 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
                return -1;
        }
 
-       if (strlen(token) >= IFNAMSIZ) {
+       retlen = strlcpy(netdev->priv.veth_attr.veth1, token, IFNAMSIZ);
+       if (retlen >= IFNAMSIZ) {
                ERROR("Host side veth device name returned by lxc-user-nic is "
                      "too long");
                return -E2BIG;
        }
-       strcpy(netdev->priv.veth_attr.veth1, token);
 
        /* netdev->priv.veth_attr.ifindex */
        token = strtok_r(NULL, ":", &saveptr);
@@ -2237,11 +2226,26 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
 
        ret = lxc_safe_int(token, &netdev->priv.veth_attr.ifindex);
        if (ret < 0) {
-               ERROR("%s - Failed to convert string \"%s\" to integer",
-                     strerror(-ret), token);
+               errno = -ret;
+               SYSERROR("Failed to convert string \"%s\" to integer", token);
                return -1;
        }
 
+       if (netdev->upscript) {
+               char *argv[] = {
+                       "veth",
+                       netdev->link,
+                       netdev->priv.veth_attr.veth1,
+                       NULL,
+               };
+
+               ret = run_script_argv(lxcname,
+                               hooks_version, "net",
+                               netdev->upscript, "up", argv);
+               if (ret < 0)
+                       return -1;
+    }
+
        return 0;
 }
 
@@ -2252,7 +2256,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
        int bytes, ret;
        pid_t child;
        int pipefd[2];
-       char buffer[MAXPATHLEN] = {0};
+       char buffer[PATH_MAX] = {0};
 
        if (netdev->type != LXC_NET_VETH) {
                ERROR("Network type %d not support for unprivileged use", netdev->type);
@@ -2275,7 +2279,6 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
 
        if (child == 0) {
                char *hostveth;
-               int ret;
 
                close(pipefd[0]);
 
@@ -2314,7 +2317,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
 
        close(pipefd[1]);
 
-       bytes = read(pipefd[0], &buffer, MAXPATHLEN);
+       bytes = lxc_read_nointr(pipefd[0], &buffer, PATH_MAX);
        if (bytes < 0) {
                SYSERROR("Failed to read from pipe file descriptor.");
                close(pipefd[0]);
@@ -2340,15 +2343,15 @@ bool lxc_delete_network_unpriv(struct lxc_handler *handler)
        struct lxc_list *network = &handler->conf->network;
        /* strlen("/proc/") = 6
         * +
-        * LXC_NUMSTRLEN64
+        * INTTYPE_TO_STRLEN(pid_t)
         * +
         * strlen("/fd/") = 4
         * +
-        * LXC_NUMSTRLEN64
+        * INTTYPE_TO_STRLEN(int)
         * +
         * \0
         */
-       char netns_path[6 + LXC_NUMSTRLEN64 + 4 + LXC_NUMSTRLEN64 + 1];
+       char netns_path[6 + INTTYPE_TO_STRLEN(pid_t) + 4 + INTTYPE_TO_STRLEN(int) + 1];
 
        *netns_path = '\0';
 
@@ -2416,7 +2419,7 @@ bool lxc_delete_network_unpriv(struct lxc_handler *handler)
                     netdev->link);
 
 clear_ifindices:
-               /* We need to clear any ifindeces we recorded so liblxc won't
+               /* We need to clear any ifindices we recorded so liblxc won't
                 * have cached stale data which would cause it to fail on reboot
                 * we're we don't re-read the on-disk config file.
                 */
@@ -2483,9 +2486,9 @@ int lxc_network_move_created_netdev_priv(const char *lxcpath, const char *lxcnam
 
                ret = lxc_netdev_move_by_name(ifname, pid, NULL);
                if (ret) {
-                       ERROR("Failed to move network device \"%s\" to "
-                             "network namespace %d: %s", ifname, pid,
-                             strerror(-ret));
+                       errno = -ret;
+                       SYSERROR("Failed to move network device \"%s\" to "
+                                "network namespace %d", ifname, pid);
                        return -1;
                }
 
@@ -2499,7 +2502,7 @@ int lxc_network_move_created_netdev_priv(const char *lxcpath, const char *lxcnam
 }
 
 int lxc_create_network_unpriv(const char *lxcpath, const char *lxcname,
-                             struct lxc_list *network, pid_t pid)
+                             struct lxc_list *network, pid_t pid, unsigned int hooks_version)
 {
        struct lxc_list *iterator;
 
@@ -2525,7 +2528,7 @@ int lxc_create_network_unpriv(const char *lxcpath, const char *lxcname,
                if (netdev->mtu)
                        INFO("mtu ignored due to insufficient privilege");
 
-               if (lxc_create_network_unpriv_exec(lxcpath, lxcname, netdev, pid))
+               if (lxc_create_network_unpriv_exec(lxcpath, lxcname, netdev, pid, hooks_version))
                        return -1;
        }
 
@@ -2578,10 +2581,10 @@ bool lxc_delete_network_priv(struct lxc_handler *handler)
                             netdev->name[0] != '\0' ? netdev->name : "(null)",
                             netdev->ifindex);
                } else if (ret < 0) {
-                       WARN("Failed to remove interface \"%s\" with "
-                            "index %d: %s",
-                            netdev->name[0] != '\0' ? netdev->name : "(null)",
-                            netdev->ifindex, strerror(-ret));
+                       errno = -ret;
+                       SYSWARN("Failed to remove interface \"%s\" with index %d",
+                               netdev->name[0] != '\0' ? netdev->name : "(null)",
+                               netdev->ifindex);
                        goto clear_ifindices;
                }
                INFO("Removed interface \"%s\" with index %d",
@@ -2603,8 +2606,9 @@ bool lxc_delete_network_priv(struct lxc_handler *handler)
 
                ret = lxc_netdev_delete_by_name(hostveth);
                if (ret < 0) {
-                       WARN("Failed to remove interface \"%s\" from \"%s\": %s",
-                            hostveth, netdev->link, strerror(-ret));
+                       errno = -ret;
+                       SYSWARN("Failed to remove interface \"%s\" from \"%s\"",
+                               hostveth, netdev->link);
                        goto clear_ifindices;
                }
                INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
@@ -2626,7 +2630,7 @@ bool lxc_delete_network_priv(struct lxc_handler *handler)
                             hostveth, netdev->link);
 
 clear_ifindices:
-               /* We need to clear any ifindeces we recorded so liblxc won't
+               /* We need to clear any ifindices we recorded so liblxc won't
                 * have cached stale data which would cause it to fail on reboot
                 * we're we don't re-read the on-disk config file.
                 */
@@ -2734,12 +2738,12 @@ static int setup_hw_addr(char *hwaddr, const char *ifname)
 {
        struct sockaddr sockaddr;
        struct ifreq ifr;
-       int ret, fd, saved_errno;
+       int ret, fd;
 
        ret = lxc_convert_mac(hwaddr, &sockaddr);
        if (ret) {
-               ERROR("Mac address \"%s\" conversion failed: %s", hwaddr,
-                     strerror(-ret));
+               errno = -ret;
+               SYSERROR("Mac address \"%s\" conversion failed", hwaddr);
                return -1;
        }
 
@@ -2752,10 +2756,10 @@ static int setup_hw_addr(char *hwaddr, const char *ifname)
                return -1;
 
        ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
-       saved_errno = errno;
-       close(fd);
        if (ret)
-               ERROR("Failed to perform ioctl: %s", strerror(saved_errno));
+               SYSERROR("Failed to perform ioctl");
+
+       close(fd);
 
        DEBUG("Mac address \"%s\" on \"%s\" has been setup", hwaddr,
              ifr.ifr_name);
@@ -2774,8 +2778,9 @@ static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
                err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
                                        &inetdev->bcast, inetdev->prefix);
                if (err) {
-                       ERROR("Failed to setup ipv4 address for network device "
-                             "with eifindex %d: %s", ifindex, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to setup ipv4 address for network device "
+                                "with eifindex %d", ifindex);
                        return -1;
                }
        }
@@ -2795,8 +2800,9 @@ static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
                                        &inet6dev->mcast, &inet6dev->acast,
                                        inet6dev->prefix);
                if (err) {
-                       ERROR("Failed to setup ipv6 address for network device "
-                             "with eifindex %d: %s", ifindex, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to setup ipv6 address for network device "
+                                "with eifindex %d", ifindex);
                        return -1;
                }
        }
@@ -2816,9 +2822,8 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
                if (netdev->flags & IFF_UP) {
                        err = lxc_netdev_up("lo");
                        if (err) {
-                               ERROR("Failed to set the loopback network "
-                                     "device up: %s",
-                                     strerror(-err));
+                               errno = -err;
+                               SYSERROR("Failed to set the loopback network device up");
                                return -1;
                        }
                }
@@ -2862,17 +2867,18 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
         */
        if (netdev->name[0] == '\0') {
                if (netdev->type == LXC_NET_PHYS)
-                       strcpy(netdev->name, netdev->link);
+                       (void)strlcpy(netdev->name, netdev->link, IFNAMSIZ);
                else
-                       strcpy(netdev->name, "eth%d");
+                       (void)strlcpy(netdev->name, "eth%d", IFNAMSIZ);
        }
 
        /* rename the interface name */
        if (strcmp(ifname, netdev->name) != 0) {
                err = lxc_netdev_rename_by_name(ifname, netdev->name);
                if (err) {
-                       ERROR("Failed to rename network device \"%s\" to "
-                             "\"%s\": %s", ifname, netdev->name, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to rename network device \"%s\" to \"%s\"",
+                                ifname, netdev->name);
                        return -1;
                }
        }
@@ -2890,7 +2896,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
         * name of the network device in the child's network namespace. We will
         * later on send this information back to the parent.
         */
-       strcpy(netdev->name, current_ifname);
+       (void)strlcpy(netdev->name, current_ifname, IFNAMSIZ);
 
        /* set a mac address */
        if (netdev->hwaddr) {
@@ -2917,20 +2923,19 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 
        /* set the network device up */
        if (netdev->flags & IFF_UP) {
-               int err;
-
                err = lxc_netdev_up(current_ifname);
                if (err) {
-                       ERROR("Failed to set network device \"%s\" up: %s",
-                             current_ifname, strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to set network device \"%s\" up",
+                                current_ifname);
                        return -1;
                }
 
                /* the network is up, make the loopback up too */
                err = lxc_netdev_up("lo");
                if (err) {
-                       ERROR("Failed to set the loopback network device up: %s",
-                             strerror(-err));
+                       errno = -err;
+                       SYSERROR("Failed to set the loopback network device up");
                        return -1;
                }
        }
@@ -2958,15 +2963,17 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
                if (err) {
                        err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
                        if (err) {
-                               ERROR("Failed to add ipv4 dest for network "
-                                     "device \"%s\": %s", ifname, strerror(-err));
+                               errno = -err;
+                               SYSERROR("Failed to add ipv4 dest for network device \"%s\"",
+                                        ifname);
                        }
 
                        err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
                        if (err) {
-                               ERROR("Failed to setup ipv4 gateway for "
-                                     "network device \"%s\": %s",
-                                     ifname, strerror(-err));
+                               errno = -err;
+                               SYSERROR("Failed to setup ipv4 gateway for network device \"%s\"",
+                                        ifname);
+
                                if (netdev->ipv4_gateway_auto) {
                                        char buf[INET_ADDRSTRLEN];
                                        inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
@@ -2995,15 +3002,17 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
                if (err) {
                        err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
                        if (err) {
-                               ERROR("Failed to add ipv6 dest for network "
-                                     "device \"%s\": %s", ifname, strerror(-err));
+                               errno = -err;
+                               SYSERROR("Failed to add ipv6 dest for network device \"%s\"",
+                                        ifname);
                        }
 
                        err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
                        if (err) {
-                               ERROR("Failed to setup ipv6 gateway for "
-                                     "network device \"%s\": %s", ifname,
-                                     strerror(-err));
+                               errno = -err;
+                               SYSERROR("Failed to setup ipv6 gateway for network device \"%s\"",
+                                        ifname);
+
                                if (netdev->ipv6_gateway_auto) {
                                        char buf[INET6_ADDRSTRLEN];
                                        inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
@@ -3058,7 +3067,7 @@ int lxc_network_send_veth_names_to_child(struct lxc_handler *handler)
                if (netdev->type != LXC_NET_VETH)
                        continue;
 
-               ret = send(data_sock, netdev->name, IFNAMSIZ, 0);
+               ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
                if (ret < 0)
                        return -1;
                TRACE("Sent network device name \"%s\" to child", netdev->name);
@@ -3083,7 +3092,7 @@ int lxc_network_recv_veth_names_from_parent(struct lxc_handler *handler)
                if (netdev->type != LXC_NET_VETH)
                        continue;
 
-               ret = recv(data_sock, netdev->name, IFNAMSIZ, 0);
+               ret = lxc_recv_nointr(data_sock, netdev->name, IFNAMSIZ, 0);
                if (ret < 0)
                        return -1;
                TRACE("Received network device name \"%s\" from parent", netdev->name);
@@ -3106,19 +3115,19 @@ int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
                struct lxc_netdev *netdev = iterator->elem;
 
                /* Send network device name in the child's namespace to parent. */
-               ret = send(data_sock, netdev->name, IFNAMSIZ, 0);
+               ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
                if (ret < 0)
                        return -1;
 
                /* Send network device ifindex in the child's namespace to
                 * parent.
                 */
-               ret = send(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
+               ret = lxc_send_nointr(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), MSG_NOSIGNAL);
                if (ret < 0)
                        return -1;
        }
 
-       TRACE("Sent network device names and ifindeces to parent");
+       TRACE("Sent network device names and ifindices to parent");
        return 0;
 }
 
@@ -3138,14 +3147,14 @@ int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
                /* Receive network device name in the child's namespace to
                 * parent.
                 */
-               ret = recv(data_sock, netdev->name, IFNAMSIZ, 0);
+               ret = lxc_recv_nointr(data_sock, netdev->name, IFNAMSIZ, 0);
                if (ret < 0)
                        return -1;
 
                /* Receive network device ifindex in the child's namespace to
                 * parent.
                 */
-               ret = recv(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
+               ret = lxc_recv_nointr(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
                if (ret < 0)
                        return -1;
        }
@@ -3166,3 +3175,142 @@ void lxc_delete_network(struct lxc_handler *handler)
        else
                DEBUG("Deleted network devices");
 }
+
+int lxc_netns_set_nsid(int fd)
+{
+       int ret;
+       char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
+                NLMSG_ALIGN(1024)];
+       struct nl_handler nlh;
+       struct nlmsghdr *hdr;
+       struct rtgenmsg *msg;
+       int saved_errno;
+       const __s32 ns_id = -1;
+       const __u32 netns_fd = fd;
+
+       ret = netlink_open(&nlh, NETLINK_ROUTE);
+       if (ret < 0)
+               return -1;
+
+       memset(buf, 0, sizeof(buf));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+       hdr = (struct nlmsghdr *)buf;
+       msg = (struct rtgenmsg *)NLMSG_DATA(hdr);
+#pragma GCC diagnostic pop
+
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
+       hdr->nlmsg_type = RTM_NEWNSID;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = RTM_NEWNSID;
+       msg->rtgen_family = AF_UNSPEC;
+
+       ret = addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
+       if (ret < 0)
+               goto on_error;
+
+       ret = addattr(hdr, 1024, __LXC_NETNSA_NSID, &ns_id, sizeof(ns_id));
+       if (ret < 0)
+               goto on_error;
+
+       ret = __netlink_transaction(&nlh, hdr, hdr);
+
+on_error:
+       saved_errno = errno;
+       netlink_close(&nlh);
+       errno = saved_errno;
+
+       return ret;
+}
+
+static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+
+       memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+
+       while (RTA_OK(rta, len)) {
+               unsigned short type = rta->rta_type;
+
+               if ((type <= max) && (!tb[type]))
+                       tb[type] = rta;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+               rta = RTA_NEXT(rta, len);
+#pragma GCC diagnostic pop
+       }
+
+       return 0;
+}
+
+static inline __s32 rta_getattr_s32(const struct rtattr *rta)
+{
+       return *(__s32 *)RTA_DATA(rta);
+}
+
+#ifndef NETNS_RTA
+#define NETNS_RTA(r) \
+       ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
+#endif
+
+int lxc_netns_get_nsid(int fd)
+{
+       int ret;
+       ssize_t len;
+       char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
+                NLMSG_ALIGN(1024)];
+       struct rtattr *tb[__LXC_NETNSA_MAX + 1];
+       struct nl_handler nlh;
+       struct nlmsghdr *hdr;
+       struct rtgenmsg *msg;
+       int saved_errno;
+       __u32 netns_fd = fd;
+
+       ret = netlink_open(&nlh, NETLINK_ROUTE);
+       if (ret < 0)
+               return -1;
+
+       memset(buf, 0, sizeof(buf));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+       hdr = (struct nlmsghdr *)buf;
+       msg = (struct rtgenmsg *)NLMSG_DATA(hdr);
+#pragma GCC diagnostic pop
+
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
+       hdr->nlmsg_type = RTM_GETNSID;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = RTM_GETNSID;
+       msg->rtgen_family = AF_UNSPEC;
+
+       ret = addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
+       if (ret == 0)
+               ret = __netlink_transaction(&nlh, hdr, hdr);
+
+       saved_errno = errno;
+       netlink_close(&nlh);
+       errno = saved_errno;
+       if (ret < 0)
+               return -1;
+
+       errno = EINVAL;
+       msg = NLMSG_DATA(hdr);
+       len = hdr->nlmsg_len - NLMSG_SPACE(sizeof(*msg));
+       if (len < 0)
+               return -1;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+       parse_rtattr(tb, __LXC_NETNSA_MAX, NETNS_RTA(msg), len);
+       if (tb[__LXC_NETNSA_NSID])
+               return rta_getattr_s32(tb[__LXC_NETNSA_NSID]);
+#pragma GCC diagnostic pop
+
+       return -1;
+}