Exemplo n.º 1
0
	void NetLinkManager::run()
	{
		struct nl_handle *handle = nl_handle_alloc();
		nl_connect(handle, NETLINK_ROUTE);

		// init route messages
		nl_socket_add_membership(handle, RTNLGRP_IPV4_IFADDR);

//		IPv6 requires further support in the parsing procedures!
//		nl_socket_add_membership(handle, RTNLGRP_IPV6_IFADDR);
		nl_socket_add_membership(handle, RTNLGRP_LINK);

		// add netlink fd to vsocket
		_sock->add(nl_socket_get_fd(handle));

		try {
			while (_initialized)
			{
				std::list<int> fds;
				_sock->select(fds, NULL);
				int fd = fds.front();

				// create a new event object
				NetLinkManagerEvent lme(fd);

				// ignore if the event is unknown
				if (lme.getType() == LinkManagerEvent::EVENT_UNKOWN) continue;

				// ignore if this is an wireless extension event
				if (lme.isWirelessExtension()) continue;

				// need to refresh the cache
				{
					ibrcommon::MutexLock l(_call_mutex);
					_refresh_cache = true;
				}

				// print out some debugging
				IBRCOMMON_LOGGER_DEBUG(10) << lme.toString() << IBRCOMMON_LOGGER_ENDL;

				// notify all subscribers about this event
				raiseEvent(lme);
			}
		} catch (const vsocket_exception&) {
			// stopped / interrupted
			IBRCOMMON_LOGGER(error) << "NetLink connection stopped" << IBRCOMMON_LOGGER_ENDL;
		}

		nl_close(handle);
		nl_handle_destroy(handle);
	}
Exemplo n.º 2
0
static bool nl_new(struct dionaea *d)
{
	g_debug("%s", __PRETTY_FUNCTION__);
	nl_runtime.sock = nl_socket_alloc();
	struct nl_sock  *sock = nl_runtime.sock;
	nl_socket_disable_seq_check(sock);
	nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, nl_event_input, NULL);
	nl_join_groups(sock, RTMGRP_LINK);
	int err;
	if ( (err = nl_connect(sock, NETLINK_ROUTE)) < 0) 
	{
		g_error("Could not connect netlink (%s)", nl_geterror(err));
	}

	nl_socket_add_membership(sock, RTNLGRP_LINK);
	nl_socket_add_membership(sock, RTNLGRP_NEIGH);
	nl_socket_add_membership(sock, RTNLGRP_IPV4_IFADDR);
	nl_socket_add_membership(sock, RTNLGRP_IPV6_IFADDR);

	if( (err=rtnl_neigh_alloc_cache(sock, &nl_runtime.neigh_cache)) != 0 )
	{
		g_error("Could not allocate neigh cache! (%s)", nl_geterror(err));
	}
#if LIBNL_RTNL_LINK_ALLOC_CACHE_ARGC == 3
	if( (err=rtnl_link_alloc_cache(sock, AF_UNSPEC, &nl_runtime.link_cache)) != 0 )
#elif LIBNL_RTNL_LINK_ALLOC_CACHE_ARGC == 2
	if( (err=rtnl_link_alloc_cache(sock, &nl_runtime.link_cache)) != 0 )
