[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