rdisc: mask host bits off RA prefix (rh #1008104) (bgo #709230)

Some RA implementations (like radvd) dump whatever the user configures
onto the wire, accepting a prefix of "2001:db8:1:0::1/64" without
masking the host bits off.

This causes NetworkManager to send that route down to the kernel, which
*does* mask the host bits off.  This causes a mismatch between the
route NetworkManager expects the kernel to create, and what the kernel
actually created, when searching for the kernel object in the platform's
refresh_object() function:

	cache = choose_cache (platform, object);
	cached_object = nl_cache_search (choose_cache (platform, object), object);
	kernel_object = get_kernel_object (priv->nlh, object);

kernel_object is NULL since 'object' (a route which came from the RA
prefix) is not the same as the object the kernel actually did create.

Ensure we match kernel behavior by fixing up prefixes for dumb router
advertisement services.
This commit is contained in:
Dan Williams
2013-10-02 13:07:16 -05:00
parent b2ff06fc12
commit 72ac1e38f9

View File

@@ -401,6 +401,25 @@ fill_address_from_mac (struct in6_addr *address, const char *mac)
memcpy (identifier + 5, mac + 3, 3);
}
/* Ensure the given address is masked with its prefix and that all host
* bits are set to zero. Some IPv6 router advertisement daemons (eg, radvd)
* don't enforce this in their configuration.
*/
static void
set_address_masked (struct in6_addr *dst, struct in6_addr *src, guint8 plen)
{
guint nbytes = plen / 8;
guint nbits = plen % 8;
g_return_if_fail (plen <= 128);
g_assert (src);
g_assert (dst);
memset (dst, 0, sizeof (*dst));
memcpy (dst, src, nbytes);
dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
}
static int
receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
{
@@ -475,8 +494,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
/* Device route */
memset (&route, 0, sizeof (route));
route.network = *ndp_msg_opt_prefix (msg, offset);
route.plen = ndp_msg_opt_prefix_len (msg, offset);
set_address_masked (&route.network, ndp_msg_opt_prefix (msg, offset), route.plen);
route.timestamp = now;
if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) {
route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset);
@@ -506,8 +525,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
/* Routers through this particular gateway */
memset (&route, 0, sizeof (route));
route.gateway = gateway.address;
route.network = *ndp_msg_opt_route_prefix (msg, offset);
route.plen = ndp_msg_opt_route_prefix_len (msg, offset);
set_address_masked (&route.network, ndp_msg_opt_route_prefix (msg, offset), route.plen);
route.timestamp = now;
route.lifetime = ndp_msg_opt_route_lifetime (msg, offset);
route.preference = translate_preference (ndp_msg_opt_route_preference (msg, offset));