#endif
	{
		g_error("Could not allocate link cache! (%s)", nl_geterror(err));
	}

	if( (err=rtnl_addr_alloc_cache(sock, &nl_runtime.addr_cache)) != 0 )
	{
		g_error("Could not allocate addr cache! (%s)", nl_geterror(err));
	}

	nl_cache_mngt_provide(nl_runtime.neigh_cache);
	nl_cache_mngt_provide(nl_runtime.link_cache);
	nl_cache_mngt_provide(nl_runtime.addr_cache);
	
	nl_runtime.ihandler = ihandler_new("dionaea.connection.*.accept", nl_ihandler_cb, NULL);

	ev_io_init(&nl_runtime.io_in, nl_io_in_cb, nl_socket_get_fd(sock), EV_READ);
	ev_io_start(g_dionaea->loop, &nl_runtime.io_in);
	nl_runtime.link_addr_cache = g_hash_table_new(g_int_hash, g_int_equal);
	nl_cache_foreach(nl_runtime.link_cache, nl_obj_input, NULL);
	nl_cache_foreach(nl_runtime.addr_cache, nl_obj_input, NULL);
    return true;
}
gboolean
nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error)
{
	NMNetlinkMonitorPrivate *priv;
	int subs, err;

	g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);

	priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);

	if (!priv->nlh_event) {
		if (!nm_netlink_monitor_open_connection (self, error))
			return FALSE;
	}

	subs = get_subs (self, group) + 1;
	if (subs == 1) {
		err = nl_socket_add_membership (priv->nlh_event, group);
		if (err < 0) {
			g_set_error (error, NM_NETLINK_MONITOR_ERROR,
			             NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP,
			             _("unable to join netlink group: %s"),
			             nl_geterror (err));
			return FALSE;
		}
	}

	/* Update # of subscriptions for this group */
	set_subs (self, group, subs);

	return TRUE;
}
Exemplo n.º 4
0
int
iface_mon_start(iface_mon_cb cb)
{
    int err;

    iface_mon_sock = nl_socket_alloc();
    if (!iface_mon_sock) {
        fprintf(stderr, "Failed to allocate netlink socket.\n");
        return -ENOMEM;
    }

    nl_socket_disable_seq_check(iface_mon_sock);

    nl_socket_modify_cb(iface_mon_sock, NL_CB_VALID, NL_CB_CUSTOM, iface_mon_handler, cb);

    if (nl_connect(iface_mon_sock, NETLINK_ROUTE)) {
        fprintf(stderr, "Failed to connect to generic netlink.\n");
        err = -ENOLINK;
        goto out_handle_destroy;
    }

    nl_socket_add_membership(iface_mon_sock, RTNLGRP_LINK);

    return 0;

out_handle_destroy:
    nl_socket_free(iface_mon_sock);
    return err;
}
gboolean
nm_netlink_listener_subscribe (NMNetlinkListener *listener,
							   int group,
							   GError **error)
{
	NMNetlinkListenerPrivate *priv;

	g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), FALSE);

	priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);

	if (!priv->nlh) {
		if (!open_connection (listener, error))
			return FALSE;
	}

	if (nl_socket_add_membership (priv->nlh, group) < 0) {
		g_set_error (error, NM_NETLINK_LISTENER_ERROR,
		             NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP,
		             _("unable to join netlink group: %s"),
		             nl_geterror ());
		return FALSE;
	}

	return TRUE;
}
Exemplo n.º 6
0
static int prepare_listen_events(void)
{
	int mcid, ret;

	/* Configuration multicast group */
	mcid = nl_get_multicast_id(state.nl_sock, "nl80211", "config");
	if (mcid < 0)
		return mcid;

	ret = nl_socket_add_membership(state.nl_sock, mcid);
	if (ret)
		return ret;

	/* Scan multicast group */
	mcid = nl_get_multicast_id(state.nl_sock, "nl80211", "scan");
	if (mcid >= 0) {
		ret = nl_socket_add_membership(state.nl_sock, mcid);
		if (ret)
			return ret;
	}

	/* Regulatory multicast group */
	mcid = nl_get_multicast_id(state.nl_sock, "nl80211", "regulatory");
	if (mcid >= 0) {
		ret = nl_socket_add_membership(state.nl_sock, mcid);
		if (ret)
			return ret;
	}

	/* MLME multicast group */
	mcid = nl_get_multicast_id(state.nl_sock, "nl80211", "mlme");
	if (mcid >= 0) {
		ret = nl_socket_add_membership(state.nl_sock, mcid);
		if (ret)
			return ret;
	}

	mcid = nl_get_multicast_id(state.nl_sock, "nl80211", "vendor");
	if (mcid >= 0) {
		ret = nl_socket_add_membership(state.nl_sock, mcid);
		if (ret)
			return ret;
	}

	return 0;
}
Exemplo n.º 7
0
int unl_genl_subscribe(struct unl *unl, const char *name)
{
	int mcid;

	mcid = unl_genl_multicast_id(unl, name);
	if (mcid < 0)
		return mcid;

	return nl_socket_add_membership(unl->sock, mcid);
}
Exemplo n.º 8
0
static struct nl_handle *init_netlink(void)
{
	struct nl_handle *handle;
	int ret, multicast_id;

	handle = nl_handle_alloc();
	if (!handle){
		elog("Cannot allocate netlink handle!\n");
		return NULL;
	}
	nl_disable_sequence_check(handle);
	ret = genl_connect(handle);
	if (ret < 0){
		elog("Cannot connect to netlink socket\n");
		return NULL;
	}

	/*
	familyid = genl_ctrl_resolve(handle, SAMPLE_NL_FAMILY_NAME);
	if (!familyid){
		elog("Cannot resolve family name(%s)\n", SAMPLE_NL_FAMILY_NAME);
		return NULL;
	}
	dlog("familyid %d\n", familyid);
	*/

	multicast_id = nl_get_multicast_id(handle, SAMPLE_NL_FAMILY_NAME, SAMPLE_NL_GRP_NAME);
	if (multicast_id < 0){
		elog("Cannot resolve grp name(%d)\n", SAMPLE_NL_GRP_NAME);
		return NULL;
	}

	ret = nl_socket_add_membership(handle, multicast_id);
	if (ret < 0){
		elog("Cannot join fs multicast group\n");
		return NULL;
	}

	ret = nl_socket_modify_cb(handle, NL_CB_VALID, NL_CB_CUSTOM,
			sample_nl_cb, NULL);
	if (ret < 0){
		elog("Cannot register callback for"
			 " netlink messages\n");
		return NULL;
	}

