[openssh-commits] [openssh] 02/03: upstream: convert PerSourcePenalties to using floating point time,

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Dec 5 19:19:49 AEDT 2025


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit c48de35bea389308428cb47b5ee55b1b1fb4567c
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Fri Dec 5 07:49:45 2025 +0000

    upstream: convert PerSourcePenalties to using floating point time,
    
    allowing penalties to be less than a second. This is useful if you need to
    penalise things you expect to occur at >=1 QPS.
    
    feedback dtucker / deraadt; ok deraadt@
    
    OpenBSD-Commit-ID: 89198be755722131b45a52d22d548e4c602201f0
---
 servconf.c | 92 +++++++++++++++++++++++++++++++++++---------------------------
 servconf.h | 16 +++++------
 srclimit.c | 36 +++++++++++++-----------
 3 files changed, 80 insertions(+), 64 deletions(-)

diff --git a/servconf.c b/servconf.c
index 6cdfb3cb6..e1e84db84 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.c,v 1.437 2025/11/25 00:52:00 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.438 2025/12/05 07:49:45 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -173,13 +173,13 @@ initialize_server_options(ServerOptions *options)
 	options->per_source_penalty.max_sources6 = -1;
 	options->per_source_penalty.overflow_mode = -1;
 	options->per_source_penalty.overflow_mode6 = -1;
-	options->per_source_penalty.penalty_crash = -1;
-	options->per_source_penalty.penalty_authfail = -1;
-	options->per_source_penalty.penalty_noauth = -1;
-	options->per_source_penalty.penalty_grace = -1;
-	options->per_source_penalty.penalty_refuseconnection = -1;
-	options->per_source_penalty.penalty_max = -1;
-	options->per_source_penalty.penalty_min = -1;
+	options->per_source_penalty.penalty_crash = -1.0;
+	options->per_source_penalty.penalty_authfail = -1.0;
+	options->per_source_penalty.penalty_noauth = -1.0;
+	options->per_source_penalty.penalty_grace = -1.0;
+	options->per_source_penalty.penalty_refuseconnection = -1.0;
+	options->per_source_penalty.penalty_max = -1.0;
+	options->per_source_penalty.penalty_min = -1.0;
 	options->max_authtries = -1;
 	options->max_sessions = -1;
 	options->banner = NULL;
@@ -429,20 +429,20 @@ fill_default_server_options(ServerOptions *options)
 		options->per_source_penalty.overflow_mode = PER_SOURCE_PENALTY_OVERFLOW_PERMISSIVE;
 	if (options->per_source_penalty.overflow_mode6 == -1)
 		options->per_source_penalty.overflow_mode6 = options->per_source_penalty.overflow_mode;
-	if (options->per_source_penalty.penalty_crash == -1)
-		options->per_source_penalty.penalty_crash = 90;
-	if (options->per_source_penalty.penalty_grace == -1)
-		options->per_source_penalty.penalty_grace = 10;
-	if (options->per_source_penalty.penalty_authfail == -1)
-		options->per_source_penalty.penalty_authfail = 5;
-	if (options->per_source_penalty.penalty_noauth == -1)
-		options->per_source_penalty.penalty_noauth = 1;
-	if (options->per_source_penalty.penalty_refuseconnection == -1)
-		options->per_source_penalty.penalty_refuseconnection = 10;
-	if (options->per_source_penalty.penalty_min == -1)
-		options->per_source_penalty.penalty_min = 15;
-	if (options->per_source_penalty.penalty_max == -1)
-		options->per_source_penalty.penalty_max = 600;
+	if (options->per_source_penalty.penalty_crash < 0.0)
+		options->per_source_penalty.penalty_crash = 90.0;
+	if (options->per_source_penalty.penalty_grace < 0.0)
+		options->per_source_penalty.penalty_grace = 10.0;
+	if (options->per_source_penalty.penalty_authfail < 0.0)
+		options->per_source_penalty.penalty_authfail = 5.0;
+	if (options->per_source_penalty.penalty_noauth < 0.0)
+		options->per_source_penalty.penalty_noauth = 1.0;
+	if (options->per_source_penalty.penalty_refuseconnection < 0.0)
+		options->per_source_penalty.penalty_refuseconnection = 10.0;
+	if (options->per_source_penalty.penalty_min < 0.0)
+		options->per_source_penalty.penalty_min = 15.0;
+	if (options->per_source_penalty.penalty_max < 0.0)
+		options->per_source_penalty.penalty_max = 600.0;
 	if (options->max_authtries == -1)
 		options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
 	if (options->max_sessions == -1)
