monitor_netlink.c revision fa6c70fabb8dc2fab580a014cdcf1b0dd3e99554
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek/*
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek SSSD - Service monitor - netlink support
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek Authors:
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek Jakub Hrozek <jhrozek@redhat.com>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek Parts of this code were borrowed from NetworkManager
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek Copyright (C) 2010 Red Hat
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek This program is free software; you can redistribute it and/or modify
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek it under the terms of the GNU General Public License as published by
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek (at your option) any later version.
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek This program is distributed in the hope that it will be useful,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek GNU General Public License for more details.
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek You should have received a copy of the GNU General Public License
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek*/
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <talloc.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <tevent.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <sys/types.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define __USE_GNU /* needed for struct ucred */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <sys/socket.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <unistd.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <fcntl.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include "monitor/monitor.h"
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include "util/util.h"
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_LIBNL
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <linux/if.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <linux/socket.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <linux/rtnetlink.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <netlink/netlink.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <netlink/utils.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <netlink/route/addr.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <netlink/route/link.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <netlink/route/rtnl.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#include <netlink/handlers.h>
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek/* Linux header file confusion causes this to be undefined. */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifndef SOL_NETLINK
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define SOL_NETLINK 270
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_LIBNL_OLDER_THAN_1_1
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_get_fd nl_handle_get_fd
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_recvmsgs_default nl_recvmsgs_def
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_get_pid nl_handle_get_pid
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_object_match nl_object_match
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define NLW_OK NL_PROCEED
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define OBJ_CAST(ptr) ((struct nl_object *) (ptr))
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_get_fd nl_socket_get_fd
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_recvmsgs_default nl_recvmsgs_default
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_get_pid nl_socket_get_local_port
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define nlw_object_match nl_object_match_filter
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#define NLW_OK NL_OK
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstruct netlink_ctx {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_LIBNL
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct nl_handle *nlh;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct tevent_fd *tefd;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek network_change_cb change_cb;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek void *cb_data;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek};
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_LIBNL
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int netlink_ctx_destructor(void *ptr)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx *nlctx;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlctx = talloc_get_type(ptr, struct netlink_ctx);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nl_handle_destroy(nlctx->nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return 0;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek/*******************************************************************
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek * Wrappers for different capabilities of different libnl versions
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek *******************************************************************/
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic bool nlw_accept_message(struct nl_handle *nlh,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek const struct sockaddr_nl *snl,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct nlmsghdr *hdr)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek bool accept_msg = false;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek uint32_t local_port;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (snl == NULL) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(3, ("Malformed message, skipping\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return false;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* Accept any messages from the kernel */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (hdr->nlmsg_pid == 0 || snl->nl_pid == 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek accept_msg = true;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* And any multicast message directed to our netlink PID, since multicast
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek * currently requires CAP_ADMIN to use.
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek local_port = nlw_get_pid(nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if ((hdr->nlmsg_pid == local_port) && snl->nl_groups) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek accept_msg = true;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (accept_msg == false) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(9, ("ignoring netlink message from PID %d",
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek hdr->nlmsg_pid));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return accept_msg;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic bool nlw_is_link_object(struct nl_object *obj)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek bool is_link_object = true;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct rtnl_link *filter;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek filter = rtnl_link_alloc();
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!filter) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(0, ("Allocation error!\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek is_link_object = false;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* Ensure it's a link object */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlw_object_match(obj, OBJ_CAST(filter))) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(2, ("Not a link object\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek is_link_object = false;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek rtnl_link_put(filter);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return is_link_object;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int nlw_enable_passcred(struct nl_handle *nlh)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifndef HAVE_NL_SET_PASSCRED
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return EOK; /* not available in this version */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return nl_set_passcred(nlh, 1); /* 1 = enabled */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int nlw_group_subscribe(struct nl_handle *nlh)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_NL_SOCKET_ADD_MEMBERSHIP
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nl_socket_add_membership(nlh, RTNLGRP_LINK);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Unable to add membership: %s\n", nl_geterror()));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int nlfd = nlw_get_fd(nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int group = RTNLGRP_LINK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek errno = 0;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = setsockopt(nlfd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek &group, sizeof(group));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret < 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = errno;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("setsockopt failed (%d): %s\n", ret, strerror(ret)));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return 0;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek/*******************************************************************
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek * Callbacks for validating and receiving messages
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek *******************************************************************/
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_LIBNL_OLDER_THAN_1_1
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int event_msg_recv(struct sockaddr_nl *nla, struct nlmsghdr *hdr,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek void *arg)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx *ctx = (struct netlink_ctx *) arg;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlw_accept_message(ctx->nlh, nla, hdr)) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NL_SKIP;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NLW_OK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int event_msg_recv(struct nl_msg *msg, void *arg)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx *ctx = (struct netlink_ctx *) arg;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct nlmsghdr *hdr;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek const struct sockaddr_nl *snl;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct ucred *creds;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek creds = nlmsg_get_creds(msg);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!creds || creds->uid != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(9, ("Ignoring netlink message from UID %d",
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek creds ? creds->uid : -1));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NL_SKIP;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek hdr = nlmsg_hdr(msg);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek snl = nlmsg_get_src(msg);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlw_accept_message(ctx->nlh, snl, hdr)) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NL_SKIP;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NLW_OK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic void link_msg_handler(struct nl_object *obj, void *arg);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifdef HAVE_LIBNL_OLDER_THAN_1_1
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int event_msg_ready(struct sockaddr_nl *nla, struct nlmsghdr *hdr,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek void *arg)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nl_msg_parse(hdr, &link_msg_handler, arg);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NLW_OK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int event_msg_ready(struct nl_msg *msg, void *arg)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nl_msg_parse(msg, &link_msg_handler, arg);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return NLW_OK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic int nlw_set_callbacks(struct nl_handle *nlh, void *data)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int ret = EIO;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifndef HAVE_NL_SOCKET_MODIFY_CB
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct nl_cb *cb = nl_handle_get_cb(nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nl_cb_set(cb, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, data);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nl_socket_modify_cb(nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, data);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Unable to set validation callback\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#ifndef HAVE_NL_SOCKET_MODIFY_CB
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, event_msg_ready, data);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_msg_ready, data);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Unable to set receive callback\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic void link_msg_handler(struct nl_object *obj, void *arg)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx *ctx = (struct netlink_ctx *) arg;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct rtnl_link *link_obj;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int flags;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int ifidx;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlw_is_link_object(obj)) return;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek link_obj = (struct rtnl_link *) obj;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek flags = rtnl_link_get_flags(link_obj);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ifidx = rtnl_link_get_ifindex(link_obj);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(8, ("netlink link message: iface idx %d flags 0x%X\n", ifidx, flags));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* IFF_LOWER_UP is the indicator of carrier status */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (flags & IFF_LOWER_UP) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ctx->change_cb(NL_ROUTE_UP, ctx->cb_data);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek } else {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ctx->change_cb(NL_ROUTE_DOWN, ctx->cb_data);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekstatic void netlink_fd_handler(struct tevent_context *ev, struct tevent_fd *fde,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek uint16_t flags, void *data)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx *nlctx = talloc_get_type(data, struct netlink_ctx);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlctx || !nlctx->nlh) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Invalid netlink handle, this is most likely a bug!\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nlw_recvmsgs_default(nlctx->nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != EOK) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Error while reading from netlink fd\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek/*******************************************************************
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek * Set up the netlink library
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek *******************************************************************/
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekint setup_netlink(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek network_change_cb change_cb, void *cb_data,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx **_nlctx)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx *nlctx;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek int nlfd;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek unsigned flags;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlctx = talloc_zero(mem_ctx, struct netlink_ctx);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlctx) return ENOMEM;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek talloc_set_destructor((TALLOC_CTX *) nlctx, netlink_ctx_destructor);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlctx->change_cb = change_cb;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlctx->cb_data = cb_data;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* allocate the libnl handle and register the default filter set */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlctx->nlh = nl_handle_alloc();
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (!nlctx->nlh) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, (("unable to allocate netlink handle: %s"),
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nl_geterror()));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = ENOMEM;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* Register our custom message validation filter */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nlw_set_callbacks(nlctx->nlh, nlctx);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Unable to set callbacks\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = EIO;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* Try to start talking to netlink */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nl_connect(nlctx->nlh, NETLINK_ROUTE);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Unable to connect to netlink: %s\n", nl_geterror()));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = EIO;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nlw_enable_passcred(nlctx->nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Cannot enable credential passing: %s\n", nl_geterror()));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = EIO;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek /* Subscribe to the LINK group for internal carrier signals */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = nlw_group_subscribe(nlctx->nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret != 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Unable to subscribe to netlink monitor\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = EIO;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nl_disable_sequence_check(nlctx->nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlfd = nlw_get_fd(nlctx->nlh);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek flags = fcntl(nlfd, F_GETFL, 0);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek errno = 0;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = fcntl(nlfd, F_SETFL, flags | O_NONBLOCK);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (ret < 0) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = errno;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("Cannot set the netlink fd to nonblocking\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek nlctx->tefd = tevent_add_fd(ev, nlctx, nlfd, TEVENT_FD_READ,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek netlink_fd_handler, nlctx);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek if (nlctx->tefd == NULL) {
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek DEBUG(1, ("tevent_add_fd() failed\n"));
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek ret = EIO;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek goto fail;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek }
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek *_nlctx = nlctx;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return EOK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekfail:
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek talloc_free(nlctx);
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return ret;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#else /* HAVE_LIBNL not defined */
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozekint setup_netlink(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek network_change_cb change_cb, void *cb_data,
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek struct netlink_ctx **_nlctx)
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek{
fa6c70fabb8dc2fab580a014cdcf1b0dd3e99554Sumit Bose if (_nlctx) *_nlctx = NULL;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek return EOK;
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek}
90acbcf20b5f896ca8f631923afe946c90d90de7Jakub Hrozek#endif