diff --git a/assets/parser_fixture_matrix_journalctl_short_full.log b/assets/parser_fixture_matrix_journalctl_short_full.log index c007c83..4c1670d 100644 --- a/assets/parser_fixture_matrix_journalctl_short_full.log +++ b/assets/parser_fixture_matrix_journalctl_short_full.log @@ -20,6 +20,7 @@ Tue 2026-03-10 09:03:39 UTC example-host sshd[3022]: Illegal user legacy-backup Tue 2026-03-10 09:03:40 UTC example-host sshd[3003]: Connection closed by user alice 203.0.113.50 port 52010 [preauth] Tue 2026-03-10 09:04:05 UTC example-host sshd[3004]: Connection closed by authenticating user carol 203.0.113.51 port 52011 [preauth] Tue 2026-03-10 09:04:28 UTC example-host sshd[3005]: Connection closed by invalid user deploy 203.0.113.52 port 52012 [preauth] +Tue 2026-03-10 09:04:36 UTC example-host sshd[3024]: Connection reset by invalid user deploy 203.0.113.58 port 52020 [preauth] Tue 2026-03-10 09:05:02 UTC example-host sshd[3006]: Disconnected from authenticating user dave 203.0.113.53 port 52013 [preauth] Tue 2026-03-10 09:05:34 UTC example-host sshd[3007]: Timeout, client not responding from 203.0.113.54 port 52014 Tue 2026-03-10 09:05:46 UTC example-host sshd[3010]: Received disconnect from 203.0.113.55 port 52015:11: disconnected by user diff --git a/assets/parser_fixture_matrix_syslog.log b/assets/parser_fixture_matrix_syslog.log index 9cfe3da..254de92 100644 --- a/assets/parser_fixture_matrix_syslog.log +++ b/assets/parser_fixture_matrix_syslog.log @@ -20,6 +20,7 @@ Mar 10 09:03:39 example-host sshd[2022]: Illegal user legacy-backup from 203.0.1 Mar 10 09:03:40 example-host sshd[2003]: Connection closed by user alice 203.0.113.50 port 52010 [preauth] Mar 10 09:04:05 example-host sshd[2004]: Connection closed by authenticating user carol 203.0.113.51 port 52011 [preauth] Mar 10 09:04:28 example-host sshd[2005]: Connection closed by invalid user deploy 203.0.113.52 port 52012 [preauth] +Mar 10 09:04:36 example-host sshd[2024]: Connection reset by invalid user deploy 203.0.113.58 port 52020 [preauth] Mar 10 09:05:02 example-host sshd[2006]: Disconnected from authenticating user dave 203.0.113.53 port 52013 [preauth] Mar 10 09:05:34 example-host sshd[2007]: Timeout, client not responding from 203.0.113.54 port 52014 Mar 10 09:05:46 example-host sshd[2010]: Received disconnect from 203.0.113.55 port 52015:11: disconnected by user diff --git a/src/parser.cpp b/src/parser.cpp index 8a55b71..cf61a25 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -663,7 +663,8 @@ std::string classify_unknown_pam_sss_pattern(std::string_view message) { std::string classify_unknown_auth_pattern(const Event& event) { const auto message = std::string_view{event.message}; if (event.program == "sshd") { - if ((message.starts_with("Connection closed by ") || message.starts_with("Connection closed by authenticating user ")) + if ((message.starts_with("Connection closed by ") || message.starts_with("Connection closed by authenticating user ") + || message.starts_with("Connection reset by ")) && message.find("[preauth]") != std::string_view::npos) { return "sshd_connection_closed_preauth"; } diff --git a/tests/test_parser.cpp b/tests/test_parser.cpp index b7aa91a..f6decfa 100644 --- a/tests/test_parser.cpp +++ b/tests/test_parser.cpp @@ -548,19 +548,20 @@ void test_unknown_auth_patterns_are_warnings_only() { "Mar 10 08:11:22 example-host sshd[1234]: Failed password for root from 203.0.113.10 port 51022 ssh2\n" "Mar 10 08:12:05 example-host sshd[1235]: Failed publickey for invalid user svc-backup from 203.0.113.10 port 51030 ssh2\n" "Mar 10 08:13:10 example-host sshd[1236]: Connection closed by authenticating user alice 203.0.113.50 port 51290 [preauth]\n" + "Mar 10 08:13:40 example-host sshd[1238]: Connection reset by invalid user deploy 203.0.113.52 port 51292 [preauth]\n" "Mar 10 08:14:44 example-host sshd[1237]: Timeout, client not responding from 203.0.113.51 port 51291\n"); const auto result = parser.parse_stream(input); expect(result.events.size() == 2, "expected only recognized lines to become events"); - expect(result.warnings.size() == 2, "expected unknown auth patterns to become warnings"); - expect(result.quality.total_lines == 4, "expected total analyzed line count"); + expect(result.warnings.size() == 3, "expected unknown auth patterns to become warnings"); + expect(result.quality.total_lines == 5, "expected total analyzed line count"); expect(result.quality.parsed_lines == 2, "expected parsed line count"); - expect(result.quality.unparsed_lines == 2, "expected unparsed line count"); - expect(result.quality.parse_success_rate == 0.5, "expected parse success rate"); + expect(result.quality.unparsed_lines == 3, "expected unparsed line count"); + expect(result.quality.parse_success_rate == 0.4, "expected parse success rate"); expect(result.quality.top_unknown_patterns.size() == 2, "expected two unknown pattern buckets"); expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", - "expected preauth connection close pattern"); - expect(result.quality.top_unknown_patterns[0].count == 1, "expected preauth connection close count"); + "expected preauth connection close/reset pattern"); + expect(result.quality.top_unknown_patterns[0].count == 2, "expected preauth connection close/reset count"); expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", "expected timeout/disconnection pattern"); expect(result.quality.top_unknown_patterns[1].count == 1, "expected timeout/disconnection count"); @@ -646,11 +647,11 @@ void test_syslog_fixture_matrix_file() { const auto result = parser.parse_file(asset_path("parser_fixture_matrix_syslog.log")); expect(result.events.size() == 20, "expected twenty recognized syslog fixture events"); - expect(result.warnings.size() == 8, "expected eight syslog fixture warnings"); - expect(result.quality.total_lines == 28, "expected twenty-eight syslog fixture lines"); + expect(result.warnings.size() == 9, "expected nine syslog fixture warnings"); + expect(result.quality.total_lines == 29, "expected twenty-nine syslog fixture lines"); expect(result.quality.parsed_lines == 20, "expected twenty parsed syslog fixture lines"); - expect(result.quality.unparsed_lines == 8, "expected eight unparsed syslog fixture lines"); - expect_close(result.quality.parse_success_rate, 20.0 / 28.0, 1e-9, "expected syslog fixture parse success rate"); + expect(result.quality.unparsed_lines == 9, "expected nine unparsed syslog fixture lines"); + expect_close(result.quality.parse_success_rate, 20.0 / 29.0, 1e-9, "expected syslog fixture parse success rate"); expect(result.events[0].event_type == loglens::EventType::SshInvalidUser, "expected invalid-user failed password"); expect(result.events[1].event_type == loglens::EventType::SshFailedPublicKey, "expected failed publickey variant"); @@ -705,7 +706,7 @@ void test_syslog_fixture_matrix_file() { expect(result.quality.top_unknown_patterns.size() == 4, "expected four unknown syslog buckets"); expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", "expected preauth connection-close syslog bucket"); - expect(result.quality.top_unknown_patterns[0].count == 3, "expected three preauth connection-close syslog lines"); + expect(result.quality.top_unknown_patterns[0].count == 4, "expected four preauth connection-close/reset syslog lines"); expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", "expected timeout/disconnection syslog bucket"); expect(result.quality.top_unknown_patterns[1].count == 3, "expected three timeout/disconnection syslog lines"); @@ -724,11 +725,11 @@ void test_journalctl_fixture_matrix_file() { const auto result = parser.parse_file(asset_path("parser_fixture_matrix_journalctl_short_full.log")); expect(result.events.size() == 20, "expected twenty recognized journalctl fixture events"); - expect(result.warnings.size() == 8, "expected eight journalctl fixture warnings"); - expect(result.quality.total_lines == 28, "expected twenty-eight journalctl fixture lines"); + expect(result.warnings.size() == 9, "expected nine journalctl fixture warnings"); + expect(result.quality.total_lines == 29, "expected twenty-nine journalctl fixture lines"); expect(result.quality.parsed_lines == 20, "expected twenty parsed journalctl fixture lines"); - expect(result.quality.unparsed_lines == 8, "expected eight unparsed journalctl fixture lines"); - expect_close(result.quality.parse_success_rate, 20.0 / 28.0, 1e-9, "expected journalctl fixture parse success rate"); + expect(result.quality.unparsed_lines == 9, "expected nine unparsed journalctl fixture lines"); + expect_close(result.quality.parse_success_rate, 20.0 / 29.0, 1e-9, "expected journalctl fixture parse success rate"); expect(result.events[0].event_type == loglens::EventType::SshInvalidUser, "expected journalctl invalid-user failed password"); expect(result.events[1].event_type == loglens::EventType::SshFailedPublicKey, "expected journalctl failed publickey variant"); @@ -773,7 +774,7 @@ void test_journalctl_fixture_matrix_file() { expect(result.quality.top_unknown_patterns.size() == 4, "expected four unknown journalctl buckets"); expect(result.quality.top_unknown_patterns[0].pattern == "sshd_connection_closed_preauth", "expected preauth connection-close journalctl bucket"); - expect(result.quality.top_unknown_patterns[0].count == 3, "expected three preauth connection-close journalctl lines"); + expect(result.quality.top_unknown_patterns[0].count == 4, "expected four preauth connection-close/reset journalctl lines"); expect(result.quality.top_unknown_patterns[1].pattern == "sshd_timeout_or_disconnection", "expected timeout/disconnection journalctl bucket"); expect(result.quality.top_unknown_patterns[1].count == 3, "expected three timeout/disconnection journalctl lines");