	return handle;
}
Exemplo n.º 9
0
static int wifi_add_membership(wifi_handle handle, const char *group)
{
    hal_info *info = getHalInfo(handle);

    int id = wifi_get_multicast_id(handle, "nl80211", group);
    if (id < 0) {
        ALOGE("Could not find group %s", group);
        return id;
    }

    int ret = nl_socket_add_membership(info->event_sock, id);
    if (ret < 0) {
        ALOGE("Could not add membership to group %s", group);
    }

    return ret;
}
Exemplo n.º 10
0
static wifi_error wifi_init_user_sock(hal_info *info)
{
    struct nl_sock *user_sock =
        wifi_create_nl_socket(WIFI_HAL_USER_SOCK_PORT, NETLINK_USERSOCK);
    if (user_sock == NULL) {
        ALOGE("Could not create diag sock");
        return WIFI_ERROR_UNKNOWN;
    }

    /* Set the socket buffer size */
    if (nl_socket_set_buffer_size(user_sock, (256*1024), 0) < 0) {
        ALOGE("Could not set size for user_sock: %s",
                   strerror(errno));
        /* continue anyway with the default (smaller) buffer */
    }
    else {
        ALOGV("nl_socket_set_buffer_size successful for user_sock");
    }

    struct nl_cb *cb = nl_socket_get_cb(user_sock);
    if (cb == NULL) {
        ALOGE("Could not get cb");
        return WIFI_ERROR_UNKNOWN;
    }

    info->user_sock_arg = 1;
    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &info->user_sock_arg);
    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &info->user_sock_arg);
    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &info->user_sock_arg);

    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, user_sock_message_handler, info);
    nl_cb_put(cb);

    int ret = nl_socket_add_membership(user_sock, 1);
    if (ret < 0) {
        ALOGE("Could not add membership");
        return WIFI_ERROR_UNKNOWN;
    }

    info->user_sock = user_sock;
    ALOGV("Initiialized diag sock successfully");
    return WIFI_SUCCESS;
}
Exemplo n.º 11
0
static ni_bool_t
__ni_rtevent_join_group(ni_rtevent_handle_t *handle, unsigned int group)
{
	int ret;

	if (!group || !handle || !handle->nlsock)
		return FALSE;

	if (ni_uint_array_contains(&handle->groups, group))
		return TRUE;

	if (!ni_uint_array_append(&handle->groups, group))
		return FALSE;

	ret = nl_socket_add_membership(handle->nlsock, group);
	if (ret != NLE_SUCCESS) {
		/* remove from array? */
		ni_error("Cannot add rtnetlink group %u membership: %s",
				group, nl_geterror(ret));
		return FALSE;
	}
	return TRUE;
}
Exemplo n.º 12
0
/**
 * Add cache to cache manager
 * @arg mngr		Cache manager.
 * @arg cache		Cache to be added to cache manager
 * @arg cb		Function to be called upon changes.
 * @arg data		Argument passed on to change callback
 *
 * Adds cache to the manager. The operation will trigger a full
 * dump request from the kernel to initially fill the contents
 * of the cache. The manager will subscribe to the notification group
 * of the cache and keep track of any further changes.
 *
 * The user is responsible for calling nl_cache_mngr_poll() or monitor
 * the socket and call nl_cache_mngr_data_ready() to allow the library
 * to process netlink notification events.
 *
 * @see nl_cache_mngr_poll()
 * @see nl_cache_mngr_data_ready()
 *
 * @return 0 on success or a negative error code.
 * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
 * 			       cache type
 * @return -NLE_OPNOTSUPP Cache type does not support updates
 * @return -NLE_EXIST Cache of this type already being managed
 */
int nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr, struct nl_cache *cache,
		      change_func_t cb, void *data)
{
	struct nl_cache_ops *ops;
	struct nl_af_group *grp;
	int err, i;

	ops = cache->c_ops;
	if (!ops)
		return -NLE_INVAL;

	if (ops->co_protocol != mngr->cm_protocol)
		return -NLE_PROTO_MISMATCH;

	if (ops->co_groups == NULL)
		return -NLE_OPNOTSUPP;

	for (i = 0; i < mngr->cm_nassocs; i++)
		if (mngr->cm_assocs[i].ca_cache &&
		    mngr->cm_assocs[i].ca_cache->c_ops == ops)
			return -NLE_EXIST;

retry:
	for (i = 0; i < mngr->cm_nassocs; i++)
		if (!mngr->cm_assocs[i].ca_cache)
			break;

	if (i >= mngr->cm_nassocs) {
		mngr->cm_nassocs += NASSOC_EXPAND;
		mngr->cm_assocs = realloc(mngr->cm_assocs,
					  mngr->cm_nassocs *
					  sizeof(struct nl_cache_assoc));
		if (mngr->cm_assocs == NULL)
			return -NLE_NOMEM;

		memset(mngr->cm_assocs + (mngr->cm_nassocs - NASSOC_EXPAND), 0,
		       NASSOC_EXPAND * sizeof(struct nl_cache_assoc));

		NL_DBG(1, "Increased capacity of cache manager %p " \
			  "to %d\n", mngr, mngr->cm_nassocs);
		goto retry;
	}

	for (grp = ops->co_groups; grp->ag_group; grp++) {
		err = nl_socket_add_membership(mngr->cm_sock, grp->ag_group);
		if (err < 0)
			return err;
	}

	err = nl_cache_refill(mngr->cm_sync_sock, cache);
	if (err < 0)
		goto errout_drop_membership;

	mngr->cm_assocs[i].ca_cache = cache;
	mngr->cm_assocs[i].ca_change = cb;
	mngr->cm_assocs[i].ca_change_data = data;

	if (mngr->cm_flags & NL_AUTO_PROVIDE)
		nl_cache_mngt_provide(cache);

	NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
	       cache, nl_cache_name(cache), mngr);

	return 0;

