From 72ac1e38f9bc9aa972f03ed0c85d9d7039d0583f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 Oct 2013 13:07:16 -0500 Subject: [PATCH] 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. --- src/rdisc/nm-lndp-rdisc.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index cc228fe0e..3dbabbf6b 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -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));