Keep wrong join-code streak when a correct code is tried (#1174)

Fixes #1088

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-24 05:25:17 -04:00
committed by GitHub
co-authored by Claude Haiku 5.5
parent 7bc594632d
commit 8ab0de2690
2 changed files with 15 additions and 11 deletions
+3 -3
View File
@@ -120,15 +120,15 @@ impl Abuse {
open
}
/// `ip` tried a join code that was right (`ok`) or wrong: a right one forgives the wrong ones
/// before it; enough wrong ones in a row lock the address out.
/// `ip` tried a join code that was right (`ok`) or wrong: a right one doesn't forgive the wrong
/// ones before it (they only decay with time); enough wrong ones lock the address out.
pub fn code_tried(&mut self, ip: IpAddr, ok: bool, now: Instant) {
if !ok {
self.wrong_codes.take(now);
}
for (k, times) in ip_blocks(ip) {
let a = self.address(k, f64::from(times), now);
if ok || now.saturating_duration_since(a.wrong_at) > CODE_LOCKOUT {
if now.saturating_duration_since(a.wrong_at) > CODE_LOCKOUT {
a.wrong = 0;
}
if !ok {
+12 -8
View File
@@ -262,17 +262,21 @@ fn the_limits_on_codes_over_time() {
let t0 = Instant::now();
let me = ip("198.51.100.9");
let mut abuse = Abuse::new(AbuseConfig { open: false, connects_per_minute: 30, publishes_per_hour: 10, messages_per_second: 200 });
// A right code forgives the wrong ones before it.
// A right code, even from a neighbour in the same /64, doesn't forgive the wrong ones.
let a = ip("2001:db8:1:2::1");
let b = ip("2001:db8:1:2::2");
for _ in 0..WRONG_CODES - 1 {
abuse.code_tried(a, false, t0);
}
abuse.code_tried(b, true, t0);
abuse.code_tried(a, true, t0);
assert_eq!(abuse.code_locked(a, t0), None);
abuse.code_tried(a, false, t0);
assert_eq!(abuse.code_locked(a, t0), Some(CODE_LOCKOUT));
// Wrong codes: locked for the lockout, then free again.
for _ in 0..WRONG_CODES {
abuse.code_tried(me, false, t0);
}
abuse.code_tried(me, true, t0);
for _ in 0..WRONG_CODES - 1 {
abuse.code_tried(me, false, t0);
}
assert_eq!(abuse.code_locked(me, t0), None);
// One more: locked for the lockout, then free again.
abuse.code_tried(me, false, t0);
assert_eq!(abuse.code_locked(me, t0), Some(CODE_LOCKOUT));
assert!(abuse.code_locked(me, t0 + CODE_LOCKOUT - Duration::from_secs(1)).is_some());
assert_eq!(abuse.code_locked(me, t0 + CODE_LOCKOUT), None);