Booting an nfsroot with connman requires passing -I eth0 to ignore
the interface. This isn't very nice, for at least the following
reasons:

* A User interface based on connman is led to believe that there's no
  network interface and thus connman seems to be offline when it's not.
* The DHCP lease obtained by the kernel won't get renewed.
* DNS servers won't get obtained from DHCP, thus requiring a workaround
  to copy /proc/net/pnp to /etc/resolv.conf and passing -r to connmand.

Therefore change behaviour to restrict interfaces passed with -I to
read-only ioctls.

Signed-off-by: Andreas Oberritter <o...@opendreambox.org>
---
 Makefile.am      |   1 +
 include/device.h |   3 ++
 src/device.c     |  34 +++++++++++---
 src/inet.c       | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/ipconfig.c   |  16 +++++++
 src/rtnl.c       |  20 +-------
 6 files changed, 178 insertions(+), 36 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 19cc8b1..423261f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -210,6 +210,7 @@ src_connmand_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ 
@XTABLES_CFLAGS@ \
                                -DSTORAGEDIR=\""$(storagedir)\"" \
                                -DVPN_STORAGEDIR=\""$(vpn_storagedir)\"" \
                                -DCONFIGDIR=\""$(configdir)\"" \
+                               -DCONNMAND \
                                -I$(builddir)/src
 
 EXTRA_DIST = src/genbuiltin src/connman-dbus.conf src/connman-polkit.conf \
diff --git a/include/device.h b/include/device.h
index 57b925c..3c9615f 100644
--- a/include/device.h
+++ b/include/device.h
@@ -93,6 +93,9 @@ int connman_device_set_string(struct connman_device *device,
                                        const char *key, const char *value);
 const char *connman_device_get_string(struct connman_device *device,
                                                        const char *key);
+void connman_device_set_readonly(struct connman_device *device,
+                                               bool readonly);
+bool connman_device_get_readonly(struct connman_device *device);
 
 int connman_device_add_network(struct connman_device *device,
                                        struct connman_network *network);
