[Git][NTPsec/ntpsec][master] 2 commits: Add sanity check for mru list
Hal Murray
gitlab at mg.gitlab.com
Mon Apr 20 06:19:31 UTC 2020
Hal Murray pushed to branch master at NTPsec / ntpsec
Commits:
aaca5400 by Hal Murray at 2020-04-17T19:08:35-07:00
Add sanity check for mru list
- - - - -
df67c30e by Hal Murray at 2020-04-19T23:16:23-07:00
Add config and doc for rate limiting
- - - - -
14 changed files:
- docs/includes/access-commands.adoc
- docs/includes/accopt.adoc
- docs/includes/misc-options.adoc
- docs/includes/mrufmt.adoc
- docs/includes/ntpq-body.adoc
- include/ntp.h
- include/ntp_config.h
- include/ntpd.h
- ntpd/keyword-gen.c
- ntpd/ntp_config.c
- ntpd/ntp_monitor.c
- ntpd/ntp_parser.y
- ntpd/ntp_proto.c
- ntpd/ntp_timer.c
Changes:
=====================================
docs/includes/access-commands.adoc
=====================================
@@ -1,25 +1,21 @@
// Access control commands. Is included twice.
-[[discard]]+discard+ [+average+ _avg_] [+minimum+ _min_] [+monitor+ _prob_]::
- Set the parameters of the +limited+ facility which protects the server
- from client abuse. The +average+ subcommand specifies the minimum
- average packet spacing, while the +minimum+ subcommand specifies the
- minimum packet spacing. Packets that violate these minima are
- discarded and a kiss-o'-death packet returned if enabled. The default
- minimum average and minimum are 5 and 2, respectively. The monitor
- subcommand specifies the probability of discard for packets that
- overflow the rate-control window. The options are:
- +average+ 'avg';;
- Specify the minimum average interpacket spacing (minimum average
- headway time) in log~2~ s with default 3.
- +minimum+ 'min';;
- Specify the minimum interpacket spacing (guard time) in seconds with
- default 2.
- +monitor+;;
- Specify the probability of being recorded for packets that overflow
- the MRU list size limit set by +mru maxmem+ or +mru maxdepth+; this
- is a performance optimization for servers with aggregate arrivals of
- 1000 packets per second or more.
+[[limit]]+limit+ [+average+ _average_] [+burst+ _burst_] [+kod+ _kod_]::
+ Set the parameters of the _limited_ facility which protects the server
+ from client abuse. Internally, each link:ntpq.html#mrulist[MRU]
+ slot contains a _score_ in units of packets per second.
+ It is updated each time a packet arrives from that IP Address.
+ The _score_ decays exponentially at the _burst_ rate and is bumped
+ by 1.0/burst when a packet arrives.
+ +average+ 'average';;
+ Specify the allowed average rate for response packets
+ in packets per second. The default is 1.0
+ +burst+ 'burst';;
+ Specify the allowed burst size if the bursts are far enough apart
+ to keep the average rate below _average_. The default is 20.0
+ +kod+ 'kod';;
+ Specify the allowed average rate for KoD packets
+ in packets per second. The default is 0.5
[[restrict]]+restrict+ _address_[/_cidr_] [+mask+ _mask_] [+flag+ +...+]::
The _address_ argument expressed in dotted-quad (for IPv4) or
@@ -51,12 +47,10 @@
Deny packets of all kinds, including {ntpqman} queries.
+kod+;;
If this flag is set when an access violation occurs, a kiss-o'-death
- (KoD) packet is sent. KoD packets are rate limited to no more than
- one per second. If another KoD packet occurs within one second after
- the last one, the packet is dropped.
+ (KoD) packet is sent. KoD packets are rate limited.
+limited+;;
Deny service if the packet spacing violates the lower limits
- specified in the discard command. A history of clients is kept using
+ specified in the _limit_ command. A history of clients is kept using
the monitoring capability of {ntpdman}. Thus, monitoring is
always active as long as there is a restriction entry with
the limited flag.
@@ -71,8 +65,9 @@
Deny {ntpqman} queries which attempt
to modify the state of the server (i.e., run time reconfiguration).
Queries which return information are permitted.
- +noquery+;;
- Deny {ntpqman} queries. Time service is not affected.
+ +nomrulist+;;
+ Do not accept MRU-list requests. These can be expensive to
+ service and may generate a high volume of response traffic.
+nopeer+;;
Deny packets which would result in mobilizing a new association;
this includes symmetric active packets when a
@@ -81,6 +76,8 @@
We don't support that mode.
It used to include _pool_ servers, but they now poke a hole in any
restrictions.
+ +noquery+;;
+ Deny {ntpqman} queries. Time service is not affected.
+noserve+;;
Deny all packets except {ntpqman} and queries.
+notrust+;;
@@ -92,9 +89,6 @@
UDP port (123). Both +ntpport+ and +non-ntpport+ may be specified.
The +ntpport+ is considered more specific and is sorted later in the
list.
- +nomrulist+;;
- Do not accept MRU-list requests. These can be expensive to
- service and may generate a high volume of response traffic.
+version+;;
Deny packets that do not match the current NTP version.
--
=====================================
docs/includes/accopt.adoc
=====================================
@@ -1,5 +1,5 @@
=== Access Control Commands and Options
-* link:accopt.html#discard[discard - specify headway parameters]
+* link:accopt.html#limit[limit - specify rate limiting parameters]
* link:accopt.html#restrict[restrict - specify access restrictions]
* link:accopt.html#unrestrict[unrestrict - remove access restrictions]
* link:comdex.html[Command Index]
=====================================
docs/includes/misc-options.adoc
=====================================
@@ -1,10 +1,5 @@
// Miscellaneous options. Gets included twice.
-+calldelay+ _delay_::
- This option controls the delay in seconds between the first and second
- packets sent in burst or iburst mode to allow additional time for a
- modem or ISDN call to complete.
-
[[driftfile]]+driftfile+ _driftfile_::
This command specifies the complete path and name of the file used to
record the frequency of the local clock oscillator; this is the same
=====================================
docs/includes/mrufmt.adoc
=====================================
@@ -19,7 +19,7 @@ KoD response, respectively.
|+m+ |Packet mode.
|+v+ |Packet version number.
|+count+ |Packets received from this address.
-|+score+ |Packets per second with 20 second decay time.
+|+score+ |Packets per second (averaged with exponential decay).
|+drop+ |Packets dropped (or KoDed) from this address.
|+rport+ |Source port of last packet from this address.
|+remote address+|
=====================================
docs/includes/ntpq-body.adoc
=====================================
@@ -295,7 +295,7 @@ ind assid status conf reach auth condition last_event cnt
server so loaded that none of its MRU entries age out before they
are shipped. With this option, each segment is reported as it arrives.
-+mrulist+ [+limited+ | +kod+ | +mincount=+'count' | +mindrop=+'drop' | +minscore=+'score' | +maxlstint=+'seconds' | +minlstint=+'seconds' | +laddr=+'localaddr' | +sort=+'sortorder' | +resany=+'hexmask' | +resall=+'hexmask']::
+[[mrulist]]+mrulist+ [+limited+ | +kod+ | +mincount=+'count' | +mindrop=+'drop' | +minscore=+'score' | +maxlstint=+'seconds' | +minlstint=+'seconds' | +laddr=+'localaddr' | +sort=+'sortorder' | +resany=+'hexmask' | +resall=+'hexmask']::
Obtain and print traffic counts collected and maintained by the
monitor facility. This is useful for tracking who _uses_ or
_abuses_ your server.
=====================================
include/ntp.h
=====================================
@@ -567,7 +567,7 @@ struct pkt {
#define PROTO_FLOOR 17
#define PROTO_CEILING 18
/* #define PROTO_COHORT 19 */
-#define PROTO_CALLDELAY 20
+/* #define PROTO_CALLDELAY 20 */
#define PROTO_MINDIST 21
#define PROTO_MAXDIST 22
#define PROTO_MAXDISP 23
=====================================
include/ntp_config.h
=====================================
@@ -192,7 +192,7 @@ struct config_tree_tag {
filegen_fifo * filegen_opts;
/* Access Control Configuration */
- attr_val_fifo * discard_opts;
+ attr_val_fifo * limit_opts;
attr_val_fifo * mru_opts;
restrict_fifo * restrict_opts;
=====================================
include/ntpd.h
=====================================
@@ -126,6 +126,7 @@ extern void mon_setup(int);
extern void mon_setdown(int);
extern void mon_start(void);
extern void mon_stop(void);
+extern void mon_timer(void);
extern unsigned short ntp_monitor (struct recvbuf *, unsigned short);
extern void mon_clearinterface(endpt *interface);
extern int mon_get_oldest_age(l_fp);
@@ -340,19 +341,25 @@ struct monitor_data {
*/
unsigned int mon_enabled; /* MON_OFF (0) or other MON_* */
+/* Slot allocation sizes */
uint64_t mru_peakentries; /* highest mru_entries */
uint64_t mru_initalloc; /* entries to preallocate */
uint64_t mru_incalloc; /* allocation batch factor */
+/* Slot (re)allocation parameters */
uint64_t mru_mindepth; /* preempt above this */
- int mru_maxage; /* recycle if older than this */
- int mru_minage; /* recycle if older than this & full */
+ int mru_maxage; /* recycle if older than this */
+ int mru_minage; /* recycle if older & full */
uint64_t mru_maxdepth; /* MRU size hard limit */
+/* Slot (re)allocation counters */
uint64_t mru_exists; /* slot already exists */
uint64_t mru_new; /* allocated new slot */
- uint64_t mru_recycleold; /* recycle: age > maxage */
- uint64_t mru_recyclefull; /* recycle: full and age > minage */
+ uint64_t mru_recycleold; /* age > maxage */
+ uint64_t mru_recyclefull; /* full & age > minage */
uint64_t mru_none; /* couldn't allocate slot */
- int mon_age; /* preemption limit */
+/* rate limiting */
+ float rate_limit; /* responses per second */
+ float decay_time; /* seconds, exponential decay time */
+ float kod_limit ; /* KoDs per second */
};
extern struct monitor_data mon_data;
=====================================
ntpd/keyword-gen.c
=====================================
@@ -51,7 +51,6 @@ struct key_tok ntp_keywords[] = {
{ "pidfile", T_Pidfile, FOLLBY_STRING },
{ "pool", T_Pool, FOLLBY_STRING },
{ "ppspath", T_Ppspath, FOLLBY_STRING },
-{ "discard", T_Discard, FOLLBY_TOKEN },
{ "reset", T_Reset, FOLLBY_TOKEN },
{ "restrict", T_Restrict, FOLLBY_TOKEN },
{ "refclock", T_Refclock, FOLLBY_STRING },
@@ -131,6 +130,7 @@ struct key_tok ntp_keywords[] = {
{ "source", T_Source, FOLLBY_TOKEN },
{ "flake", T_Flake, FOLLBY_TOKEN },
{ "ignore", T_Ignore, FOLLBY_TOKEN },
+{ "limit", T_Limit, FOLLBY_TOKEN },
{ "limited", T_Limited, FOLLBY_TOKEN },
{ "mssntp", T_Mssntp, FOLLBY_TOKEN },
{ "kod", T_Kod, FOLLBY_TOKEN },
@@ -143,9 +143,8 @@ struct key_tok ntp_keywords[] = {
{ "noserve", T_Noserve, FOLLBY_TOKEN },
{ "notrust", T_Notrust, FOLLBY_TOKEN },
{ "ntpport", T_Ntpport, FOLLBY_TOKEN },
-/* discard_option */
+/* limit_option */
{ "average", T_Average, FOLLBY_TOKEN },
-{ "minimum", T_Minimum, FOLLBY_TOKEN },
{ "monitor", T_Monitor, FOLLBY_TOKEN },
/* mru_option */
{ "incalloc", T_Incalloc, FOLLBY_TOKEN },
=====================================
ntpd/ntp_config.c
=====================================
@@ -1592,35 +1592,28 @@ config_access(
keyword(my_opt->attr), my_opt->value.i);
}
- /* Configure the discard options */
- my_opt = HEAD_PFIFO(ptree->discard_opts);
+ /* Configure the limit options */
+ my_opt = HEAD_PFIFO(ptree->limit_opts);
for (; my_opt != NULL; my_opt = my_opt->link) {
switch (my_opt->attr) {
+ default:
+ INSIST(0);
+ break;
+
case T_Average:
- if (0 <= my_opt->value.i &&
- my_opt->value.i <= UCHAR_MAX)
- rstrct.ntp_minpoll = (uint8_t)my_opt->value.u;
- else
- msyslog(LOG_ERR,
- "CONFIG: discard average %d out of range, ignored.",
- my_opt->value.i);
+ mon_data.rate_limit = my_opt->value.d;
break;
- case T_Minimum:
- rstrct.ntp_minpkt = my_opt->value.i;
+ case T_Burst:
+ mon_data.decay_time = my_opt->value.d;
break;
- case T_Monitor:
- mon_data.mon_age = my_opt->value.i;
+ case T_Kod:
+ mon_data.kod_limit = my_opt->value.d;
break;
- default:
- msyslog(LOG_ERR,
- "CONFIG: Unknown discard option %s (%d)",
- keyword(my_opt->attr), my_opt->attr);
- exit(1);
}
}
@@ -1880,7 +1873,7 @@ free_config_access(
)
{
FREE_ATTR_VAL_FIFO(ptree->mru_opts);
- FREE_ATTR_VAL_FIFO(ptree->discard_opts);
+ FREE_ATTR_VAL_FIFO(ptree->limit_opts);
FREE_RESTRICT_FIFO(ptree->restrict_opts);
}
=====================================
ntpd/ntp_monitor.c
=====================================
@@ -64,7 +64,10 @@ struct monitor_data mon_data = {
.mru_recycleold = 0, /* recycle slot: age > mru_maxage */
.mru_recyclefull = 0, /* recycle slot: full and age > mru_minage */
.mru_none = 0, /* couldn't get one */
- .mon_age = 3000 /* preemption limit */
+ .rate_limit = 1.0, /* responses per second */
+ .decay_time = 20, /* seconds, exponential decay time */
+ .kod_limit = 0.5, /* KoDs per second */
+
};
/*
@@ -80,11 +83,6 @@ static void remove_from_hash(mon_entry *);
static void mon_free_entry(mon_entry *);
static void mon_reclaim_entry(mon_entry *);
-/* Rate limiting */
-float rate_limit = 1.0; /* packets per second */
-float kod_limit = 0.1; /* KOD per second - see comments below */
-float decay_time = 20; /* seconds, exponential decay time */
-
/*
* init_mon - initialize monitoring global data
@@ -320,7 +318,7 @@ ntp_monitor(
unsigned short flags
)
{
- l_fp interval_fp;
+ l_fp delta_fp;
mon_entry * mon;
mon_entry * oldest;
int oldest_age;
@@ -350,8 +348,7 @@ ntp_monitor(
if (mon != NULL) {
mon_data.mru_exists++;
- interval_fp = rbufp->recv_time;
- interval_fp -= mon->last;
+ delta_fp = rbufp->recv_time-mon->last;
mon->last = rbufp->recv_time;
NSRCPORT(&mon->rmtadr) = NSRCPORT(&rbufp->recv_srcadr);
mon->count++;
@@ -366,30 +363,22 @@ ntp_monitor(
* if packets arrive at 1/second,
* score will build up to (almost) 1.0
*/
- since_last = ldexpf(interval_fp, -32);
- mon->score *= expf(-since_last/decay_time);
- /* count the ones we drop */
- /* with enough traffic, we drop everything */
- mon->score += 1.0/decay_time;
- if (mon->score < rate_limit) {
+ since_last = ldexpf(delta_fp, -32);
+ mon->score *= expf(-since_last/mon_data.decay_time);
+ mon->score += 1.0/mon_data.decay_time;
+
+ if (mon->score < mon_data.rate_limit) {
/* low score, turn off reject bits */
restrict_mask &= ~(RES_LIMITED | RES_KOD);
}
-
if (RES_LIMITED & restrict_mask)
mon->dropped++;
- if (RES_KOD & restrict_mask) {
- /* We need rate limiting on KoD too.
- * Note that DDoS attackers often send
- * >1000 packets/second. A simple fraction
- * would turn into lots of KoDs.
- * So we try 1/score-squared.
- * kod_limit is roughly packets/second when
- * score is close to 1.
- */
- float rand = random()*1.0/RAND_MAX;
- if (rand > kod_limit/(mon->score*mon->score))
- restrict_mask &= ~RES_KOD;
+
+ /* HACK: Much abusive traffic is big bursts.
+ * Don't send KoDs for them or we can be used
+ * as a DDoS reflector to hide the true source. */
+ if (mon->score > (+mon_data.kod_limit+mon_data.rate_limit)) {
+ restrict_mask &= ~RES_KOD;
}
mon->flags = restrict_mask;
@@ -468,7 +457,7 @@ ntp_monitor(
mon->first = mon->last;
mon->count = 1;
mon->dropped = 0;
- mon->score = 1.0/decay_time;
+ mon->score = 1.0/mon_data.decay_time;
mon->flags = ~(RES_LIMITED | RES_KOD) & flags;
memcpy(&mon->rmtadr, &rbufp->recv_srcadr, sizeof(mon->rmtadr));
mon->vn_mode = VN_MODE(version, mode);
@@ -486,4 +475,55 @@ ntp_monitor(
return mon->flags;
}
+/* This is a hack to sanity check the MRU list
+ * See issue #648 - duplicate ntpq-mrulist slots
+ * I have no suspicions that the list is broken,
+ * but this code is easy to write.
+ *
+ * We may want to do things like log piggy slots.
+ */
+void mon_timer(void) {
+#ifdef DEBUG
+ long int count = 0, hits = 0;
+ l_fp when = 0;
+ mon_entry *mon, *slot;
+
+ for ( mon = TAIL_DLIST(mon_data.mon_mru_list, mru);
+ mon != NULL;
+ mon = PREV_DLIST(mon_data.mon_mru_list, mon, mru)) {
+ count++;
+ /* check if lookup of addr gets this slot */
+ slot = mon_get_slot(&mon->rmtadr);
+ if (mon != slot) {
+ if (10 > hits++) {
+ if (NULL == slot)
+ msyslog(LOG_INFO, "MON: Can't find %ld, %s",
+ count, sockporttoa(&mon->rmtadr));
+ else
+ msyslog(LOG_INFO, "MON: Wrong find %ld, %s",
+ count, sockporttoa(&mon->rmtadr));
+ }
+ }
+ /* check if time stamps are ordered */
+ if (when > mon->last) {
+ if (10 > hits++) {
+ if (NULL == slot)
+ msyslog(LOG_INFO, "MON: backwards %ld, 0x%08x.%08x 0x%08x.%08x %s",
+ count,
+ (unsigned int)lfpuint(mon->last),
+ (unsigned int)lfpfrac(mon->last),
+ (unsigned int)lfpuint(when),
+ (unsigned int)lfpfrac(when),
+ sockporttoa(&mon->rmtadr) );
+ }
+ }
+ when = mon->last;
+ }
+ if (count == (long)mon_data.mru_entries)
+ msyslog(LOG_INFO, "MON: Scanned %ld slots", count);
+ else
+ msyslog(LOG_ERR, "MON: Scan found %ld slots, expected %ld",
+ count, (long)mon_data.mru_entries);
+#endif
+}
=====================================
ntpd/ntp_parser.y
=====================================
@@ -74,7 +74,6 @@
%token <Integer> T_Day
%token <Integer> T_Default
%token <Integer> T_Disable
-%token <Integer> T_Discard
%token <Integer> T_Dispersion
%token <Double> T_Double /* Not a token */
%token <Integer> T_Driftfile
@@ -120,6 +119,7 @@
%token <Integer> T_Mssntp
%token <Integer> T_Leapfile
%token <Integer> T_Leapsmearinterval
+%token <Integer> T_Limit
%token <Integer> T_Limited
%token <Integer> T_Link
%token <Integer> T_Listen
@@ -142,7 +142,6 @@
%token <Integer> T_Minclock
%token <Integer> T_Mindepth
%token <Integer> T_Mindist
-%token <Integer> T_Minimum
%token <Integer> T_Minpoll
%token <Integer> T_Minsane
%token <Integer> T_Mintls
@@ -240,9 +239,9 @@
%type <Integer> client_type
%type <Integer> counter_set_keyword
%type <Int_fifo> counter_set_list
-%type <Attr_val> discard_option
-%type <Integer> discard_option_keyword
-%type <Attr_val_fifo> discard_option_list
+%type <Attr_val> limit_option
+%type <Integer> limit_option_keyword
+%type <Attr_val_fifo> limit_option_list
%type <Integer> enable_disable
%type <Attr_val> filegen_option
%type <Attr_val_fifo> filegen_option_list
@@ -739,9 +738,9 @@ restrict_prefix
;
access_control_command
- : T_Discard discard_option_list
+ : T_Limit limit_option_list
{
- CONCAT_G_FIFOS(cfgt.discard_opts, $2);
+ CONCAT_G_FIFOS(cfgt.limit_opts, $2);
}
| T_Mru mru_option_list
{
@@ -839,28 +838,28 @@ access_control_flag
| T_Version
;
-discard_option_list
- : discard_option_list discard_option
+limit_option_list
+ : limit_option_list limit_option
{
$$ = $1;
APPEND_G_FIFO($$, $2);
}
- | discard_option
+ | limit_option
{
$$ = NULL;
APPEND_G_FIFO($$, $1);
}
;
-discard_option
- : discard_option_keyword T_Integer
- { $$ = create_attr_ival($1, $2); }
+limit_option
+ : limit_option_keyword number
+ { $$ = create_attr_dval($1, $2); }
;
-discard_option_keyword
+limit_option_keyword
: T_Average
- | T_Minimum
- | T_Monitor
+ | T_Burst
+ | T_Kod
;
mru_option_list
=====================================
ntpd/ntp_proto.c
=====================================
@@ -2924,9 +2924,6 @@ proto_config(
sys_maxdist = dvalue;
break;
- case PROTO_CALLDELAY: /* modem call delay (mdelay) */
- break; /* NOT USED */
-
case PROTO_MINCLOCK: /* minimum candidates (minclock) */
sys_minclock = (int)dvalue;
break;
=====================================
ntpd/ntp_timer.c
=====================================
@@ -283,6 +283,7 @@ timer(void)
#ifndef DISABLE_NTS
nts_timer();
#endif
+ mon_timer();
check_logfile();
if (leapf_timer <= current_time) {
leapf_timer += SECSPERDAY;
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/33a554b7e9b7ec8241fd92bd7c0fcddb35e570ce...df67c30eb1de5694280be363a16afc510d3e90d0
--
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/33a554b7e9b7ec8241fd92bd7c0fcddb35e570ce...df67c30eb1de5694280be363a16afc510d3e90d0
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20200420/a43147d4/attachment-0001.htm>
More information about the vc
mailing list