/* Create a socket to netlink interface_t */ int netlink_socket(nl_handle_t *nl, unsigned long groups) { socklen_t addr_len; int ret; memset(nl, 0, sizeof (*nl)); nl->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (nl->fd < 0) { log_message(LOG_INFO, "Netlink: Cannot open netlink socket : (%s)", strerror(errno)); return -1; } ret = fcntl(nl->fd, F_SETFL, O_NONBLOCK); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot set netlink socket flags : (%s)", strerror(errno)); close(nl->fd); return -1; } memset(&nl->snl, 0, sizeof (nl->snl)); nl->snl.nl_family = AF_NETLINK; nl->snl.nl_groups = groups; ret = bind(nl->fd, (struct sockaddr *) &nl->snl, sizeof (nl->snl)); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot bind netlink socket : (%s)", strerror(errno)); close(nl->fd); return -1; } addr_len = sizeof (nl->snl); ret = getsockname(nl->fd, (struct sockaddr *) &nl->snl, &addr_len); if (ret < 0 || addr_len != sizeof (nl->snl)) { log_message(LOG_INFO, "Netlink: Cannot getsockname : (%s)", strerror(errno)); close(nl->fd); return -1; } if (nl->snl.nl_family != AF_NETLINK) { log_message(LOG_INFO, "Netlink: Wrong address family %d", nl->snl.nl_family); close(nl->fd); return -1; } nl->seq = time(NULL); /* Set default rcvbuf size */ if_setsockopt_rcvbuf(&nl->fd, IF_DEFAULT_BUFSIZE); if (nl->fd < 0) return -1; return ret; }
/* Create a socket to netlink interface_t */ static int netlink_socket(nl_handle_t *nl, int flags, int group, ...) { int ret; va_list gp; memset(nl, 0, sizeof (*nl)); #ifdef _HAVE_LIBNL3_ /* We need to keep libnl3 in step with our netlink socket creation. */ nl->sk = nl_socket_alloc(); if ( nl->sk == NULL ) { log_message(LOG_INFO, "Netlink: Cannot allocate netlink socket" ); return -1; } ret = nl_connect(nl->sk, NETLINK_ROUTE); if (ret != 0) { log_message(LOG_INFO, "Netlink: Cannot open netlink socket : (%d)", ret); return -1; } /* Unfortunately we can't call nl_socket_add_memberships() with variadic arguments * from a variadic argument list passed to us */ va_start(gp, group); while (group != 0) { if (group < 0) { va_end(gp); return -1; } if ((ret = nl_socket_add_membership(nl->sk, group))) { log_message(LOG_INFO, "Netlink: Cannot add socket membership 0x%x : (%d)", group, ret); return -1; } group = va_arg(gp,int); } va_end(gp); if (flags & SOCK_NONBLOCK) { if ((ret = nl_socket_set_nonblocking(nl->sk))) { log_message(LOG_INFO, "Netlink: Cannot set netlink socket non-blocking : (%d)", ret); return -1; } } if ((ret = nl_socket_set_buffer_size(nl->sk, IF_DEFAULT_BUFSIZE, 0))) { log_message(LOG_INFO, "Netlink: Cannot set netlink buffer size : (%d)", ret); return -1; } nl->nl_pid = nl_socket_get_local_port(nl->sk); nl->fd = nl_socket_get_fd(nl->sk); /* Set CLOEXEC */ fcntl(nl->fd, F_SETFD, fcntl(nl->fd, F_GETFD) | FD_CLOEXEC); #else socklen_t addr_len; struct sockaddr_nl snl; #if !HAVE_DECL_SOCK_NONBLOCK int sock_flags = flags; flags &= ~SOCK_NONBLOCK; #endif nl->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | flags, NETLINK_ROUTE); if (nl->fd < 0) { log_message(LOG_INFO, "Netlink: Cannot open netlink socket : (%s)", strerror(errno)); return -1; } #if !HAVE_DECL_SOCK_NONBLOCK if ((sock_flags & SOCK_NONBLOCK) && set_sock_flags(nl->fd, F_SETFL, O_NONBLOCK)) return -1; #endif memset(&snl, 0, sizeof (snl)); snl.nl_family = AF_NETLINK; ret = bind(nl->fd, (struct sockaddr *) &snl, sizeof (snl)); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot bind netlink socket : (%s)", strerror(errno)); close(nl->fd); return -1; } /* Join the requested groups */ va_start(gp, group); while (group != 0) { if (group < 0) { va_end(gp); return -1; } ret = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); if (ret < 0) { log_message(LOG_INFO, "Netlink: Cannot add membership on netlink socket : (%s)", strerror(errno)); va_end(gp); return -1; } group = va_arg(gp,int); } va_end(gp); addr_len = sizeof (snl); ret = getsockname(nl->fd, (struct sockaddr *) &snl, &addr_len); if (ret < 0 || addr_len != sizeof (snl)) { log_message(LOG_INFO, "Netlink: Cannot getsockname : (%s)", strerror(errno)); close(nl->fd); return -1; } if (snl.nl_family != AF_NETLINK) { log_message(LOG_INFO, "Netlink: Wrong address family %d", snl.nl_family); close(nl->fd); return -1; } /* Save the port id for checking message source later */ nl->nl_pid = snl.nl_pid; /* Set default rcvbuf size */ if_setsockopt_rcvbuf(&nl->fd, IF_DEFAULT_BUFSIZE); #endif nl->seq = (uint32_t)time(NULL); if (nl->fd < 0) return -1; return ret; }