diff --git a/src/device.c b/src/device.c
index c0683ab..301e850 100644
--- a/src/device.c
+++ b/src/device.c
@@ -54,6 +54,7 @@ struct connman_device {
        bool powered;
        bool scanning;
        bool disconnected;
+       bool readonly;
        char *name;
        char *node;
        char *address;
@@ -782,6 +783,32 @@ bool connman_device_get_disconnected(struct connman_device 
*device)
 }
 
 /**
+ * connman_device_set_readonly:
+ * @device: device structure
+ * @readonly: read-only state
+ *
+ * Change read-only state of device
+ */
+void connman_device_set_readonly(struct connman_device *device,
+                                               bool readonly)
+{
+       DBG("device %p readonly %d", device, readonly);
+
+       device->readonly = readonly;
+}
+
+/**
+ * connman_device_get_readonly:
+ * @device: device structure
+ *
+ * Get device read-only state
+ */
+bool connman_device_get_readonly(struct connman_device *device)
+{
+       return device->readonly;
+}
+
+/**
  * connman_device_set_string:
  * @device: device structure
  * @key: unique identifier
@@ -1246,12 +1273,6 @@ struct connman_device 
*connman_device_create_from_index(int index)
        if (!devname)
                return NULL;
 
-       if (__connman_device_isfiltered(devname)) {
-               connman_info("Ignoring interface %s (filtered)", devname);
-               g_free(devname);
-               return NULL;
-       }
-
        type = __connman_rtnl_get_device_type(index);
 
        switch (type) {
@@ -1305,6 +1326,7 @@ struct connman_device 
*connman_device_create_from_index(int index)
        }
 
        connman_device_set_string(device, "Address", addr);
+       connman_device_set_readonly(device, 
__connman_device_isfiltered(devname));
 
 done:
        g_free(devname);
diff --git a/src/inet.c b/src/inet.c
index cd220ff..ac646c9 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -55,6 +55,21 @@
        ((struct rtattr *) (((uint8_t*) (nmsg)) +       \
        NLMSG_ALIGN((nmsg)->nlmsg_len)))
 
+static inline int __connman_inet_check_write_perm(int ifindex)
+{
+    #if defined(CONNMAND)
+       struct connman_device *dev = connman_device_find_by_index(ifindex);
+
+       if (!dev)
+               return -ENODEV;
+
+       if (connman_device_get_readonly(dev))
+               return -EPERM;
+    #endif
+
+       return 0;
+}
+
 int __connman_inet_rtnl_addattr_l(struct nlmsghdr *n, size_t max_length,
                                int type, const void *data, size_t data_length)
 {
@@ -104,6 +119,11 @@ int __connman_inet_modify_address(int cmd, int flags,
        if (family != AF_INET && family != AF_INET6)
                return -EINVAL;
 
+       if (__connman_inet_check_write_perm(index) < 0) {
+               DBG("insufficient permission, ignoring request");
+               return 0;
+       }
+
        memset(&request, 0, sizeof(request));
 
        header = (struct nlmsghdr *)request;
@@ -245,6 +265,12 @@ int connman_inet_ifup(int index)
        struct ifreq ifr;
        int sk, err;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0)
                return -errno;
@@ -288,6 +314,12 @@ int connman_inet_ifdown(int index)
        struct sockaddr_in *addr;
        int sk, err;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0)
                return -errno;
@@ -454,11 +486,17 @@ int connman_inet_add_network_route(int index, const char 
*host,
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d host %s gateway %s netmask %s", index,
                host, gateway, netmask);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -525,10 +563,16 @@ int connman_inet_del_network_route(int index, const char 
*host)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d host %s", index, host);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -573,13 +617,19 @@ int connman_inet_del_ipv6_network_route(int index, const 
char *host,
                                                unsigned char prefix_len)
 {
        struct in6_rtmsg rt;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d host %s", index, host);
 
        if (!host)
                return -EINVAL;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        memset(&rt, 0, sizeof(rt));
 
        rt.rtmsg_dst_len = prefix_len;
@@ -623,13 +673,19 @@ int connman_inet_add_ipv6_network_route(int index, const 
char *host,
                                        unsigned char prefix_len)
 {
        struct in6_rtmsg rt;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d host %s gateway %s", index, host, gateway);
 
        if (!host)
                return -EINVAL;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        memset(&rt, 0, sizeof(rt));
 
        rt.rtmsg_dst_len = prefix_len;
@@ -677,13 +733,19 @@ int connman_inet_add_ipv6_host_route(int index, const 
char *host,
 int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway)
 {
        struct in6_rtmsg rt;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d gateway %s", index, gateway);
 
        if (!gateway)
                return -EINVAL;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        memset(&rt, 0, sizeof(rt));
 
        if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) < 0) {
@@ -720,10 +782,16 @@ int connman_inet_set_gateway_interface(int index)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d", index);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -773,10 +841,16 @@ int connman_inet_set_ipv6_gateway_interface(int index)
        struct rtentry rt;
        struct sockaddr_in6 addr;
        const struct in6_addr any = IN6ADDR_ANY_INIT;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d", index);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -825,10 +899,16 @@ int connman_inet_clear_gateway_address(int index, const 
char *gateway)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d gateway %s", index, gateway);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -882,10 +962,16 @@ int connman_inet_clear_gateway_interface(int index)
        struct ifreq ifr;
        struct rtentry rt;
        struct sockaddr_in addr;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d", index);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -935,10 +1021,16 @@ int connman_inet_clear_ipv6_gateway_interface(int index)
        struct rtentry rt;
        struct sockaddr_in6 addr;
        const struct in6_addr any = IN6ADDR_ANY_INIT;
-       int sk, err = 0;
+       int sk, err;
 
        DBG("index %d", index);
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -1035,11 +1127,17 @@ bool connman_inet_compare_subnet(int index, const char 
*host)
 int connman_inet_remove_from_bridge(int index, const char *bridge)
 {
        struct ifreq ifr;
-       int sk, err = 0;
+       int sk, err;
 
        if (!bridge)
                return -EINVAL;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -1066,11 +1164,17 @@ out:
 int connman_inet_add_to_bridge(int index, const char *bridge)
 {
        struct ifreq ifr;
-       int sk, err = 0;
+       int sk, err;
 
        if (!bridge)
                return -EINVAL;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
        if (sk < 0) {
                err = -errno;
@@ -1099,6 +1203,12 @@ int connman_inet_set_mtu(int index, int mtu)
        struct ifreq ifr;
        int sk, err;
 
+       err = __connman_inet_check_write_perm(index);
+       if (err < 0) {
+               DBG("insufficient permission");
+               return err;
+       }
+
        sk = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        if (sk < 0)
                return sk;
@@ -2812,6 +2922,12 @@ static int iproute_default_modify(int cmd, uint32_t 
table_id, int ifindex,
        if (ret <= 0)
                return -EINVAL;
 
+       ret = __connman_inet_check_write_perm(ifindex);
+       if (ret < 0) {
+               DBG("insufficient permission");
+               return ret;
+       }
+
        memset(&rth, 0, sizeof(rth));
 
        rth.req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
diff --git a/src/ipconfig.c b/src/ipconfig.c
index f8c148b..3ecabfc 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -90,6 +90,17 @@ static GHashTable *ipdevice_hash = NULL;
 static GList *ipconfig_list = NULL;
 static bool is_ipv6_supported = false;
 
+static int __connman_ipconfig_check_write_perm(const gchar *ifname)
+{
+       int index = connman_inet_ifindex(ifname);
+       struct connman_device *dev = connman_device_find_by_index(index);
+
+       if (!dev)
+               return -ENODEV;
+
+       return connman_device_get_readonly(dev) ? -EPERM : 0;
+}
+
 void __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig)
 {
        if (!ipconfig)
@@ -210,6 +221,8 @@ static void set_ipv6_state(gchar *ifname, bool enable)
 
        if (!ifname)
                path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
+       else if (__connman_ipconfig_check_write_perm(ifname) < 0)
+               return;
        else
                path = g_strdup_printf(
                        "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
@@ -273,6 +286,9 @@ static void set_ipv6_privacy(gchar *ifname, int value)
        if (!ifname)
                return;
 
+       if (__connman_ipconfig_check_write_perm(ifname) < 0)
+               return;
+
        path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
                                                                ifname);
 
diff --git a/src/rtnl.c b/src/rtnl.c
index b8b02c4..25da07b 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -83,17 +83,6 @@ static void free_interface(gpointer data)
        g_free(interface);
 }
 
-static bool ether_blacklisted(const char *name)
-{
-       if (!name)
-               return true;
-
-       if (__connman_device_isfiltered(name))
-               return true;
-
-       return false;
-}
-
 static bool wext_interface(char *ifname)
 {
        struct iwreq wrq;
@@ -124,13 +113,8 @@ static void read_uevent(struct interface_data *interface)
 
        name = connman_inet_ifname(interface->index);
 
-       if (ether_blacklisted(name)) {
-               interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
-               interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN;
-       } else {
-               interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
-               interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
-       }
+       interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
+       interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
 
        filename = g_strdup_printf("/sys/class/net/%s/uevent", name);
 
-- 
1.9.1

_______________________________________________
connman mailing list
connman@connman.net
https://lists.connman.net/mailman/listinfo/connman

Reply via email to