errout_drop_membership:
	for (grp = ops->co_groups; grp->ag_group; grp++)
		nl_socket_drop_membership(mngr->cm_sock, grp->ag_group);

	return err;
}
Exemplo n.º 13
0
int main(int argc, char **argv)
{
	int c;
	int i;
	int family;
	int group;
	struct nl_sock *nl;
	struct nl_msg *msg;
	char *dummy = NULL;

	/* Currently processed command info */
	struct iz_cmd cmd;


	/* Parse options */
	while (1) {
#ifdef HAVE_GETOPT_LONG
		int opt_idx = -1;
		c = getopt_long(argc, argv, "d::vh", iz_long_opts, &opt_idx);
#else
		c = getopt(argc, argv, "d::vh");
#endif
		if (c == -1)
			break;

		switch(c) {
		case 'd':
			if (optarg) {
				i = strtol(optarg, &dummy, 10);
				if (*dummy == '\0')
					iz_debug = nl_debug = i;
				else {
					fprintf(stderr, "Error: incorrect debug level: '%s'\n", optarg);
					exit(1);
				}
			} else
				iz_debug = nl_debug = 1;
			break;
		case 'v':
			printf(	"iz " VERSION "\n"
				"Copyright (C) 2008, 2009 by Siemens AG\n"
				"License GPLv2 GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.\n"
				"This is free software: you are free to change and redistribute it.\n"
				"There is NO WARRANTY, to the extent permitted by law.\n"
				"\n"
				"Written by Dmitry Eremin-Solenikov, Sergey Lapin and Maxim Osipov\n");
			return 0;
		case 'h':
			iz_help(argv[0]);
			return 0;
		default:
			iz_help(argv[0]);
			return 1;
		}
	}
	if (optind >= argc) {
		iz_help(argv[0]);
		return 1;
	}

	memset(&cmd, 0, sizeof(cmd));

	cmd.argc = argc - optind;
	cmd.argv = argv + optind;

	/* Parse command */
	cmd.desc = get_cmd(argv[optind]);
	if (!cmd.desc) {
		printf("Unknown command %s!\n", argv[optind]);
		return 1;
	}
	if (cmd.desc->parse) {
		i = cmd.desc->parse(&cmd);
		if (i == IZ_STOP_OK) {
			return 0;
		} else if (i == IZ_STOP_ERR) {
			printf("Command line parsing error!\n");
			return 1;
		}
	}

	/* Prepare NL command */
	nl = nl_socket_alloc();
	if (!nl) {
		nl_perror(NLE_NOMEM, "Could not allocate NL handle");
		return 1;
	}
	genl_connect(nl);
	family = genl_ctrl_resolve(nl, IEEE802154_NL_NAME);
	group = nl_get_multicast_id(nl,
			IEEE802154_NL_NAME, IEEE802154_MCAST_COORD_NAME);
	if (group < 0) {
		fprintf(stderr, "Could not get multicast group ID: %s\n", strerror(-group));
		return 1;
	}
	nl_socket_add_membership(nl, group);
	iz_seq = nl_socket_use_seq(nl) + 1;
	nl_socket_modify_cb(nl, NL_CB_VALID, NL_CB_CUSTOM,
		iz_cb_valid, (void*)&cmd);
	nl_socket_modify_cb(nl, NL_CB_FINISH, NL_CB_CUSTOM,
		iz_cb_finish, (void*)&cmd);
	nl_socket_modify_cb(nl, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
		iz_cb_seq_check, (void*)&cmd);

	/* Send request, if necessary */
	if (cmd.desc->request) {
		msg = nlmsg_alloc();
		if (!msg) {
			nl_perror(NLE_NOMEM, "Could not allocate NL message!\n"); /* FIXME: err */
			return 1;
		}
		genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0,
			cmd.flags, cmd.desc->nl_cmd, 1);

		if (cmd.desc->request(&cmd, msg) != IZ_CONT_OK) {
			printf("Request processing error!\n");
			return 1;
		}

		dprintf(1, "nl_send_auto_complete\n");
		nl_send_auto_complete(nl, msg);
		cmd.seq = nlmsg_hdr(msg)->nlmsg_seq;

		dprintf(1, "nlmsg_free\n");
		nlmsg_free(msg);
	}

	/* Received message handling loop */
	while (iz_exit == IZ_CONT_OK) {
		int err = nl_recvmsgs_default(nl);
		if (err != NLE_SUCCESS) {
			nl_perror(err, "Receive failed");
			return 1;
		}
	}
	nl_close(nl);

	if (iz_exit == IZ_STOP_ERR)
		return 1;

	return 0;
}
Exemplo n.º 14
0
/**
 * Add cache responsibility to cache manager
 * @arg mngr		Cache manager.
 * @arg name		Name of cache to keep track of
 * @arg cb		Function to be called upon changes.
 * @arg data		Argument passed on to change callback
 * @arg result		Pointer to store added cache.
 *
 * Allocates a new cache of the specified type and adds it to the manager.
 * The operation will trigger a full dump request from the kernel to
 * initially fill the contents of the cache. The manager will subscribe
 * to the notification group of the cache to keep track of any further
 * changes.
 *
 * @return 0 on success or a negative error code.
 */
