summaryrefslogtreecommitdiffstats
path: root/src/monitor/monitor_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/monitor/monitor_netlink.c')
-rw-r--r--src/monitor/monitor_netlink.c158
1 files changed, 155 insertions, 3 deletions
diff --git a/src/monitor/monitor_netlink.c b/src/monitor/monitor_netlink.c
index cbf717fc3..737266bfb 100644
--- a/src/monitor/monitor_netlink.c
+++ b/src/monitor/monitor_netlink.c
@@ -24,6 +24,7 @@
#include <talloc.h>
#include <tevent.h>
#include <sys/types.h>
+#include <sys/ioctl.h>
#define __USE_GNU /* needed for struct ucred */
#include <sys/socket.h>
#include <unistd.h>
@@ -36,6 +37,7 @@
#include <linux/if.h>
#include <linux/socket.h>
#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/addr.h>
@@ -55,6 +57,14 @@
#define nlw_object_match nl_object_match_filter
#define NLW_OK NL_OK
+#define SYSFS_IFACE_TEMPLATE "/sys/class/net/%s/type"
+#define SYSFS_IFACE_PATH_MAX (21+IFNAMSIZ)
+
+#define PHY_80211_SUBDIR "phy80211"
+#define SYSFS_SUBDIR_PATH_MAX (SYSFS_IFACE_PATH_MAX+9)
+
+#define BUFSIZE 8
+
struct netlink_ctx {
#ifdef HAVE_LIBNL
struct nl_handle *nlh;
@@ -76,6 +86,141 @@ static int netlink_ctx_destructor(void *ptr)
}
/*******************************************************************
+ * Utility functions
+ *******************************************************************/
+
+static bool has_wireless_extension(const char *ifname)
+{
+ int s;
+ errno_t ret;
+ struct iwreq iwr;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s == -1) {
+ ret = errno;
+ DEBUG(2, ("Could not open socket: [%d] %s\n", ret, strerror(ret)));
+ return false;
+ }
+
+ strncpy(iwr.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);
+ /* Does the interface support a wireless extension? */
+ ret = ioctl(s, SIOCGIWNAME, &iwr);
+ close(s);
+
+ return ret == 0;
+}
+
+static bool has_ethernet_encapsulation(const char *sysfs_path)
+{
+ errno_t ret;
+ int fd = -1;
+ char buf[BUFSIZE];
+
+ fd = open(sysfs_path, O_RDONLY);
+ if (fd == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not open sysfs file %s: [%d] %s\n",
+ sysfs_path, ret, strerror(ret)));
+ return false;
+ }
+
+ memset(buf, 0, BUFSIZE);
+ while ((ret = read(fd, buf, BUFSIZE)) != 0) {
+ if (ret == -1) {
+ ret = errno;
+ if (ret == EINTR || ret == EAGAIN) {
+ continue;
+ }
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("read failed [%d][%s].\n", ret, strerror(ret)));
+ close(fd);
+ return false;
+ }
+ }
+ close(fd);
+
+ return strncmp(buf, "1\n", BUFSIZE) == 0;
+}
+
+static bool has_phy_80211_subdir(const char *sysfs_path)
+{
+ char phy80211_path[SYSFS_IFACE_PATH_MAX];
+ struct stat statbuf;
+ errno_t ret;
+
+ ret = snprintf(phy80211_path, SYSFS_SUBDIR_PATH_MAX,
+ "%s/%s", sysfs_path, PHY_80211_SUBDIR);
+ if (ret < 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("snprintf failed"));
+ return false;
+ } else if (ret >= SYSFS_SUBDIR_PATH_MAX) {
+ DEBUG(SSSDBG_OP_FAILURE, ("path too long?!?!\n"));
+ return false;
+ }
+
+ errno = 0;
+ ret = stat(phy80211_path, &statbuf);
+ if (ret == -1) {
+ ret = errno;
+ if (ret == ENOENT || ret == ENOTDIR) {
+ DEBUG(SSSDBG_TRACE_LIBS, ("No %s directory in sysfs, probably "
+ "not a wireless interface\n", PHY_80211_SUBDIR));
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("stat failed: [%d] %s\n",
+ ret, strerror(ret)));
+ }
+ return false;
+ }
+
+ if (statbuf.st_mode & S_IFDIR) {
+ DEBUG(SSSDBG_TRACE_LIBS, ("Directory %s found in sysfs, looks like "
+ "a wireless iface\n", PHY_80211_SUBDIR));
+ return true;
+ }
+
+ return false;
+}
+
+static bool discard_iff_up(const char *ifname)
+{
+ char path[SYSFS_IFACE_PATH_MAX];
+ errno_t ret;
+
+ /* This catches most of the new 80211 drivers */
+ if (has_wireless_extension(ifname)) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("%s has a wireless extension\n", ifname));
+ return true;
+ }
+
+ ret = snprintf(path, SYSFS_IFACE_PATH_MAX, SYSFS_IFACE_TEMPLATE, ifname);
+ if (ret < 0) {
+ DEBUG(SSSDBG_OP_FAILURE, ("snprintf failed"));
+ return false;
+ } else if (ret >= SYSFS_IFACE_PATH_MAX) {
+ DEBUG(SSSDBG_OP_FAILURE, ("path too long?!?!\n"));
+ return false;
+ }
+
+ /* This will filter PPP and such. Both wired and wireless
+ * interfaces have the encapsulation. */
+ if (!has_ethernet_encapsulation(path)) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("%s does not have ethernet encapsulation, "
+ "filtering out\n", ifname));
+ return true;
+ }
+
+ /* This captures old WEXT drivers, the new mac8011 would
+ * be caught by the ioctl check */
+ if (has_phy_80211_subdir(path)) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("%s has a 802_11 subdir, filtering out\n",
+ ifname));
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************
* Wrappers for different capabilities of different libnl versions
*******************************************************************/
@@ -237,8 +382,10 @@ static void link_msg_handler(struct nl_object *obj, void *arg)
{
struct netlink_ctx *ctx = (struct netlink_ctx *) arg;
struct rtnl_link *link_obj;
- int flags;
+ unsigned int flags;
+ char str_flags[512];
int ifidx;
+ const char *ifname;
if (!nlw_is_link_object(obj)) return;
@@ -246,10 +393,15 @@ static void link_msg_handler(struct nl_object *obj, void *arg)
flags = rtnl_link_get_flags(link_obj);
ifidx = rtnl_link_get_ifindex(link_obj);
- DEBUG(8, ("netlink link message: iface idx %d flags 0x%X\n", ifidx, flags));
+ rtnl_link_flags2str(flags, str_flags, 512);
+
+ ifname = rtnl_link_get_name(link_obj);
+ DEBUG(SSSDBG_TRACE_LIBS, ("netlink link message: iface idx %u (%s) "
+ "flags 0x%X (%s)\n", ifidx, ifname, flags, str_flags));
/* IFF_LOWER_UP is the indicator of carrier status */
- if (flags & IFF_LOWER_UP) {
+ if ((flags & IFF_RUNNING) && (flags & IFF_LOWER_UP) &&
+ !discard_iff_up(ifname)) {
ctx->change_cb(ctx->cb_data);
}
}