mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-27 04:40:09 +01:00
It's possible that the first timeout gets delayed; therefore the
interval between the first and the second callback can be less than
one second, and the budget doesn't refill completely.
Schedule the second timeout from the first callback to guarantee that
at least one second passes between the callbacks.
Fixes: ff0c4346fc ('core: add rate-limiting helper')
342 lines
12 KiB
C
342 lines
12 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2015 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "src/core/nm-default-daemon.h"
|
|
|
|
#include <arpa/inet.h>
|
|
#include <linux/if_ether.h>
|
|
|
|
#include "nm-test-utils-core.h"
|
|
|
|
static void
|
|
test_stable_privacy(void)
|
|
{
|
|
struct in6_addr addr1;
|
|
|
|
inet_pton(AF_INET6, "1234::", &addr1);
|
|
nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_UUID,
|
|
&addr1,
|
|
"eth666",
|
|
"6b138152-9f3e-4b97-aaf7-e6e553f2a24e",
|
|
0,
|
|
(guint8 *) "key",
|
|
3);
|
|
nmtst_assert_ip6_address(&addr1, "1234::4ceb:14cd:3d54:793f");
|
|
|
|
/* We get an address without the UUID. */
|
|
inet_pton(AF_INET6, "1::", &addr1);
|
|
nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_UUID,
|
|
&addr1,
|
|
"eth666",
|
|
"",
|
|
384,
|
|
(guint8 *) "key",
|
|
3);
|
|
nmtst_assert_ip6_address(&addr1, "1::11aa:2530:9144:dafa");
|
|
|
|
/* We get a different address in a different network. */
|
|
inet_pton(AF_INET6, "2::", &addr1);
|
|
nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_UUID,
|
|
&addr1,
|
|
"eth666",
|
|
"",
|
|
384,
|
|
(guint8 *) "key",
|
|
3);
|
|
nmtst_assert_ip6_address(&addr1, "2::338e:8d:c11:8726");
|
|
|
|
inet_pton(AF_INET6, "1234::", &addr1);
|
|
nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_STABLE_ID,
|
|
&addr1,
|
|
"eth666",
|
|
"6b138152-9f3e-4b97-aaf7-e6e553f2a24e",
|
|
0,
|
|
(guint8 *) "key",
|
|
3);
|
|
nmtst_assert_ip6_address(&addr1, "1234::ad4c:ae44:3d30:af1e");
|
|
|
|
inet_pton(AF_INET6, "1234::", &addr1);
|
|
nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_STABLE_ID,
|
|
&addr1,
|
|
"eth666",
|
|
"stable-id-1",
|
|
0,
|
|
(guint8 *) "key",
|
|
3);
|
|
nmtst_assert_ip6_address(&addr1, "1234::4944:67b0:7a6c:1cf");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_do_test_hw_addr(NMUtilsStableType stable_type,
|
|
const char *stable_id,
|
|
const guint8 *secret_key,
|
|
gsize key_len,
|
|
const char *ifname,
|
|
const char *current_mac_address,
|
|
const char *generate_mac_address_mask,
|
|
const char *const *expected)
|
|
{
|
|
gs_free char *generated = NULL;
|
|
const char *const *e;
|
|
gboolean found = FALSE;
|
|
|
|
for (e = expected; *e; e++) {
|
|
g_assert(*e);
|
|
g_assert(nm_utils_hwaddr_valid(*e, ETH_ALEN));
|
|
}
|
|
|
|
generated = nm_utils_hw_addr_gen_stable_eth_impl(stable_type,
|
|
stable_id,
|
|
secret_key,
|
|
key_len,
|
|
ifname,
|
|
current_mac_address,
|
|
generate_mac_address_mask);
|
|
|
|
g_assert(generated);
|
|
g_assert(nm_utils_hwaddr_valid(generated, ETH_ALEN));
|
|
for (e = expected; *e; e++) {
|
|
if (!nm_utils_hwaddr_matches(generated, -1, *e, -1))
|
|
continue;
|
|
g_assert(!found);
|
|
found = TRUE;
|
|
g_assert_cmpstr(generated, ==, *e);
|
|
}
|
|
g_assert(found);
|
|
}
|
|
#define do_test_hw_addr(stable_type, \
|
|
stable_id, \
|
|
secret_key, \
|
|
ifname, \
|
|
current_mac_address, \
|
|
generate_mac_address_mask, \
|
|
...) \
|
|
_do_test_hw_addr((stable_type), \
|
|
(stable_id), \
|
|
(const guint8 *) "" secret_key "", \
|
|
NM_STRLEN(secret_key), \
|
|
(ifname), \
|
|
"" current_mac_address "", \
|
|
generate_mac_address_mask, \
|
|
NM_MAKE_STRV(__VA_ARGS__))
|
|
|
|
static void
|
|
test_hw_addr_gen_stable_eth(void)
|
|
{
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
NULL,
|
|
"06:0D:CD:0C:9E:2C");
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_STABLE_ID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
NULL,
|
|
"C6:AE:A9:9A:76:09");
|
|
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"FF:FF:FF:00:00:00",
|
|
"00:23:45:0C:9E:2C");
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"03:23:45:67:89:ab",
|
|
"FF:FF:FF:00:00:00",
|
|
"02:23:45:0C:9E:2C");
|
|
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"00:00:00:00:00:00",
|
|
"06:0D:CD:0C:9E:2C");
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"02:00:00:00:00:00",
|
|
"04:0D:CD:0C:9E:2C");
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"02:00:00:00:00:00",
|
|
"04:0D:CD:0C:9E:2C");
|
|
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"02:00:00:00:00:00 00:00:00:00:00:00",
|
|
"04:0D:CD:0C:9E:2C");
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"02:00:00:00:00:00 02:00:00:00:00:00",
|
|
"06:0D:CD:0C:9E:2C");
|
|
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"00:00:00:00:00:00 E9:60:CE:F5:ED:2F",
|
|
"06:0D:CD:0C:9E:2C");
|
|
|
|
do_test_hw_addr(NM_UTILS_STABLE_TYPE_UUID,
|
|
"stable-1",
|
|
"key1",
|
|
"eth0",
|
|
"01:23:45:67:89:ab",
|
|
"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00",
|
|
"06:0D:CD:0C:9E:2C",
|
|
"04:0D:CD:0C:9E:2C");
|
|
}
|
|
|
|
static void
|
|
test_shorten_hostname(void)
|
|
{
|
|
gs_free char *maxhost = NULL;
|
|
char *hostname;
|
|
|
|
#define do_test_shorten_hostname(_host, _exp_res, _exp_short) \
|
|
G_STMT_START \
|
|
{ \
|
|
gboolean _res; \
|
|
gs_free char *_short = NULL; \
|
|
\
|
|
_res = nm_utils_shorten_hostname((_host), &_short); \
|
|
g_assert_cmpint((_res), ==, (_exp_res)); \
|
|
g_assert_cmpstr(_short, ==, (_exp_short)); \
|
|
} \
|
|
G_STMT_END
|
|
|
|
/* 'maxhost' is the longest allowed hostname according to
|
|
* system configuration (`getconf HOST_NAME_MAX`). On Linux
|
|
* it's typically 64 characters, but POSIX allows up to
|
|
* 255 characters.
|
|
*
|
|
* We use our own define NM_HOST_NAME_MAX, which is always 64.
|
|
*/
|
|
maxhost = g_strnfill(NM_HOST_NAME_MAX, 'a');
|
|
|
|
do_test_shorten_hostname("name1", TRUE, NULL);
|
|
|
|
do_test_shorten_hostname("name1.example.com", TRUE, NULL);
|
|
|
|
do_test_shorten_hostname(maxhost, TRUE, NULL);
|
|
|
|
hostname = g_strdup_printf("%sbbb", maxhost);
|
|
do_test_shorten_hostname(hostname, TRUE, maxhost);
|
|
nm_clear_g_free(&hostname);
|
|
|
|
hostname = g_strdup_printf("%s.com", maxhost);
|
|
do_test_shorten_hostname(hostname, TRUE, maxhost);
|
|
nm_clear_g_free(&hostname);
|
|
|
|
hostname = g_strdup_printf("name1.%s.com", maxhost);
|
|
do_test_shorten_hostname(hostname, TRUE, "name1");
|
|
nm_clear_g_free(&hostname);
|
|
|
|
do_test_shorten_hostname(".name1", FALSE, NULL);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
typedef struct {
|
|
NMRateLimit ratelimit;
|
|
GMainLoop *loop;
|
|
GSource *source;
|
|
guint num;
|
|
} RateLimitData;
|
|
|
|
static int
|
|
rate_limit_window_expire_cb(gpointer user_data)
|
|
{
|
|
RateLimitData *data = user_data;
|
|
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
|
|
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
|
|
nm_clear_g_source_inst(&data->source);
|
|
g_main_loop_quit(data->loop);
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
rate_limit_check_cb(gpointer user_data)
|
|
{
|
|
RateLimitData *data = user_data;
|
|
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
|
|
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5));
|
|
|
|
nm_clear_g_source_inst(&data->source);
|
|
data->source = nm_g_timeout_add_source(1000, rate_limit_window_expire_cb, data);
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
static void
|
|
test_rate_limit_check(void)
|
|
{
|
|
RateLimitData data;
|
|
|
|
data = (RateLimitData) {
|
|
.loop = g_main_loop_new(NULL, FALSE),
|
|
.ratelimit = {},
|
|
.source = nm_g_timeout_add_source(1, rate_limit_check_cb, &data),
|
|
.num = 0,
|
|
};
|
|
|
|
g_main_loop_run(data.loop);
|
|
g_main_loop_unref(data.loop);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
NMTST_DEFINE();
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
nmtst_init_with_logging(&argc, &argv, NULL, "ALL");
|
|
|
|
g_test_add_func("/utils/stable_privacy", test_stable_privacy);
|
|
g_test_add_func("/utils/hw_addr_gen_stable_eth", test_hw_addr_gen_stable_eth);
|
|
g_test_add_func("/utils/shorten-hostname", test_shorten_hostname);
|
|
g_test_add_func("/utils/rate-limit-check", test_rate_limit_check);
|
|
|
|
return g_test_run();
|
|
}
|