diff --git a/ChangeLog b/ChangeLog
index b22d740c..2163b254 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,6 +45,8 @@ ver. 0.10.3-dev-1 (20??/??/??) - development edition
- avoid banning of legitimate users when pam_unix used in combination with other password method, so
bypass pam_unix failures if accepted available for this user gh-2070;
- amend to gh-1263 with better handling of multiple attempts (failures for different user-names recognized immediatelly);
+ - mode `ddos` (and `aggressive`) extended to catch `Connection closed by ... [preauth]`, so in DDOS mode
+ it counts failure on closing connection within preauth-stage (gh-2085);
* `action.d/badips.py`: implicit convert IPAddr to str, solves an issue "expected string, IPAddr found" (gh-2059);
* `action.d/hostsdeny.conf`: fixed IPv6 syntax (enclosed in square brackets, gh-2066);
* (Free)BSD ipfw actionban fixed to allow same rule added several times (gh-2054);
diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf
index d6f39bc5..60b61241 100644
--- a/config/filter.d/sshd.conf
+++ b/config/filter.d/sshd.conf
@@ -54,23 +54,29 @@ cmnfailre = ^[aA]uthentication (?:failure|error|failed) for .*
^User .+ not allowed because account is locked%(__suff)s
^Disconnecting: Too many authentication failures(?: for .+?)?%(__suff)s$
^Received disconnect from %(__on_port_opt)s:\s*11:
- ^Connection closed by
+ ^Connection closed by -suff-onclosed>
^Accepted \w+ for \S+ from (?:\s|$)
mdre-normal =
+# used to differentiate "connection closed" with and without `[preauth]` (fail/nofail cases in ddos mode)
+mdrp-normal-suff-onclosed =
mdre-ddos = ^Did not receive identification string from
^Connection reset by
+ ^Connection closed by %(__on_port_opt)s\s+\[preauth\]\s*$
^SSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+:
^Read from socket failed: Connection reset by peer
+mdrp-ddos-suff-onclosed = %(__on_port_opt)s\s*$
mdre-extra = ^Received disconnect from %(__on_port_opt)s:\s*14: No supported authentication methods available
^Unable to negotiate with %(__on_port_opt)s: no matching <__alg_match> found.
^Unable to negotiate a <__alg_match>
^no matching <__alg_match> found:
+mdrp-extra-suff-onclosed = %(mdrp-normal-suff-onclosed)s
mdre-aggressive = %(mdre-ddos)s
%(mdre-extra)s
+mdrp-aggressive-suff-onclosed = %(mdrp-ddos-suff-onclosed)s
cfooterre = ^Connection from
diff --git a/fail2ban/tests/files/logs/sshd b/fail2ban/tests/files/logs/sshd
index 28b2f065..21629fb7 100644
--- a/fail2ban/tests/files/logs/sshd
+++ b/fail2ban/tests/files/logs/sshd
@@ -120,7 +120,7 @@ Sep 29 16:28:02 spaceman sshd[16699]: Failed password for dan from 127.0.0.1 por
# failJSON: { "match": false, "desc": "no failure, just cache mlfid (conn-id)" }
Sep 29 16:28:05 localhost sshd[16700]: Connection from 192.0.2.5
# failJSON: { "match": false, "desc": "no failure, just covering mlfid (conn-id) forget" }
-Sep 29 16:28:05 localhost sshd[16700]: Connection closed by 192.0.2.5 [preauth]
+Sep 29 16:28:05 localhost sshd[16700]: Connection closed by 192.0.2.5
# failJSON: { "time": "2004-09-29T17:15:02", "match": true , "host": "127.0.0.1" }
Sep 29 17:15:02 spaceman sshd[12946]: Failed hostbased for dan from 127.0.0.1 port 45785 ssh2: RSA 8c:e3:aa:0f:64:51:02:f7:14:79:89:3f:65:84:7c:30, client user "dan", client host "localhost.localdomain"
@@ -159,7 +159,7 @@ Nov 28 09:16:03 srv sshd[32307]: Postponed publickey for git from 192.0.2.1 port
# failJSON: { "match": false }
Nov 28 09:16:03 srv sshd[32307]: Accepted publickey for git from 192.0.2.1 port 57904 ssh2: DSA 36:48:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
# failJSON: { "match": false, "desc": "Should be forgotten by success/accepted public key" }
-Nov 28 09:16:03 srv sshd[32307]: Connection closed by 192.0.2.1 [preauth]
+Nov 28 09:16:03 srv sshd[32307]: Connection closed by 192.0.2.1
# Failure on connect with valid user-name but wrong public keys (retarded to disconnect/too many errors, because of gh-1263):
# failJSON: { "match": false }
@@ -179,7 +179,7 @@ Nov 23 21:50:37 sshd[8148]: Connection closed by 61.0.0.1 [preauth]
# failJSON: { "match": false }
Nov 23 21:50:19 sshd[9148]: Disconnecting: Too many authentication failures for root [preauth]
# failJSON: { "match": false , "desc": "Pids don't match" }
-Nov 23 21:50:37 sshd[7148]: Connection closed by 61.0.0.1 [preauth]
+Nov 23 21:50:37 sshd[7148]: Connection closed by 61.0.0.1
# failJSON: { "time": "2005-07-13T18:44:28", "match": true , "host": "89.24.13.192", "desc": "from gh-289" }
Jul 13 18:44:28 mdop sshd[4931]: Received disconnect from 89.24.13.192: 3: com.jcraft.jsch.JSchException: Auth fail
@@ -216,7 +216,7 @@ Apr 27 13:02:04 host sshd[29116]: Received disconnect from 1.2.3.4: 11: Normal S
# failJSON: { "match": false, "desc": "No failure until closed or another fail (e. g. F-MLFFORGET by success/accepted password can avoid failure, see gh-2070)" }
2015-04-16T18:02:50.321974+00:00 host sshd[2716]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.0.2.112 user=root
# failJSON: { "time": "2015-04-16T20:02:50", "match": true , "host": "192.0.2.112", "desc": "Should catch failure - no success/no accepted password" }
-2015-04-16T18:02:50.568798+00:00 host sshd[2716]: Connection closed by 192.0.2.112
+2015-04-16T18:02:50.568798+00:00 host sshd[2716]: Connection closed by 192.0.2.112 [preauth]
# disable this test-cases block for obsolete multi-line filter (zzz-sshd-obsolete...):
# filterOptions: [{"test.condition":"name=='sshd'"}]
@@ -283,6 +283,14 @@ Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection res
# failJSON: { "time": "2005-03-15T09:20:57", "match": true , "host": "192.0.2.39", "desc": "Singleline for connection reset by" }
Mar 15 09:20:57 host sshd[28972]: Connection reset by 192.0.2.39 port 14282 [preauth]
+# filterOptions: [{"test.condition":"name=='sshd'", "mode": "ddos"}, {"test.condition":"name=='sshd'", "mode": "aggressive"}]
+
+# failJSON: { "time": "2005-03-15T09:21:01", "match": true , "host": "192.0.2.212", "desc": "DDOS mode causes failure on close within preauth stage" }
+Mar 15 09:21:01 host sshd[2717]: Connection closed by 192.0.2.212 [preauth]
+# failJSON: { "time": "2005-03-15T09:21:02", "match": true , "host": "192.0.2.212", "desc": "DDOS mode causes failure on close within preauth stage" }
+Mar 15 09:21:02 host sshd[2717]: Connection closed by 192.0.2.212 [preauth]
+
+
# filterOptions: [{"mode": "extra"}, {"mode": "aggressive"}]