/**
 * nm_netlink_foreach_route:
 * @ifindex: the interface index to filter routes for
 * @family: the address family to filter routes for
 * @scope: route scope, eg RT_SCOPE_LINK
 * @ignore_inet6_ll_mc: if %TRUE ignore IPv6 link-local and multi-cast routes
 * @callback: function called when a route matches the filter
 * @user_data: data passed to @callback
 *
 * Filters each route in the routing table against the given @ifindex and
 * @family (if given) and calls @callback for each matching route.
 *
 * Returns: a route if @callback returned one; the caller must dispose of the
 * route using rtnl_route_put() when it is no longer required.
 **/
struct rtnl_route *
nm_netlink_foreach_route (int ifindex,
                          int family,
                          int scope,
                          gboolean ignore_inet6_ll_mc,
                          NlRouteForeachFunc callback,
                          gpointer user_data)
{
	struct nl_cache *cache;
	ForeachRouteInfo info;

	memset (&info, 0, sizeof (info));
	info.ifindex = ifindex;
	info.family = family;
	info.scope = scope;
	info.ignore_inet6_ll_mc = ignore_inet6_ll_mc;
	info.callback = callback;
	info.user_data = user_data;
	info.iface = nm_netlink_index_to_iface (ifindex);

	rtnl_route_alloc_cache (nm_netlink_get_default_handle (), family, 0, &cache);
	g_warn_if_fail (cache != NULL);
	if (cache) {
		nl_cache_foreach (cache, foreach_route_cb, &info);
		nl_cache_free (cache);
	}
	g_free (info.iface);
	return info.out_route;
}
Exemplo n.º 2
0
static void
nm_ip6_manager_init (NMIP6Manager *manager)
{
	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);

	priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
	                                       NULL,
	                                       (GDestroyNotify) nm_ip6_device_destroy);

	priv->monitor = nm_netlink_monitor_get ();
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_ROUTE, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);

	priv->netlink_id = g_signal_connect (priv->monitor, "notification",
	                                     G_CALLBACK (netlink_notification), manager);

	priv->nlh = nm_netlink_get_default_handle ();
	rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache);
	g_warn_if_fail (priv->addr_cache != NULL);
	rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache);
	g_warn_if_fail (priv->route_cache != NULL);
}
/**
 * nm_netlink_route_delete:
 * @route: the route to delete
 *
 * Returns: %TRUE if the request was successful, %FALSE if it failed
 **/
gboolean
nm_netlink_route_delete (struct rtnl_route *route)
{
	struct nl_sock *nlh;
	int err = 0;

	g_return_val_if_fail (route != NULL, FALSE);

	nlh = nm_netlink_get_default_handle ();
	err = rtnl_route_delete (nlh, route, 0);

	if (err)
		nm_log_dbg (LOGD_IP4 | LOGD_IP6, "%s (%d)", nl_geterror(err), err);

	/* Workaround libnl BUG: ESRCH is aliased to generic NLE_FAILURE
	 * See: http://git.kernel.org/?p=libs/netlink/libnl.git;a=commit;h=7e9d5f */
	if (err == -NLE_FAILURE)
		err = -NLE_OBJ_NOTFOUND;

	return (err && (err != -NLE_OBJ_NOTFOUND) && (err != -NLE_RANGE) ) ? FALSE : TRUE;
}
/**
 * nm_netlink_find_address:
 * @ifindex: interface index
 * @family: address family, either AF_INET or AF_INET6
 * @addr: binary address, either struct in_addr* or struct in6_addr*
 * @prefix: prefix length
 *
 * Searches for a matching address on the given interface.
 *
 * Returns: %TRUE if the given address was found on the interface, %FALSE if it
 * was not found or an error occurred.
 **/
gboolean
nm_netlink_find_address (int ifindex,
                         int family,
                         void *addr,  /* struct in_addr or struct in6_addr */
                         int prefix)
{
	struct nl_sock *nlh = NULL;
	struct nl_cache *cache = NULL;
	FindAddrInfo info;

	g_return_val_if_fail (ifindex > 0, FALSE);
	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
	g_return_val_if_fail (addr != NULL, FALSE);
	g_return_val_if_fail (prefix >= 0, FALSE);

	memset (&info, 0, sizeof (info));
	info.ifindex = ifindex;
	info.family = family;
	info.prefix = prefix;
	info.addr = addr;
	if (family == AF_INET)
		info.addrlen = sizeof (struct in_addr);
	else if (family == AF_INET6)
		info.addrlen = sizeof (struct in6_addr);
	else
		g_assert_not_reached ();

	nlh = nm_netlink_get_default_handle ();
	if (nlh) {
		rtnl_addr_alloc_cache(nlh, &cache);
		if (cache) {
			nl_cache_mngt_provide (cache);
			nl_cache_foreach (cache, find_one_address, &info);
			nl_cache_free (cache);
		}
	}
	return info.found;
}
/**
 * _route_add:
 * @route: the route to add
 * @family: address family, either %AF_INET or %AF_INET6
 * @dest: the route destination address, either a struct in_addr or a struct
 *   in6_addr depending on @family
 * @dest_prefix: the CIDR prefix of @dest
 * @gateway: the gateway through which to reach @dest, if any; given as a
 *   struct in_addr or struct in6_addr depending on @family
 * @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
 *
 * Returns: zero if succeeded or the netlink error otherwise.
 **/
static int
_route_add (struct rtnl_route *route,
            int family,
            const void *dest, /* in_addr or in6_addr */
            int dest_prefix,
            const void *gateway, /* in_addr or in6_addr */
            int flags)
{
	struct nl_sock *sk;
	struct nl_addr *dest_addr, *gw_addr;
	void *tmp_addr;
	int addrlen, err, log;

	if (family == AF_INET) {
		addrlen = sizeof (struct in_addr);
		log = LOGD_IP4;
	} else if (family == AF_INET6) {
		addrlen = sizeof (struct in6_addr);
		log = LOGD_IP6;
	} else
		g_assert_not_reached ();

	sk = nm_netlink_get_default_handle ();

	/* Build up the destination address */
	if (dest) {
		/* Copy to preserve const */
		tmp_addr = g_malloc0 (addrlen);
		memcpy (tmp_addr, dest, addrlen);

		dest_addr = nl_addr_build (family, tmp_addr, addrlen);
		g_free (tmp_addr);

		g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL);
		nl_addr_set_prefixlen (dest_addr, dest_prefix);

		rtnl_route_set_dst (route, dest_addr);
		nl_addr_put (dest_addr);
	}

	/* Build up the gateway address */
	if (gateway) {
		tmp_addr = g_malloc0 (addrlen);
		memcpy (tmp_addr, gateway, addrlen);

		gw_addr = nl_addr_build (family, tmp_addr, addrlen);
		g_free (tmp_addr);

		if (gw_addr) {
			nl_addr_set_prefixlen (gw_addr, 0);
			rtnl_route_set_gateway (route, gw_addr);
			rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
			nl_addr_put (gw_addr);
		} else
			nm_log_err (LOGD_DEVICE | log, "Invalid gateway");
	}

	err = rtnl_route_add (sk, route, flags);

	/* LIBNL Bug: Aliased ESRCH */
	if (err == -NLE_FAILURE)
		err = -NLE_OBJ_NOTFOUND;

	return err;
}