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