int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
		      change_func_t cb, void *data, struct nl_cache **result)
{
	struct nl_cache_ops *ops;
	struct nl_cache *cache;
	struct nl_af_group *grp;
	int err, i;

	ops = nl_cache_ops_lookup(name);
	if (!ops)
		return -NLE_NOCACHE;

	if (ops->co_protocol != mngr->cm_protocol)
		return -NLE_PROTO_MISMATCH;

	if (ops->co_groups == NULL)
		return -NLE_OPNOTSUPP;

	for (i = 0; i < mngr->cm_nassocs; i++)
		if (mngr->cm_assocs[i].ca_cache &&
		    mngr->cm_assocs[i].ca_cache->c_ops == ops)
			return -NLE_EXIST;

retry:
	for (i = 0; i < mngr->cm_nassocs; i++)
		if (!mngr->cm_assocs[i].ca_cache)
			break;

	if (i >= mngr->cm_nassocs) {
		mngr->cm_nassocs += 16;
		mngr->cm_assocs = realloc(mngr->cm_assocs,
					  mngr->cm_nassocs *
					  sizeof(struct nl_cache_assoc));
		if (mngr->cm_assocs == NULL)
			return -NLE_NOMEM;
		else {
			NL_DBG(1, "Increased capacity of cache manager %p " \
				  "to %d\n", mngr, mngr->cm_nassocs);
			goto retry;
		}
	}

	cache = nl_cache_alloc(ops);
	if (!cache)
		return -NLE_NOMEM;

	for (grp = ops->co_groups; grp->ag_group; grp++) {
		err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
		if (err < 0)
			goto errout_free_cache;
	}

	err = nl_cache_refill(mngr->cm_handle, cache);
	if (err < 0)
		goto errout_drop_membership;

	mngr->cm_assocs[i].ca_cache = cache;
	mngr->cm_assocs[i].ca_change = cb;
	mngr->cm_assocs[i].ca_change_data = data;

	if (mngr->cm_flags & NL_AUTO_PROVIDE)
		nl_cache_mngt_provide(cache);

	NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
	       cache, nl_cache_name(cache), mngr);

	*result = cache;
	return 0;

errout_drop_membership:
	for (grp = ops->co_groups; grp->ag_group; grp++)
		nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
errout_free_cache:
	nl_cache_free(cache);

	return err;
}
Exemplo n.º 15
0
/**
 * virNetlinkEventServiceStart:
 *
 * start a monitor to receive netlink messages for libvirtd.
 * This registers a netlink socket with the event interface.
 *
 * @protocol: netlink protocol
 * @groups: broadcast groups to join in
 * Returns -1 if the monitor cannot be registered, 0 upon success
 */
