ndisc: honor default route parameters from RA route options

RFC 4191 section-3.1 says:

  When processing a Router Advertisement, a type C host first updates a
  ::/0 route based on the Router Lifetime and Default Router Preference
  in the Router Advertisement message header. [...] The Router Preference
  and Lifetime values in a ::/0 Route Information Option override the
  preference and lifetime values in the Router Advertisement header.

Fix the RA parsing so that the parameters from a default route option
are applied to the gateway.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1666
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2072

Fixes: c3a4656a68 ('rdisc: libndp implementation')
(cherry picked from commit 6c18fda519)
This commit is contained in:
Beniamino Galvani 2024-11-18 11:46:16 +01:00
parent 3917235a2d
commit d775c3d256

View file

@ -115,7 +115,8 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
NMNDisc *ndisc = (NMNDisc *) user_data; NMNDisc *ndisc = (NMNDisc *) user_data;
NMNDiscDataInternal *rdata = ndisc->rdata; NMNDiscDataInternal *rdata = ndisc->rdata;
NMNDiscConfigMap changed = 0; NMNDiscConfigMap changed = 0;
struct ndp_msgra *msgra = ndp_msgra(msg); NMNDiscGateway gateway;
struct ndp_msgra *msgra = ndp_msgra(msg);
struct in6_addr gateway_addr; struct in6_addr gateway_addr;
const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec(); const gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
int offset; int offset;
@ -174,23 +175,17 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
* Subsequent router advertisements can represent new default gateways * Subsequent router advertisements can represent new default gateways
* on the network. We should present all of them in router preference * on the network. We should present all of them in router preference
* order. * order.
*/ *
{ * https://tools.ietf.org/html/rfc2461#section-4.2 :
const NMNDiscGateway gateway = { * A Lifetime of 0 indicates that the router is not a default router and
.address = gateway_addr, * SHOULD NOT appear on the default router list.
.expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msgra_router_lifetime(msgra)), *
.preference = _route_preference_coerce(ndp_msgra_route_preference(msgra)), * We handle that by tracking a gateway that expires right now. */
}; gateway = (NMNDiscGateway) {
.address = gateway_addr,
/* https://tools.ietf.org/html/rfc2461#section-4.2 .expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msgra_router_lifetime(msgra)),
* > A Lifetime of 0 indicates that the router is not a .preference = _route_preference_coerce(ndp_msgra_route_preference(msgra)),
* > default router and SHOULD NOT appear on the default };
* > router list.
* We handle that by tracking a gateway that expires right now. */
if (nm_ndisc_add_gateway(ndisc, &gateway, now_msec))
changed |= NM_NDISC_CONFIG_GATEWAYS;
}
/* Addresses & Routes */ /* Addresses & Routes */
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREFIX) { ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREFIX) {
@ -240,9 +235,24 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
guint8 plen = ndp_msg_opt_route_prefix_len(msg, offset); guint8 plen = ndp_msg_opt_route_prefix_len(msg, offset);
struct in6_addr network; struct in6_addr network;
if (plen == 0 || plen > 128) if (plen > 128)
continue; continue;
if (plen == 0) {
/* https://tools.ietf.org/html/rfc4191#section-3.1 :
* When processing a Router Advertisement, a type C host first updates a
* ::/0 route based on the Router Lifetime and Default Router Preference
* in the Router Advertisement message header. [...] The Router Preference
* and Lifetime values in a ::/0 Route Information Option override the
* preference and lifetime values in the Router Advertisement header.
*/
gateway.preference =
_route_preference_coerce(ndp_msg_opt_route_preference(msg, offset));
gateway.expiry_msec =
_nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_route_lifetime(msg, offset));
continue;
}
nm_ip6_addr_clear_host_address(&network, ndp_msg_opt_route_prefix(msg, offset), plen); nm_ip6_addr_clear_host_address(&network, ndp_msg_opt_route_prefix(msg, offset), plen);
{ {
@ -262,6 +272,9 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
} }
} }
if (nm_ndisc_add_gateway(ndisc, &gateway, now_msec))
changed |= NM_NDISC_CONFIG_GATEWAYS;
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_RDNSS) { ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_RDNSS) {
struct in6_addr *addr; struct in6_addr *addr;
int addr_index; int addr_index;