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.
This commit is contained in:
Miroslav Lichvar 2024-04-02 15:25:51 +02:00
parent aac898343e
commit 24d28cd679
6 changed files with 41 additions and 11 deletions

View file

@ -374,7 +374,7 @@ CLG_Initialise(void)
switch (i) { switch (i) {
case CLG_NTP: case CLG_NTP:
if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate)) if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate, &krate))
continue; continue;
break; break;
case CLG_NTSKE: case CLG_NTSKE:

16
conf.c
View file

@ -79,7 +79,7 @@ static void parse_maxchange(char *);
static void parse_ntsserver(char *, ARR_Instance files); static void parse_ntsserver(char *, ARR_Instance files);
static void parse_ntstrustedcerts(char *); static void parse_ntstrustedcerts(char *);
static void parse_ratelimit(char *line, int *enabled, int *interval, 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_refclock(char *);
static void parse_smoothtime(char *); static void parse_smoothtime(char *);
static void parse_source(char *line, char *type, int fatal); 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_interval = 3;
static int ntp_ratelimit_burst = 8; static int ntp_ratelimit_burst = 8;
static int ntp_ratelimit_leak = 2; static int ntp_ratelimit_leak = 2;
static int ntp_ratelimit_kod = 0;
static int nts_ratelimit_enabled = 0; static int nts_ratelimit_enabled = 0;
static int nts_ratelimit_interval = 6; static int nts_ratelimit_interval = 6;
static int nts_ratelimit_burst = 8; static int nts_ratelimit_burst = 8;
@ -591,7 +592,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_int(p, &cmd_port); parse_int(p, &cmd_port);
} else if (!strcasecmp(command, "cmdratelimit")) { } else if (!strcasecmp(command, "cmdratelimit")) {
parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval, 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")) { } else if (!strcasecmp(command, "combinelimit")) {
parse_double(p, &combine_limit); parse_double(p, &combine_limit);
} else if (!strcasecmp(command, "confdir")) { } else if (!strcasecmp(command, "confdir")) {
@ -678,7 +679,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_string(p, &ntp_signd_socket); parse_string(p, &ntp_signd_socket);
} else if (!strcasecmp(command, "ntsratelimit")) { } else if (!strcasecmp(command, "ntsratelimit")) {
parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval, 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") || } else if (!strcasecmp(command, "ntscachedir") ||
!strcasecmp(command, "ntsdumpdir")) { !strcasecmp(command, "ntsdumpdir")) {
parse_string(p, &nts_dump_dir); parse_string(p, &nts_dump_dir);
@ -710,7 +711,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_int(p, &ptp_port); parse_int(p, &ptp_port);
} else if (!strcasecmp(command, "ratelimit")) { } else if (!strcasecmp(command, "ratelimit")) {
parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval, 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")) { } else if (!strcasecmp(command, "refclock")) {
parse_refclock(p); parse_refclock(p);
} else if (!strcasecmp(command, "refresh")) { } else if (!strcasecmp(command, "refresh")) {
@ -848,7 +849,7 @@ parse_sourcedir(char *line)
/* ================================================== */ /* ================================================== */
static void 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; int n, val;
char *opt; char *opt;
@ -869,6 +870,8 @@ parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak)
*burst = val; *burst = val;
else if (!strcasecmp(opt, "leak")) else if (!strcasecmp(opt, "leak"))
*leak = val; *leak = val;
else if (!strcasecmp(opt, "kod") && kod)
*kod = val;
else else
command_parse_error(); 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; *interval = ntp_ratelimit_interval;
*burst = ntp_ratelimit_burst; *burst = ntp_ratelimit_burst;
*leak = ntp_ratelimit_leak; *leak = ntp_ratelimit_leak;
*kod = ntp_ratelimit_kod;
return ntp_ratelimit_enabled; return ntp_ratelimit_enabled;
} }

2
conf.h
View file

@ -115,7 +115,7 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void); extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(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_GetNtsRateLimit(int *interval, int *burst, int *leak);
extern int CNF_GetCommandRateLimit(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); extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);

View file

@ -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 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 least every fourth request has a response. The minimum value is 1 and the
maximum value is 4. 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}:: {blank}::
+ +
An example use of the directive is: An example use of the directive is:
@ -1876,7 +1884,7 @@ packets, by up to 75% (with default *leak* of 2).
[[ntsratelimit]]*ntsratelimit* [_option_]...:: [[ntsratelimit]]*ntsratelimit* [_option_]...::
This directive enables rate limiting of NTS-KE requests. It is similar to the This directive enables rate limiting of NTS-KE requests. It is similar to the
<<ratelimit,*ratelimit*>> directive, except the default interval is 6 <<ratelimit,*ratelimit*>> 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: 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_]...:: [[cmdratelimit]]*cmdratelimit* [_option_]...::
This directive enables response rate limiting for command packets. It is This directive enables response rate limiting for command packets. It is
similar to the <<ratelimit,*ratelimit*>> directive, except responses to similar to the <<ratelimit,*ratelimit*>> directive, except responses to
localhost are never limited and the default interval is -4 (16 packets per localhost are never limited, the default interval is -4 (16 packets per
second). second), and the *kod* option is not supported.
+ +
An example of the use of the directive is: An example of the use of the directive is:
+ +

View file

@ -2717,6 +2717,13 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
return; 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; local_ntp_rx = NULL;
tx_ts = NULL; tx_ts = NULL;
interleaved = 0; interleaved = 0;

View file

@ -15,4 +15,15 @@ check_sync || test_fail
check_file_messages " 2 1 " 1200 1300 log.packets || test_fail check_file_messages " 2 1 " 1200 1300 log.packets || test_fail
check_file_messages " 1 2 " 180 220 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 test_pass