]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Linux: detect network namespace and deny udev in one
authorRoy Marples <roy@marples.name>
Sat, 19 Sep 2020 13:40:50 +0000 (14:40 +0100)
committerRoy Marples <roy@marples.name>
Sat, 19 Sep 2020 13:40:50 +0000 (14:40 +0100)
udev says whether an interface name is stable or not.
In a network namespace, udev claims the interface does not exist.
This makes sense because udev only operates in the root namespace.

As such disable udev in a network namespace.

While here correctly spell initialise.

src/dev.c
src/dev.h
src/dev/udev.c
src/dhcpcd.h
src/if-linux.c
src/if.c
src/if.h
src/privsep-root.c
src/privsep-root.h

index f7da67e4dea586a0beb29bdbc8cb53f2108a4122..8f14bf6bc0f4f1b7ae1dc7e7f72ac3be5ca87e4c 100644 (file)
--- a/src/dev.c
+++ b/src/dev.c
 #include "logerr.h"
 
 int
-dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
+dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname)
 {
 
 #ifdef PRIVSEP
        if (ctx->options & DHCPCD_PRIVSEP &&
            !(ctx->options & DHCPCD_PRIVSEPROOT))
-               return ps_root_dev_initialized(ctx, ifname);
+               return ps_root_dev_initialised(ctx, ifname);
 #endif
 
        if (ctx->dev == NULL)
                return 1;
-       return ctx->dev->initialized(ifname);
+       return ctx->dev->initialised(ifname);
 }
 
 int
index d51cbbec8a062eef057736d1afd81186d9310925..3bfb57291d2832f56c8200096df3313b07ffc0f5 100644 (file)
--- a/src/dev.h
+++ b/src/dev.h
@@ -31,7 +31,7 @@
 // dev plugin setup
 struct dev {
        const char *name;
-       int (*initialized)(const char *);
+       int (*initialised)(const char *);
        int (*listening)(void);
        int (*handle_device)(void *);
        int (*start)(void);
@@ -47,7 +47,7 @@ int dev_init(struct dev *, const struct dev_dhcpcd *);
 // hooks for dhcpcd
 #ifdef PLUGIN_DEV
 #include "dhcpcd.h"
-int dev_initialized(struct dhcpcd_ctx *, const char *);
+int dev_initialised(struct dhcpcd_ctx *, const char *);
 int dev_listening(struct dhcpcd_ctx *);
 int dev_start(struct dhcpcd_ctx *, int (*)(void *, int, const char *));
 void dev_stop(struct dhcpcd_ctx *);
index 4fe7dde4f2d7689747fe61ae70a7d403fe3916e4..fefdefb20f4de61f68ce2995c2224644636738d2 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "../common.h"
 #include "../dev.h"
+#include "../if.h"
 #include "../logerr.h"
 
 static const char udev_name[] = "udev";
@@ -55,7 +56,7 @@ udev_listening(void)
 }
 
 static int