int
virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups)
{
    virNetlinkEventSrvPrivatePtr srv;
    int fd;
    int ret = -1;

    if (protocol >= MAX_LINKS) {
        virReportSystemError(EINVAL,
                             _("invalid protocol argument: %d"), protocol);
        return -EINVAL;
    }

    if (server[protocol])
        return 0;

    VIR_INFO("starting netlink event service with protocol %d", protocol);

    if (VIR_ALLOC(srv) < 0)
        return -1;

    if (virMutexInit(&srv->lock) < 0) {
        VIR_FREE(srv);
        return -1;
    }

    virNetlinkEventServerLock(srv);

    /* Allocate a new socket and get fd */
    if (!(srv->netlinknh = virNetlinkCreateSocket(protocol)))
        goto error_locked;

    fd = nl_socket_get_fd(srv->netlinknh);
    if (fd < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot get netlink socket fd"));
        goto error_server;
    }

    if (groups && nl_socket_add_membership(srv->netlinknh, groups) < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot add netlink membership"));
        goto error_server;
    }

    if (nl_socket_set_nonblocking(srv->netlinknh)) {
        virReportSystemError(errno, "%s",
                             _("cannot set netlink socket nonblocking"));
        goto error_server;
    }

    if ((srv->eventwatch = virEventAddHandle(fd,
                                             VIR_EVENT_HANDLE_READABLE,
                                             virNetlinkEventCallback,
                                             srv, NULL)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to add netlink event handle watch"));
        goto error_server;
    }

    srv->netlinkfd = fd;
    VIR_DEBUG("netlink event listener on fd: %i running", fd);

    ret = 0;
    server[protocol] = srv;

 error_server:
    if (ret < 0) {
        nl_close(srv->netlinknh);
        virNetlinkFree(srv->netlinknh);
    }
 error_locked:
    virNetlinkEventServerUnlock(srv);
    if (ret < 0) {
        virMutexDestroy(&srv->lock);
        VIR_FREE(srv);
    }
    return ret;
}
Exemplo n.º 16
0
/**
 * virNetlinkCommand:
 * @nlmsg: pointer to netlink message
 * @respbuf: pointer to pointer where response buffer will be allocated
 * @respbuflen: pointer to integer holding the size of the response buffer
 *      on return of the function.
 * @src_pid: the pid of the process to send a message
 * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel
 * @protocol: netlink protocol
 * @groups: the group identifier
 *
 * Send the given message to the netlink layer and receive response.
 * Returns 0 on success, -1 on error. In case of error, no response
 * buffer will be returned.
 */
int virNetlinkCommand(struct nl_msg *nl_msg,
                      struct nlmsghdr **resp, unsigned int *respbuflen,
                      uint32_t src_pid, uint32_t dst_pid,
                      unsigned int protocol, unsigned int groups)
{
    int ret = -1;
    struct sockaddr_nl nladdr = {
            .nl_family = AF_NETLINK,
            .nl_pid    = dst_pid,
            .nl_groups = 0,
    };
    ssize_t nbytes;
    struct pollfd fds[1];
    int fd;
    int n;
    struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
    virNetlinkHandle *nlhandle = NULL;
    int len = 0;

    if (protocol >= MAX_LINKS) {
        virReportSystemError(EINVAL,
                             _("invalid protocol argument: %d"), protocol);
        goto cleanup;
    }

    if (!(nlhandle = virNetlinkCreateSocket(protocol)))
        goto cleanup;

    fd = nl_socket_get_fd(nlhandle);
    if (fd < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot get netlink socket fd"));
        goto cleanup;
    }

    if (groups && nl_socket_add_membership(nlhandle, groups) < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot add netlink membership"));
        goto cleanup;
    }

    nlmsg_set_dst(nl_msg, &nladdr);

    nlmsg->nlmsg_pid = src_pid ? src_pid : getpid();

    nbytes = nl_send_auto_complete(nlhandle, nl_msg);
    if (nbytes < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot send to netlink socket"));
        goto cleanup;
    }

    memset(fds, 0, sizeof(fds));
    fds[0].fd = fd;
    fds[0].events = POLLIN;

    n = poll(fds, ARRAY_CARDINALITY(fds), NETLINK_ACK_TIMEOUT_S);
    if (n <= 0) {
        if (n < 0)
            virReportSystemError(errno, "%s",
                                 _("error in poll call"));
        if (n == 0)
            virReportSystemError(ETIMEDOUT, "%s",
                                 _("no valid netlink response was received"));
        goto cleanup;
    }

    len = nl_recv(nlhandle, &nladdr, (unsigned char **)resp, NULL);
    if (len == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("nl_recv failed - returned 0 bytes"));
        goto cleanup;
    }
    if (len < 0) {
        virReportSystemError(errno, "%s", _("nl_recv failed"));
        goto cleanup;
    }

    ret = 0;
    *respbuflen = len;
 cleanup:
    if (ret < 0) {
        *resp = NULL;
        *respbuflen = 0;
    }

    virNetlinkFree(nlhandle);
    return ret;
}


/**
 * virNetlinkDumpLink:
 *
 * @ifname:  The name of the interface; only use if ifindex <= 0
 * @ifindex: The interface index; may be <= 0 if ifname is given
 * @data:    Gets a pointer to the raw data from netlink.
             MUST BE FREED BY CALLER!
 * @nlattr:  Pointer to a pointer of netlink attributes that will contain
 *           the results
 * @src_pid: pid used for nl_pid of the local end of the netlink message
 *           (0 == "use getpid()")
 * @dst_pid: pid of destination nl_pid if the kernel
 *           is not the target of the netlink message but it is to be
 *           sent to another process (0 if sending to the kernel)
 *
 * Get information from netlink about an interface given its name or index.
 *
 * Returns 0 on success, -1 on fatal error.
 */
int
virNetlinkDumpLink(const char *ifname, int ifindex,
                   void **nlData, struct nlattr **tb,
                   uint32_t src_pid, uint32_t dst_pid)
{
    int rc = -1;
    struct nlmsghdr *resp = NULL;
    struct nlmsgerr *err;
    struct ifinfomsg ifinfo = {
        .ifi_family = AF_UNSPEC,
        .ifi_index  = ifindex
    };
    unsigned int recvbuflen;
    struct nl_msg *nl_msg;

    if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0)
        return -1;

    ifinfo.ifi_index = ifindex;

    nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
    if (!nl_msg) {
        virReportOOMError();
        return -1;
    }

    if (nlmsg_append(nl_msg,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
        goto buffer_too_small;

    if (ifname) {
        if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
            goto buffer_too_small;
    }

# ifdef RTEXT_FILTER_VF
    /* if this filter exists in the kernel's netlink implementation,
     * we need to set it, otherwise the response message will not
     * contain the IFLA_VFINFO_LIST that we're looking for.
     */
    {
        uint32_t ifla_ext_mask = RTEXT_FILTER_VF;

        if (nla_put(nl_msg, IFLA_EXT_MASK,
                    sizeof(ifla_ext_mask), &ifla_ext_mask) < 0) {
            goto buffer_too_small;
        }
    }
# endif

    if (virNetlinkCommand(nl_msg, &resp, &recvbuflen,
                          src_pid, dst_pid, NETLINK_ROUTE, 0) < 0)
        goto cleanup;

    if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
        goto malformed_resp;

    switch (resp->nlmsg_type) {
    case NLMSG_ERROR:
        err = (struct nlmsgerr *)NLMSG_DATA(resp);
        if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
            goto malformed_resp;

        if (err->error) {
            virReportSystemError(-err->error,
                                 _("error dumping %s (%d) interface"),
                                 ifname, ifindex);
            goto cleanup;
        }
        break;

    case GENL_ID_CTRL:
    case NLMSG_DONE:
        rc = nlmsg_parse(resp, sizeof(struct ifinfomsg),
                         tb, IFLA_MAX, NULL);
        if (rc < 0)
            goto malformed_resp;
        break;

    default:
        goto malformed_resp;
    }
    rc = 0;
 cleanup:
    nlmsg_free(nl_msg);
    if (rc < 0)
       VIR_FREE(resp);
    *nlData = resp;
    return rc;

 malformed_resp:
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("malformed netlink response message"));
    goto cleanup;

 buffer_too_small:
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("allocated netlink buffer is too small"));
    goto cleanup;
}
Exemplo n.º 17
0
static struct nl_addr *process_get_neigh_mac(
		struct get_neigh_handler *neigh_handler)
{
	int err;
	struct nl_addr *ll_addr = get_neigh_mac(neigh_handler);
	struct rtnl_neigh *neigh_filter;
	fd_set fdset;
	int sock_fd;
	int fd;
	int nfds;
	int timer_fd;
	int ret;
	struct skt addr_dst;
	char buff[sizeof(SEND_PAYLOAD)] = SEND_PAYLOAD;
	int retries = 0;

