diff options
author | Thomas Haller <thaller@redhat.com> | 2021-01-25 09:31:17 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-01-26 17:48:37 +0100 |
commit | 8e83229006e20c8997f4330fc2a8c6d048e19130 (patch) | |
tree | de198eb445ed6306d894aa39d3f96d1118665001 | |
parent | bb1d106016e0e5900145494519a923ef6d186cda (diff) | |
download | NetworkManager-th/ndisc-timeout-fixes.tar.gz |
ndisc: rate limit number of accepted RA data to trackth/ndisc-timeout-fixes
I don't think that the way we track RA data is correct. For example,
all data (like DNSSL) is tracked regardless of their router. That means,
if a router sends an update, we cannot prematurely expire a DNSSL list
which is no longer announced by that router. Anyway, that should be
reviewed and considered another time.
However, we also must rate limit the number of elements we track in
general. So far we would only do that for the addresses.
The limit for max_addresses, is already read by sysctl. We only limit
it further to at most 300 addresses. The 300 is arbitrarily chosen.
The limit for DNSSL and RDNSS are taken from systemd-networkd
(NDISC_DNSSL_MAX, NDISC_RDNSS_MAX), which is 64.
The limit for gateways and routes are not based on anything and just
made up.
-rw-r--r-- | src/ndisc/nm-ndisc.c | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c index 375efde56f..05da8eb7d1 100644 --- a/src/ndisc/nm-ndisc.c +++ b/src/ndisc/nm-ndisc.c @@ -23,6 +23,12 @@ #define RFC7559_IRT ((gint32) 4) /* RFC7559, Initial Retransmission Time, in seconds */ #define RFC7559_MRT ((gint32) 3600) /* RFC7559, Maximum Retransmission Time, in seconds */ +#define _SIZE_MAX_GATEWAYS 100u +#define _SIZE_MAX_ADDRESSES 100u +#define _SIZE_MAX_ROUTES 1000u +#define _SIZE_MAX_DNS_SERVERS 64u +#define _SIZE_MAX_DNS_DOMAINS 64u + /*****************************************************************************/ struct _NMNDiscPrivate { @@ -49,10 +55,10 @@ struct _NMNDiscPrivate { int ifindex; char * ifname; char * network_id; + guint max_addresses; NMSettingIP6ConfigAddrGenMode addr_gen_mode; NMUtilsStableType stable_type; guint32 ra_timeout; - gint32 max_addresses; gint32 router_solicitations; gint32 router_solicitation_interval; NMNDiscNodeType node_type; @@ -425,6 +431,9 @@ nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new_item, gint64 now_ i++; } + if (rdata->gateways->len >= _SIZE_MAX_GATEWAYS) + return FALSE; + if (new_item->expiry_msec <= now_msec) return FALSE; @@ -587,7 +596,7 @@ nm_ndisc_add_address(NMNDisc * ndisc, * what the kernel does, because it considers *all* addresses (including * static and other temporary addresses). **/ - if (priv->max_addresses && rdata->addresses->len >= priv->max_addresses) + if (rdata->addresses->len >= priv->max_addresses) return FALSE; if (new_item->expiry_msec <= now_msec) @@ -673,6 +682,9 @@ nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec i++; } + if (rdata->routes->len >= _SIZE_MAX_ROUTES) + return FALSE; + if (new_item->expiry_msec <= now_msec) { nm_assert(!changed); return FALSE; @@ -709,6 +721,9 @@ nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 } } + if (rdata->dns_servers->len >= _SIZE_MAX_DNS_SERVERS) + return FALSE; + if (new_item->expiry_msec <= now_msec) return FALSE; @@ -745,6 +760,9 @@ nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 } } + if (rdata->dns_domains->len >= _SIZE_MAX_DNS_DOMAINS) + return FALSE; + if (new_item->expiry_msec <= now_msec) return FALSE; @@ -1285,6 +1303,19 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed) /*****************************************************************************/ +static gboolean +_array_set_size_max(GArray *array, guint size_max) +{ + nm_assert(array); + nm_assert(size_max > 0u); + + if (array->len <= size_max) + return FALSE; + + g_array_set_size(array, size_max); + return TRUE; +} + static void clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { @@ -1311,12 +1342,16 @@ clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint6 g_array_set_size(rdata->gateways, j); } + if (_array_set_size_max(rdata->gateways, _SIZE_MAX_GATEWAYS)) + *changed |= NM_NDISC_CONFIG_GATEWAYS; + _ASSERT_data_gateways(rdata); } static void clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { + NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; NMNDiscAddress * arr; guint i; @@ -1339,6 +1374,9 @@ clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint *changed = NM_NDISC_CONFIG_ADDRESSES; g_array_set_size(rdata->addresses, j); } + + if (_array_set_size_max(rdata->gateways, priv->max_addresses)) + *changed |= NM_NDISC_CONFIG_ADDRESSES; } static void @@ -1366,6 +1404,9 @@ clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *changed |= NM_NDISC_CONFIG_ROUTES; g_array_set_size(rdata->routes, j); } + + if (_array_set_size_max(rdata->gateways, _SIZE_MAX_ROUTES)) + *changed |= NM_NDISC_CONFIG_ROUTES; } static void @@ -1393,6 +1434,9 @@ clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gi *changed |= NM_NDISC_CONFIG_DNS_SERVERS; g_array_set_size(rdata->dns_servers, j); } + + if (_array_set_size_max(rdata->gateways, _SIZE_MAX_DNS_SERVERS)) + *changed |= NM_NDISC_CONFIG_DNS_SERVERS; } static void @@ -1425,6 +1469,9 @@ clean_dns_domains(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gi *changed |= NM_NDISC_CONFIG_DNS_DOMAINS; g_array_set_size(rdata->dns_domains, j); } + + if (_array_set_size_max(rdata->gateways, _SIZE_MAX_DNS_DOMAINS)) + *changed |= NM_NDISC_CONFIG_DNS_DOMAINS; } static void @@ -1531,6 +1578,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps { NMNDisc * self = NM_NDISC(object); NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(self); + int i; switch (prop_id) { case PROP_PLATFORM: @@ -1572,7 +1620,14 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps break; case PROP_MAX_ADDRESSES: /* construct-only */ - priv->max_addresses = g_value_get_int(value); + i = g_value_get_int(value); + nm_assert(i >= 0); + priv->max_addresses = i; + + if (priv->max_addresses <= 0) + priv->max_addresses = _SIZE_MAX_ADDRESSES; + else if (priv->max_addresses > 3u * _SIZE_MAX_ADDRESSES) + priv->max_addresses = 3u * _SIZE_MAX_ADDRESSES; break; case PROP_RA_TIMEOUT: /* construct-only */ |