-udev_initialized(const char *ifname)
+udev_initialised(const char *ifname)
 {
        struct udev_device *device;
        int r;
@@ -120,8 +121,14 @@ udev_stop(void)
 static int
 udev_start(void)
 {
+       char netns[PATH_MAX];
        int fd;
 
+       if (if_getnetworknamespace(netns, sizeof(netns)) != NULL) {
+               logdebugx("udev does not work in a network namespace");
+               return -1;
+       }
+
        if (udev) {
                logerrx("udev: already started");
                return -1;
@@ -167,7 +174,7 @@ dev_init(struct dev *dev, const struct dev_dhcpcd *dev_dhcpcd)
 {
 
        dev->name = udev_name;
-       dev->initialized = udev_initialized;
+       dev->initialised = udev_initialised;
        dev->listening = udev_listening;
        dev->handle_device = udev_handle_device;
        dev->stop = udev_stop;
index 03449e5846053d3255087762420ad14c2aa75d70..0cf774ce166d4ccb46809728fec69a0d30cf29d1 100644 (file)
@@ -254,6 +254,10 @@ struct dhcpcd_ctx {
        struct dev *dev;
        void *dev_handle;
 #endif
+
+#ifdef __linux__
+       char netns[PATH_MAX];
+#endif
 };
 
 #ifdef USE_SIGNALS
index 8d87d7484f6b5596b4d6156e8481f37dd0595882..759b878e164f25350b2c840b19c4b6d9843e06fe 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/if_arp.h>
 #endif
 
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <ctype.h>
@@ -144,6 +145,7 @@ struct priv {
        int route_fd;
        int generic_fd;
        uint32_t route_pid;
+       char netns[PATH_MAX];
 };
 
 /* We need this to send a broadcast for InfiniBand.
@@ -383,6 +385,36 @@ if_linksocket(struct sockaddr_nl *nl, int protocol, int flags)
        return fd;
 }
 
+char *
+if_getnetworknamespace(char *buf, size_t len)
+{
+       struct stat sb_self, sb_netns;
+       DIR *dir;
+       struct dirent *de;
+       char file[PATH_MAX], *bufp = NULL;
+
+       if (stat("/proc/self/ns/net", &sb_self) == -1)
+               return NULL;
+
+       dir = opendir("/var/run/netns");
+       if (dir == NULL)
+               return NULL;
+
+       while ((de = readdir(dir)) != NULL) {
+               snprintf(file, sizeof(file), "/var/run/netns/%s", de->d_name);
+               if (stat(file, &sb_netns) == -1)
+                       continue;
+               if (sb_self.st_dev != sb_netns.st_dev &&
+                   sb_self.st_ino != sb_netns.st_ino)
+                       continue;
+               strlcpy(buf, de->d_name, len);
+               bufp = buf;
+               break;
+       }
+       closedir(dir);
+       return bufp;
+}
+
 int
 if_opensockets_os(struct dhcpcd_ctx *ctx)
 {
@@ -433,6 +465,9 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
        if (priv->generic_fd == -1)
                return -1;
 
+       if (if_getnetworknamespace(ctx->netns, sizeof(ctx->netns)) != NULL)
+               logdebugx("network namespace: %s", ctx->netns);
+
        return 0;
 }
 
@@ -1614,7 +1649,6 @@ if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af)
            &_if_initrt, kroutes);
 }
 
-
 #ifdef INET
 /* Linux is a special snowflake when it comes to BPF. */
 const char *bpf_name = "Packet Socket";
index 40fdadcf0e1705e27c38fe51433249b5ab13a003..cb407e19c547964658bc7e4c2c1203da74adc3f1 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -519,8 +519,11 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
 
 #ifdef PLUGIN_DEV
                /* Ensure that the interface name has settled */
-               if (!dev_initialized(ctx, spec.devname))
+               if (!dev_initialised(ctx, spec.devname)) {
+                       logdebugx("%s: waiting for interface to initialise",
+                           spec.devname);
                        continue;
+               }
 #endif
 
                if (if_vimaster(ctx, spec.devname) == 1) {
index e053fe5b62d7bf2c420937ead5b53bc432295f70..803f58184822f0d76b27b5670aef15ea39be9576 100644 (file)
--- a/src/if.h
+++ b/src/if.h
@@ -191,6 +191,7 @@ int if_ignoregroup(int, const char *);
 bool if_ignore(struct dhcpcd_ctx *, const char *);
 int if_vimaster(struct dhcpcd_ctx *ctx, const char *);
 unsigned short if_vlanid(const struct interface *);
+char * if_getnetworknamespace(char *, size_t);
 int if_opensockets(struct dhcpcd_ctx *);
 int if_opensockets_os(struct dhcpcd_ctx *);
 void if_closesockets(struct dhcpcd_ctx *);
index 1a438b67d354c5b5d045c9999460bc0b33d88d64..92faec4c0c62756e7ec28bcf069ac4dbcad1c8ff 100644 (file)
@@ -570,7 +570,7 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 #endif
 #ifdef PLUGIN_DEV
        case PS_DEV_INITTED:
-               err = dev_initialized(ctx, data);
+               err = dev_initialised(ctx, data);
                break;
        case PS_DEV_LISTENING:
                err = dev_listening(ctx);
@@ -989,7 +989,7 @@ ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm)
 
 #ifdef PLUGIN_DEV
 int
-ps_root_dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
+ps_root_dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname)
 {
 
        if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0,
index 5d6e1248bf15437aa686441699b038d3b91c17e7..146622b1a10dd00e1882684b9d9aa7eaa81ee992 100644 (file)
@@ -67,7 +67,7 @@ ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
 #endif
 
 #ifdef PLUGIN_DEV
-int ps_root_dev_initialized(struct dhcpcd_ctx *, const char *);
+int ps_root_dev_initialised(struct dhcpcd_ctx *, const char *);
 int ps_root_dev_listening(struct dhcpcd_ctx *);
 #endif