	if (NULL != ll_addr)
		return ll_addr;

	err = nl_socket_add_membership(neigh_handler->sock,
				       RTNLGRP_NEIGH);
	if (err < 0)
		return NULL;

	neigh_filter = create_filter_neigh_for_dst(neigh_handler->dst,
						   neigh_handler->oif);
	if (neigh_filter == NULL)
		return NULL;

	set_neigh_filter(neigh_handler, neigh_filter);

	nl_socket_disable_seq_check(neigh_handler->sock);
	nl_socket_modify_cb(neigh_handler->sock, NL_CB_VALID, NL_CB_CUSTOM,
			    &get_neigh_cb, neigh_handler);

	fd = nl_socket_get_fd(neigh_handler->sock);

	err = create_socket(neigh_handler, &addr_dst, &sock_fd);

	if (err)
		return NULL;

	err = try_send_to(sock_fd, buff, sizeof(buff), &addr_dst);
	if (err)
		goto close_socket;

	timer_fd = create_timer(neigh_handler);
	if (timer_fd < 0)
		goto close_socket;

	nfds = MAX(fd, timer_fd) + 1;

	while (1) {
		FD_ZERO(&fdset);
		FD_SET(fd, &fdset);
		FD_SET(timer_fd, &fdset);

		/* wait for an incoming message on the netlink socket */
		ret = select(nfds, &fdset, NULL, NULL, NULL);
		if (ret == -1) {
			goto select_err;
		} else if (ret) {
			if (FD_ISSET(fd, &fdset)) {
				nl_recvmsgs_default(neigh_handler->sock);
				if (neigh_handler->found_ll_addr)
					break;
			} else {
				nl_cache_refill(neigh_handler->sock,
						neigh_handler->neigh_cache);
				ll_addr = get_neigh_mac(neigh_handler);
				if (NULL != ll_addr) {
					break;
				} else if (FD_ISSET(timer_fd, &fdset) &&
					   retries < NUM_OF_RETRIES) {
					try_send_to(sock_fd, buff, sizeof(buff),
						    &addr_dst);
				}
			}

			if (FD_ISSET(timer_fd, &fdset)) {
				uint64_t read_val;
				ssize_t rc;

				rc =
				    read(timer_fd, &read_val, sizeof(read_val));
				assert(rc == sizeof(read_val));
				if (++retries >=  NUM_OF_TRIES) {
					if (!errno)
						errno = EDESTADDRREQ;
					break;
				}
			}
		}
	}
select_err:
	close(timer_fd);
close_socket:
	close(sock_fd);
	return ll_addr ? ll_addr : neigh_handler->found_ll_addr;
}
Exemplo n.º 18
0
/**
 * virNetlinkCommand:
 * @nlmsg: pointer to netlink message
 * @respbuf: pointer to pointer where response buffer will be allocated
 * @respbuflen: pointer to integer holding the size of the response buffer
 *      on return of the function.
 * @src_pid: the pid of the process to send a message
 * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel
 * @protocol: netlink protocol
 * @groups: the group identifier
 *
 * Send the given message to the netlink layer and receive response.
 * Returns 0 on success, -1 on error. In case of error, no response
 * buffer will be returned.
 */
