From 24d28cd679ab3962e8b29d620708ca8bc416d4c2 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Tue, 2 Apr 2024 15:25:51 +0200 Subject: [PATCH] ntp: add server support for KoD RATE Add "kod" option to the ratelimit directive to respond with the KoD RATE code to randomly selected requests exceeding the configured limit. This complements the client support of KoD RATE. It's disabled by default. There can be only one KoD code in one response. If both NTS NAK and RATE codes are triggered, drop the response. The KoD RATE code can be set in an NTS-authenticated response. --- clientlog.c | 2 +- conf.c | 16 ++++++++++------ conf.h | 2 +- doc/chrony.conf.adoc | 14 +++++++++++--- ntp_core.c | 7 +++++++ test/simulation/135-ratelimit | 11 +++++++++++ 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/clientlog.c b/clientlog.c index 43cba67..4297fe2 100644 --- a/clientlog.c +++ b/clientlog.c @@ -374,7 +374,7 @@ CLG_Initialise(void) switch (i) { case CLG_NTP: - if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate)) + if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate, &krate)) continue; break; case CLG_NTSKE: diff --git a/conf.c b/conf.c index 8849bdc..7426e61 100644 --- a/conf.c +++ b/conf.c @@ -79,7 +79,7 @@ static void parse_maxchange(char *); static void parse_ntsserver(char *, ARR_Instance files); static void parse_ntstrustedcerts(char *); static void parse_ratelimit(char *line, int *enabled, int *interval, - int *burst, int *leak); + int *burst, int *leak, int *kod); static void parse_refclock(char *); static void parse_smoothtime(char *); static void parse_source(char *line, char *type, int fatal); @@ -220,6 +220,7 @@ static int ntp_ratelimit_enabled = 0; static int ntp_ratelimit_interval = 3; static int ntp_ratelimit_burst = 8; static int ntp_ratelimit_leak = 2; +static int ntp_ratelimit_kod = 0; static int nts_ratelimit_enabled = 0; static int nts_ratelimit_interval = 6; static int nts_ratelimit_burst = 8; @@ -591,7 +592,7 @@ CNF_ParseLine(const char *filename, int number, char *line) parse_int(p, &cmd_port); } else if (!strcasecmp(command, "cmdratelimit")) { parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval, - &cmd_ratelimit_burst, &cmd_ratelimit_leak); + &cmd_ratelimit_burst, &cmd_ratelimit_leak, NULL); } else if (!strcasecmp(command, "combinelimit")) { parse_double(p, &combine_limit); } else if (!strcasecmp(command, "confdir")) { @@ -678,7 +679,7 @@ CNF_ParseLine(const char *filename, int number, char *line) parse_string(p, &ntp_signd_socket); } else if (!strcasecmp(command, "ntsratelimit")) { parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval, - &nts_ratelimit_burst, &nts_ratelimit_leak); + &nts_ratelimit_burst, &nts_ratelimit_leak, NULL); } else if (!strcasecmp(command, "ntscachedir") || !strcasecmp(command, "ntsdumpdir")) { parse_string(p, &nts_dump_dir); @@ -710,7 +711,7 @@ CNF_ParseLine(const char *filename, int number, char *line) parse_int(p, &ptp_port); } else if (!strcasecmp(command, "ratelimit")) { parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval, - &ntp_ratelimit_burst, &ntp_ratelimit_leak); + &ntp_ratelimit_burst, &ntp_ratelimit_leak, &ntp_ratelimit_kod); } else if (!strcasecmp(command, "refclock")) { parse_refclock(p); } else if (!strcasecmp(command, "refresh")) { @@ -848,7 +849,7 @@ parse_sourcedir(char *line) /* ================================================== */ static void -parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak) +parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak, int *kod) { int n, val; char *opt; @@ -869,6 +870,8 @@ parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak) *burst = val; else if (!strcasecmp(opt, "leak")) *leak = val; + else if (!strcasecmp(opt, "kod") && kod) + *kod = val; else command_parse_error(); } @@ -2428,11 +2431,12 @@ CNF_GetLockMemory(void) /* ================================================== */ -int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak) +int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak, int *kod) { *interval = ntp_ratelimit_interval; *burst = ntp_ratelimit_burst; *leak = ntp_ratelimit_leak; + *kod = ntp_ratelimit_kod; return ntp_ratelimit_enabled; } diff --git a/conf.h b/conf.h index 4c0a787..4479c9c 100644 --- a/conf.h +++ b/conf.h @@ -115,7 +115,7 @@ extern void CNF_SetupAccessRestrictions(void); extern int CNF_GetSchedPriority(void); extern int CNF_GetLockMemory(void); -extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak); +extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak, int *kod); extern int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak); extern int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak); extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only); diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc index bd296bc..b6cd421 100644 --- a/doc/chrony.conf.adoc +++ b/doc/chrony.conf.adoc @@ -1861,6 +1861,14 @@ source address from completely blocking responses to that address. The leak rate is defined as a power of 1/2 and it is 2 by default, i.e. on average at least every fourth request has a response. The minimum value is 1 and the maximum value is 4. +*kod* _rate_::: +This option sets the rate at which Kiss-o'-Death (KoD) RATE responses are +randomly sent when the limits specified by the *interval* and *burst* options +are exceeded. It is an additional stream of responses to the *leak* option. A +KoD RATE response is a request for the client to reduce its polling rate. Few +implementations actually support it. The rate is defined as a power of 1/2. The +default value is 0, which means disabled. The minimum value is 0 and the maximu +value is 4. {blank}:: + An example use of the directive is: @@ -1876,7 +1884,7 @@ packets, by up to 75% (with default *leak* of 2). [[ntsratelimit]]*ntsratelimit* [_option_]...:: This directive enables rate limiting of NTS-KE requests. It is similar to the <> directive, except the default interval is 6 -(1 connection per 64 seconds). +(1 connection per 64 seconds) and the *kod* option is not supported. + An example of the use of the directive is: + @@ -2024,8 +2032,8 @@ need to be run with the *-p 257* option to inter-operate correctly.) [[cmdratelimit]]*cmdratelimit* [_option_]...:: This directive enables response rate limiting for command packets. It is similar to the <> directive, except responses to -localhost are never limited and the default interval is -4 (16 packets per -second). +localhost are never limited, the default interval is -4 (16 packets per +second), and the *kod* option is not supported. + An example of the use of the directive is: + diff --git a/ntp_core.c b/ntp_core.c index 6aa8e18..149e32a 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -2717,6 +2717,13 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a return; } + if (limit == CLG_KOD) { + /* Don't respond if there is a conflict with the NTS NAK */ + if (kod != 0) + return; + kod = KOD_RATE; + } + local_ntp_rx = NULL; tx_ts = NULL; interleaved = 0; diff --git a/test/simulation/135-ratelimit b/test/simulation/135-ratelimit index 86c435d..0756f19 100755 --- a/test/simulation/135-ratelimit +++ b/test/simulation/135-ratelimit @@ -15,4 +15,15 @@ check_sync || test_fail check_file_messages " 2 1 " 1200 1300 log.packets || test_fail check_file_messages " 1 2 " 180 220 log.packets || test_fail +server_conf="ratelimit interval 6 burst 2 leak 4 kod 2" + +run_test || test_fail +check_chronyd_exit || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +check_file_messages " 2 1 " 700 850 log.packets || test_fail +check_file_messages " 1 2 " 350 450 log.packets || test_fail +check_log_messages "Received KoD RATE.*\.123.1" 100 140 || test_fail + test_pass