summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-10-02 13:07:16 -0500
committerDan Williams <dcbw@redhat.com>2013-10-03 13:59:18 -0500
commit72ac1e38f9bc9aa972f03ed0c85d9d7039d0583f (patch)
tree49ac6d67329af3e440442fb82969f7914ebb6bf8
parentb2ff06fc12dd755002216d7e70b98c14d8b6bfed (diff)
downloadNetworkManager-72ac1e38f9bc9aa972f03ed0c85d9d7039d0583f.tar.gz
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.
-rw-r--r--src/rdisc/nm-lndp-rdisc.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index cc228fe0ed..3dbabbf6b8 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));