int virNetlinkCommand(struct nl_msg *nl_msg,
                      struct nlmsghdr **resp, unsigned int *respbuflen,
                      uint32_t src_pid, uint32_t dst_pid,
                      unsigned int protocol, unsigned int groups)
{
    int rc = 0;
    struct sockaddr_nl nladdr = {
            .nl_family = AF_NETLINK,
            .nl_pid    = dst_pid,
            .nl_groups = 0,
    };
    ssize_t nbytes;
    struct pollfd fds[1];
    int fd;
    int n;
    struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
    virNetlinkHandle *nlhandle = NULL;

    if (protocol >= MAX_LINKS) {
        virReportSystemError(EINVAL,
                             _("invalid protocol argument: %d"), protocol);
        return -EINVAL;
    }

    nlhandle = virNetlinkAlloc();
    if (!nlhandle) {
        virReportSystemError(errno,
                             "%s", _("cannot allocate nlhandle for netlink"));
        return -1;
    }

    if (nl_connect(nlhandle, protocol) < 0) {
        virReportSystemError(errno,
                        _("cannot connect to netlink socket with protocol %d"),
                             protocol);
        rc = -1;
        goto error;
    }

    fd = nl_socket_get_fd(nlhandle);
    if (fd < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot get netlink socket fd"));
        rc = -1;
        goto error;
    }

    if (groups && nl_socket_add_membership(nlhandle, groups) < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot add netlink membership"));
        rc = -1;
        goto error;
    }

    nlmsg_set_dst(nl_msg, &nladdr);

    nlmsg->nlmsg_pid = src_pid ? src_pid : getpid();

    nbytes = nl_send_auto_complete(nlhandle, nl_msg);
    if (nbytes < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot send to netlink socket"));
        rc = -1;
        goto error;
    }

    memset(fds, 0, sizeof(fds));
    fds[0].fd = fd;
    fds[0].events = POLLIN;

    n = poll(fds, ARRAY_CARDINALITY(fds), NETLINK_ACK_TIMEOUT_S);
    if (n <= 0) {
        if (n < 0)
            virReportSystemError(errno, "%s",
                                 _("error in poll call"));
        if (n == 0)
            virReportSystemError(ETIMEDOUT, "%s",
                                 _("no valid netlink response was received"));
        rc = -1;
        goto error;
    }

    *respbuflen = nl_recv(nlhandle, &nladdr,
                          (unsigned char **)resp, NULL);
    if (*respbuflen <= 0) {
        virReportSystemError(errno,
                             "%s", _("nl_recv failed"));
        rc = -1;
    }
error:
    if (rc == -1) {
        VIR_FREE(*resp);
        *resp = NULL;
        *respbuflen = 0;
    }

    virNetlinkFree(nlhandle);
    return rc;
}

static void
virNetlinkEventServerLock(virNetlinkEventSrvPrivatePtr driver)
{
    virMutexLock(&driver->lock);
}
static void obj_input(struct nl_object *obj, void *arg)
{
	struct nl_dump_params dp = {
		.dp_type = NL_DUMP_STATS,
		.dp_fd = stdout,
		.dp_dump_msgtype = 1,
	};

	nl_object_dump(obj, &dp);
}

static int event_input(struct nl_msg *msg, void *arg)
{
	if (nl_msg_parse(msg, &obj_input, NULL) < 0)
		fprintf(stderr, "<<EVENT>> Unknown message type\n");

	/* Exit nl_recvmsgs_def() and return to the main select() */
	return NL_STOP;
}

int main(int argc, char *argv[])
{
	struct nl_handle *nlh;
	int err = 1;
	int i, idx;

	static const struct {
		enum nfnetlink_groups gr_id;
		const char* gr_name;
	} known_groups[] = {
		{ NFNLGRP_CONNTRACK_NEW, "ct-new" },
		{ NFNLGRP_CONNTRACK_UPDATE, "ct-update" },
		{ NFNLGRP_CONNTRACK_DESTROY, "ct-destroy" },
		{ NFNLGRP_NONE, NULL }
	};

	if (nltool_init(argc, argv) < 0)
		return -1;

	nlh = nltool_alloc_handle();
	if (nlh == NULL)
		return -1;

	nl_disable_sequence_check(nlh);

	nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);

	if (argc > 1 && !strcasecmp(argv[1], "-h")) {
		printf("Usage: nf-monitor [<groups>]\n");

		printf("Known groups:");
		for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++)
			printf(" %s", known_groups[i].gr_name);
		printf("\n");
		return 2;
	}

	if (nfnl_connect(nlh) < 0) {
		fprintf(stderr, "%s\n", nl_geterror());
		goto errout;
	}

	for (idx = 1; argc > idx; idx++) {
		for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++) {
			if (!strcmp(argv[idx], known_groups[i].gr_name)) {

				if (nl_socket_add_membership(nlh, known_groups[i].gr_id) < 0) {
					fprintf(stderr, "%s: %s\n", argv[idx], nl_geterror());
					goto errout;
				}

				break;
			}
		}
		if (known_groups[i].gr_id == NFNLGRP_NONE)
			fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]);
	}

	while (1) {
		fd_set rfds;
		int fd, retval;

		fd = nl_socket_get_fd(nlh);

		FD_ZERO(&rfds);
		FD_SET(fd, &rfds);
		/* wait for an incoming message on the netlink socket */
		retval = select(fd+1, &rfds, NULL, NULL, NULL);

		if (retval) {
			/* FD_ISSET(fd, &rfds) will be true */
			nl_recvmsgs_default(nlh);
		}
	}

	nl_close(nlh);
errout:
	return err;
}
Exemplo n.º 20
0
/* 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;
}