@@ -1315,6 +1315,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 {
 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
 	int cmdline = 0, *intptr, value, value2, value3, n, port, oactive, r;
+	double dvalue, *doubleptr = NULL;
 	int ca_only = 0, found = 0;
 	SyslogFacility *log_facility_ptr;
 	LogLevel *log_level_ptr;
@@ -2085,6 +2086,8 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 			const char *q = NULL;
 
 			found = 1;
+			intptr = NULL;
+			doubleptr = NULL;
 			value = -1;
 			value2 = 0;
 			/* Allow no/yes only in first position */
@@ -2100,19 +2103,19 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 					options->per_source_penalty.enabled = value2;
 				continue;
 			} else if ((q = strprefix(arg, "crash:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_crash;
+				doubleptr = &options->per_source_penalty.penalty_crash;
 			} else if ((q = strprefix(arg, "authfail:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_authfail;
+				doubleptr = &options->per_source_penalty.penalty_authfail;
 			} else if ((q = strprefix(arg, "noauth:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_noauth;
+				doubleptr = &options->per_source_penalty.penalty_noauth;
 			} else if ((q = strprefix(arg, "grace-exceeded:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_grace;
+				doubleptr = &options->per_source_penalty.penalty_grace;
 			} else if ((q = strprefix(arg, "refuseconnection:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_refuseconnection;
+				doubleptr = &options->per_source_penalty.penalty_refuseconnection;
 			} else if ((q = strprefix(arg, "max:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_max;
+				doubleptr = &options->per_source_penalty.penalty_max;
 			} else if ((q = strprefix(arg, "min:", 0)) != NULL) {
-				intptr = &options->per_source_penalty.penalty_min;
+				doubleptr = &options->per_source_penalty.penalty_min;
 			} else if ((q = strprefix(arg, "max-sources4:", 0)) != NULL) {
 				intptr = &options->per_source_penalty.max_sources4;
 				if ((errstr = atoi_err(q, &value)) != NULL)
@@ -2139,15 +2142,24 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 				fatal("%s line %d: unsupported %s keyword %s",
 				    filename, linenum, keyword, arg);
 			}
-			/* If no value was parsed above, assume it's a time */
-			if (value == -1 && (value = convtime(q)) == -1) {
-				fatal("%s line %d: invalid %s time value.",
-				    filename, linenum, keyword);
-			}
-			if (*activep && *intptr == -1) {
-				*intptr = value;
-				/* any option implicitly enables penalties */
-				options->per_source_penalty.enabled = 1;
+
+			if (doubleptr != NULL) {
+				if ((dvalue = convtime_double(q)) < 0) {
+					fatal("%s line %d: invalid %s time value.",
+					    filename, linenum, keyword);
+				}
+				if (*activep && *doubleptr < 0.0) {
+					*doubleptr = dvalue;
+					options->per_source_penalty.enabled = 1;
+				}
+			} else if (intptr != NULL) {
+				if (*activep && *intptr == -1) {
+					*intptr = value;
+					options->per_source_penalty.enabled = 1;
+				}
+			} else {
+				fatal_f("%s line %d: internal error",
+				    filename, linenum);
 			}
 		}
 		if (!found) {
@@ -3407,8 +3419,8 @@ dump_config(ServerOptions *o)
 	printf("\n");
 
 	if (o->per_source_penalty.enabled) {
-		printf("persourcepenalties crash:%d authfail:%d noauth:%d "
-		    "grace-exceeded:%d refuseconnection:%d max:%d min:%d "
+		printf("persourcepenalties crash:%f authfail:%f noauth:%f "
+		    "grace-exceeded:%f refuseconnection:%f max:%f min:%f "
 		    "max-sources4:%d max-sources6:%d "
 		    "overflow:%s overflow6:%s\n",
 		    o->per_source_penalty.penalty_crash,
diff --git a/servconf.h b/servconf.h
index 9beb90fae..885d102fc 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.168 2024/09/15 01:18:26 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.170 2025/12/05 07:49:45 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -73,13 +73,13 @@ struct per_source_penalty {
 	int	max_sources6;
 	int	overflow_mode;
 	int	overflow_mode6;
-	int	penalty_crash;
-	int	penalty_grace;
-	int	penalty_authfail;
-	int	penalty_noauth;
-	int	penalty_refuseconnection;
-	int	penalty_max;
-	int	penalty_min;
+	double	penalty_crash;
+	double	penalty_grace;
+	double	penalty_authfail;
+	double	penalty_noauth;
+	double	penalty_refuseconnection;
+	double	penalty_max;
+	double	penalty_min;
 };
 
 typedef struct {
diff --git a/srclimit.c b/srclimit.c
index c62763724..c6a553beb 100644
--- a/srclimit.c
+++ b/srclimit.c
@@ -53,7 +53,7 @@ static struct child_info {
  */
 struct penalty {
 	struct xaddr addr;
-	time_t expiry;
+	double expiry;
 	int active;
 	const char *reason;
 	RB_ENTRY(penalty) by_addr;
@@ -212,7 +212,7 @@ penalty_expiry_cmp(struct penalty *a, struct penalty *b)
 }
 
 static void
-expire_penalties_from_tree(time_t now, const char *t,
+expire_penalties_from_tree(double now, const char *t,
     struct penalties_by_expiry *by_expiry,
     struct penalties_by_addr *by_addr, size_t *npenaltiesp)
 {
@@ -234,7 +234,7 @@ expire_penalties_from_tree(time_t now, const char *t,
 }
 
 static void
-expire_penalties(time_t now)
+expire_penalties(double now)
 {
 	expire_penalties_from_tree(now, "ipv4",
 	    &penalties_by_expiry4, &penalties_by_addr4, &npenalties4);
@@ -260,7 +260,7 @@ srclimit_penalty_check_allow(int sock, const char **reason)
 {
 	struct xaddr addr;
 	struct penalty find, *penalty;
-	time_t now;
+	double now;
 	int bits, max_sources, overflow_mode;
 	char addr_s[NI_MAXHOST];
 	struct penalties_by_addr *by_addr;
@@ -277,7 +277,7 @@ srclimit_penalty_check_allow(int sock, const char **reason)
 			return 1;
 		}
 	}
-	now = monotime();
+	now = monotime_double();
 	expire_penalties(now);
 	by_addr = addr.af == AF_INET ?
 	    &penalties_by_addr4 : &penalties_by_addr6;
@@ -347,8 +347,9 @@ srclimit_penalise(struct xaddr *addr, int penalty_type)
 {
 	struct xaddr masked;
 	struct penalty *penalty = NULL, *existing = NULL;
-	time_t now;
-	int bits, penalty_secs, max_sources = 0, overflow_mode;
+	double now;
+	int bits, max_sources = 0, overflow_mode;
+	double penalty_secs;
 	char addrnetmask[NI_MAXHOST + 4];
 	const char *reason = NULL, *t;
 	size_t *npenaltiesp = NULL;
@@ -392,12 +393,16 @@ srclimit_penalise(struct xaddr *addr, int penalty_type)
 	default:
 		fatal_f("internal error: unknown penalty %d", penalty_type);
 	}
+
+	if (penalty_secs <= 0)
+		return;
+
 	bits = addr->af == AF_INET ? ipv4_masklen : ipv6_masklen;
 	if (srclimit_mask_addr(addr, bits, &masked) != 0)
 		return;
 	addr_masklen_ntop(addr, bits, addrnetmask, sizeof(addrnetmask));
 
-	now = monotime();
+	now = monotime_double();
 	expire_penalties(now);
 	by_expiry = addr->af == AF_INET ?
 	    &penalties_by_expiry4 : &penalties_by_expiry6;
@@ -429,7 +434,7 @@ srclimit_penalise(struct xaddr *addr, int penalty_type)
 			fatal_f("internal error: %s penalty tables corrupt", t);
 		do_log2_f(penalty->active ?
 		    SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE,
-		    "%s: new %s %s penalty of %d seconds for %s", t,
+		    "%s: new %s %s penalty of %f seconds for %s", t,
 		    addrnetmask, penalty->active ? "active" : "deferred",
 		    penalty_secs, reason);
 		if (++(*npenaltiesp) > (size_t)max_sources)
@@ -448,9 +453,8 @@ srclimit_penalise(struct xaddr *addr, int penalty_type)
 		existing->expiry = now + penalty_cfg.penalty_max;
 	if (existing->expiry - now > penalty_cfg.penalty_min &&
 	    !existing->active) {
-		logit_f("%s: activating %s penalty of %lld seconds for %s",
-		    addrnetmask, t, (long long)(existing->expiry - now),
-		    reason);
+		logit_f("%s: activating %s penalty of %.3f seconds for %s",
+		    addrnetmask, t, existing->expiry - now, reason);
 		existing->active = 1;
 	}
 	existing->reason = penalty->reason;
@@ -468,9 +472,9 @@ srclimit_penalty_info_for_tree(const char *t,
 	struct penalty *p = NULL;
 	int bits;
 	char s[NI_MAXHOST + 4];
-	time_t now;
+	double now;
 
-	now = monotime();
+	now = monotime_double();
 	logit("%zu active %s penalties", npenalties, t);
 	RB_FOREACH(p, penalties_by_expiry, by_expiry) {
 		bits = p->addr.af == AF_INET ? ipv4_masklen : ipv6_masklen;
@@ -478,8 +482,8 @@ srclimit_penalty_info_for_tree(const char *t,
 		if (p->expiry < now)
 			logit("client %s %s (expired)", s, p->reason);
 		else {
-			logit("client %s %s (%llu secs left)", s, p->reason,
-			   (long long)(p->expiry - now));
+			logit("client %s %s (%.3f secs left)", s, p->reason,
+			   p->expiry - now);
 		}
 	}
 }

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list