ndisc: rate limit number of accepted RA data to track

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.
This commit is contained in:
Thomas Haller
2021-01-25 09:31:17 +01:00
parent 3ab5f6550b
commit c2c8c67d8c

View File

@@ -23,6 +23,12 @@
#define RFC7559_IRT ((gint32) 4) /* RFC7559, Initial Retransmission Time, in seconds */ #define RFC7559_IRT ((gint32) 4) /* RFC7559, Initial Retransmission Time, in seconds */
#define RFC7559_MRT ((gint32) 3600) /* RFC7559, Maximum 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 { struct _NMNDiscPrivate {
@@ -49,10 +55,10 @@ struct _NMNDiscPrivate {
int ifindex; int ifindex;
char * ifname; char * ifname;
char * network_id; char * network_id;
guint max_addresses;
NMSettingIP6ConfigAddrGenMode addr_gen_mode; NMSettingIP6ConfigAddrGenMode addr_gen_mode;
NMUtilsStableType stable_type; NMUtilsStableType stable_type;
guint32 ra_timeout; guint32 ra_timeout;
gint32 max_addresses;
gint32 router_solicitations; gint32 router_solicitations;
gint32 router_solicitation_interval; gint32 router_solicitation_interval;
NMNDiscNodeType node_type; NMNDiscNodeType node_type;
@@ -425,6 +431,9 @@ nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new_item, gint64 now_
i++; i++;
} }
if (rdata->gateways->len >= _SIZE_MAX_GATEWAYS)
return FALSE;
if (new_item->expiry_msec <= now_msec) if (new_item->expiry_msec <= now_msec)
return FALSE; return FALSE;
@@ -587,7 +596,7 @@ nm_ndisc_add_address(NMNDisc * ndisc,
* what the kernel does, because it considers *all* addresses (including * what the kernel does, because it considers *all* addresses (including
* static and other temporary addresses). * static and other temporary addresses).
**/ **/
if (priv->max_addresses && rdata->addresses->len >= priv->max_addresses) if (rdata->addresses->len >= priv->max_addresses)
return FALSE; return FALSE;
if (new_item->expiry_msec <= now_msec) 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++; i++;
} }
if (rdata->routes->len >= _SIZE_MAX_ROUTES)
return FALSE;
if (new_item->expiry_msec <= now_msec) { if (new_item->expiry_msec <= now_msec) {
nm_assert(!changed); nm_assert(!changed);
return FALSE; 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) if (new_item->expiry_msec <= now_msec)
return FALSE; 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) if (new_item->expiry_msec <= now_msec)
return FALSE; 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 static void
clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) 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); 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); _ASSERT_data_gateways(rdata);
} }
static void static void
clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) 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; NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
NMNDiscAddress * arr; NMNDiscAddress * arr;
guint i; guint i;
@@ -1339,6 +1374,9 @@ clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint
*changed = NM_NDISC_CONFIG_ADDRESSES; *changed = NM_NDISC_CONFIG_ADDRESSES;
g_array_set_size(rdata->addresses, j); g_array_set_size(rdata->addresses, j);
} }
if (_array_set_size_max(rdata->gateways, priv->max_addresses))
*changed |= NM_NDISC_CONFIG_ADDRESSES;
} }
static void static void
@@ -1366,6 +1404,9 @@ clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64
*changed |= NM_NDISC_CONFIG_ROUTES; *changed |= NM_NDISC_CONFIG_ROUTES;
g_array_set_size(rdata->routes, j); g_array_set_size(rdata->routes, j);
} }
if (_array_set_size_max(rdata->gateways, _SIZE_MAX_ROUTES))
*changed |= NM_NDISC_CONFIG_ROUTES;
} }
static void static void
@@ -1393,6 +1434,9 @@ clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gi
*changed |= NM_NDISC_CONFIG_DNS_SERVERS; *changed |= NM_NDISC_CONFIG_DNS_SERVERS;
g_array_set_size(rdata->dns_servers, j); 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 static void
@@ -1425,6 +1469,9 @@ clean_dns_domains(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gi
*changed |= NM_NDISC_CONFIG_DNS_DOMAINS; *changed |= NM_NDISC_CONFIG_DNS_DOMAINS;
g_array_set_size(rdata->dns_domains, j); 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 static void
@@ -1531,6 +1578,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
{ {
NMNDisc * self = NM_NDISC(object); NMNDisc * self = NM_NDISC(object);
NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(self); NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(self);
int i;
switch (prop_id) { switch (prop_id) {
case PROP_PLATFORM: case PROP_PLATFORM:
@@ -1572,7 +1620,14 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
break; break;
case PROP_MAX_ADDRESSES: case PROP_MAX_ADDRESSES:
/* construct-only */ /* 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; break;
case PROP_RA_TIMEOUT: case PROP_RA_TIMEOUT:
/* construct-only */ /* construct-only */