From c880c825798ef65d40dc6b43fb4c97f6ef1debe0 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 12 May 2026 12:01:32 +0200 Subject: [PATCH 1/3] feat: add PumbaLP/adguardhome-dot collection for DoT scanner detection Parser: PumbaLP/adguardhome-dot-errors - Extracts remote IP from AdGuard Home DoT connection reset errors - Detects port 853 scanners that fail TLS handshake Scenario: PumbaLP/adguardhome-dot-scan - Bans after 5 resets within 10 minutes from same IP - Tested against AdGuard Home v0.107.x in production Closes: #1753 --- .../adguardhome-dot-errors.log | 6 +++ .tests/adguardhome-dot-errors/config.yaml | 7 +++ .tests/adguardhome-dot-errors/parser.assert | 4 ++ .tests/adguardhome-dot-errors/scenario.assert | 1 + .../adguardhome-dot-scan.log | 6 +++ .tests/adguardhome-dot-scan/config.yaml | 7 +++ .tests/adguardhome-dot-scan/parser.assert | 50 +++++++++++++++++++ .tests/adguardhome-dot-scan/scenario.assert | 1 + collections/PumbaLP/adguardhome-dot.yaml | 6 +++ .../PumbaLP/adguardhome-dot-errors.md | 32 ++++++++++++ .../PumbaLP/adguardhome-dot-errors.yaml | 36 +++++++++++++ scenarios/PumbaLP/adguardhome-dot-scan.md | 23 +++++++++ scenarios/PumbaLP/adguardhome-dot-scan.yaml | 25 ++++++++++ 13 files changed, 204 insertions(+) create mode 100644 .tests/adguardhome-dot-errors/adguardhome-dot-errors.log create mode 100644 .tests/adguardhome-dot-errors/config.yaml create mode 100644 .tests/adguardhome-dot-errors/parser.assert create mode 100644 .tests/adguardhome-dot-errors/scenario.assert create mode 100644 .tests/adguardhome-dot-scan/adguardhome-dot-scan.log create mode 100644 .tests/adguardhome-dot-scan/config.yaml create mode 100644 .tests/adguardhome-dot-scan/parser.assert create mode 100644 .tests/adguardhome-dot-scan/scenario.assert create mode 100644 collections/PumbaLP/adguardhome-dot.yaml create mode 100644 parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md create mode 100644 parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml create mode 100644 scenarios/PumbaLP/adguardhome-dot-scan.md create mode 100644 scenarios/PumbaLP/adguardhome-dot-scan.yaml diff --git a/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log b/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log new file mode 100644 index 00000000000..607e7df60c0 --- /dev/null +++ b/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log @@ -0,0 +1,6 @@ +2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59208: read: connection reset by peer" +2026/04/04 20:41:42.123456 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59209: read: connection reset by peer" +2026/04/04 20:41:43.234567 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59210: read: connection reset by peer" +2026/04/04 20:41:44.345678 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59211: read: connection reset by peer" +2026/04/04 20:41:45.456789 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59212: read: connection reset by peer" +2026/04/04 20:41:46.567890 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59213: read: connection reset by peer" diff --git a/.tests/adguardhome-dot-errors/config.yaml b/.tests/adguardhome-dot-errors/config.yaml new file mode 100644 index 00000000000..3e05f1cbc2f --- /dev/null +++ b/.tests/adguardhome-dot-errors/config.yaml @@ -0,0 +1,7 @@ +parsers: + - ./parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml +scenarios: + - ./scenarios/PumbaLP/adguardhome-dot-scan.yaml +postoverflows: [] +log_file: adguardhome-dot-errors.log +log_type: adguardhome diff --git a/.tests/adguardhome-dot-errors/parser.assert b/.tests/adguardhome-dot-errors/parser.assert new file mode 100644 index 00000000000..8dbbb9da221 --- /dev/null +++ b/.tests/adguardhome-dot-errors/parser.assert @@ -0,0 +1,4 @@ +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["source_ip"] == "85.217.140.42" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["log_type"] == "dot_connection_reset" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["service"] == "adguardhome_dot" diff --git a/.tests/adguardhome-dot-errors/scenario.assert b/.tests/adguardhome-dot-errors/scenario.assert new file mode 100644 index 00000000000..03455618a29 --- /dev/null +++ b/.tests/adguardhome-dot-errors/scenario.assert @@ -0,0 +1 @@ +len(results) == 0 diff --git a/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log b/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log new file mode 100644 index 00000000000..16f4d3f8414 --- /dev/null +++ b/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log @@ -0,0 +1,6 @@ +2026/04/04 20:41:41.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59201: read: connection reset by peer" +2026/04/04 20:41:42.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59202: read: connection reset by peer" +2026/04/04 20:41:43.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59203: read: connection reset by peer" +2026/04/04 20:41:44.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59204: read: connection reset by peer" +2026/04/04 20:41:45.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59205: read: connection reset by peer" +2026/04/04 20:41:46.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59206: read: connection reset by peer" diff --git a/.tests/adguardhome-dot-scan/config.yaml b/.tests/adguardhome-dot-scan/config.yaml new file mode 100644 index 00000000000..ddae4ce860c --- /dev/null +++ b/.tests/adguardhome-dot-scan/config.yaml @@ -0,0 +1,7 @@ +parsers: + - ./parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml +scenarios: + - ./scenarios/PumbaLP/adguardhome-dot-scan.yaml +postoverflows: [] +log_file: adguardhome-dot-scan.log +log_type: adguardhome diff --git a/.tests/adguardhome-dot-scan/parser.assert b/.tests/adguardhome-dot-scan/parser.assert new file mode 100644 index 00000000000..37ab142a6e3 --- /dev/null +++ b/.tests/adguardhome-dot-scan/parser.assert @@ -0,0 +1,50 @@ +len(results["s01-parse"]["PumbaLP/adguardhome-dot-errors"]) == 6 +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["day"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["month"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["remote_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["time"] == "20:41:41.000000" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["year"] == "2026" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["log_type"] == "dot_connection_reset" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["service"] == "adguardhome_dot" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["source_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Whitelisted == false +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["day"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["month"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["remote_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["time"] == "20:41:42.000000" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["year"] == "2026" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Meta["log_type"] == "dot_connection_reset" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Meta["service"] == "adguardhome_dot" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Meta["source_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Whitelisted == false +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["day"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["month"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["remote_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["time"] == "20:41:43.000000" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["year"] == "2026" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Meta["log_type"] == "dot_connection_reset" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Meta["service"] == "adguardhome_dot" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Meta["source_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Whitelisted == false +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["day"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["month"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["remote_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["time"] == "20:41:44.000000" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["year"] == "2026" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Meta["log_type"] == "dot_connection_reset" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Meta["service"] == "adguardhome_dot" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Meta["source_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Whitelisted == false +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["day"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["month"] == "04" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["remote_ip"] == "1.2.3.4" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["time"] == "20:41:45.000000" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["year"] == "2026" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Meta["log_type"] == "dot_connection_reset" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Meta["service"] == "adguardhome_dot" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Meta["source_ip"] == "1.2.3.4" diff --git a/.tests/adguardhome-dot-scan/scenario.assert b/.tests/adguardhome-dot-scan/scenario.assert new file mode 100644 index 00000000000..03455618a29 --- /dev/null +++ b/.tests/adguardhome-dot-scan/scenario.assert @@ -0,0 +1 @@ +len(results) == 0 diff --git a/collections/PumbaLP/adguardhome-dot.yaml b/collections/PumbaLP/adguardhome-dot.yaml new file mode 100644 index 00000000000..d7e83345535 --- /dev/null +++ b/collections/PumbaLP/adguardhome-dot.yaml @@ -0,0 +1,6 @@ +name: PumbaLP/adguardhome-dot +description: "Detect and block DoT (DNS-over-TLS, port 853) scanners targeting AdGuard Home" +parsers: + - PumbaLP/adguardhome-dot-errors +scenarios: + - PumbaLP/adguardhome-dot-scan diff --git a/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md new file mode 100644 index 00000000000..cbf4e68fbf5 --- /dev/null +++ b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md @@ -0,0 +1,32 @@ +# adguardhome-dot-errors + +Parser for AdGuard Home DoT (DNS-over-TLS, port 853) connection reset errors. + +## Description + +AdGuard Home logs connection reset errors when a client connects to port 853 (DoT) but does not complete a proper TLS handshake. This is a common indicator of port scanners and probers. + +This parser extracts the remote IP address and sets the `dot_connection_reset` log type for use by the `PumbaLP/adguardhome-dot-scan` scenario. + +## Matched log example +2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59208: read: connection reset by peer" +## Limitations + +- Only `connection reset by peer` errors contain a remote IP and are actionable. +- Other DoT errors (TLS version mismatch, cipher suite errors, unexpected EOF) do not contain a remote IP. +- DoQ (port 8853/udp) and direct DoH (port 443) errors also do not contain remote IPs. +- DoH via a reverse proxy (e.g. Nginx) is covered by `crowdsecurity/nginx-logs`. + +## Acquisition + +```yaml +source: docker +container_name: + - adguardhome +labels: + type: adguardhome +Or with log file: +filenames: + - /var/log/AdGuardHome.log +labels: + type: adguardhome diff --git a/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml new file mode 100644 index 00000000000..a60a9d7e452 --- /dev/null +++ b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml @@ -0,0 +1,36 @@ +name: PumbaLP/adguardhome-dot-errors +description: "Parse AdGuard Home DoT (DNS-over-TLS, port 853) connection reset errors to detect port scanners and probers" +# +# Matches AdGuard Home log lines containing a remote IP address: +# 2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59208: read: connection reset by peer" +# +# Note: Other DoT error types (TLS version mismatch, cipher suite errors, +# unexpected EOF, bad DNS header) do not contain a remote IP and are +# therefore not actionable by this parser. +# +# Note: DoQ (port 8853/udp) and direct DoH (port 443) errors also do not +# contain remote IPs in AdGuard Home logs and cannot be blocked this way. +# DoH via a reverse proxy (e.g. Nginx) is covered by crowdsecurity/nginx-logs. +# +# Acquisition example: +# source: docker +# container_name: +# - adguardhome +# labels: +# type: adguardhome +# +filter: "evt.Line.Labels.type == 'adguardhome'" +nodes: + - grok: + pattern: '%{YEAR:year}/%{MONTHNUM:month}/%{MONTHDAY:day} %{TIME:time} \[error\] dnsproxy: reading msg proto=tcp err="reading len: read tcp [^>]+->%{IP:remote_ip}:%{INT}: read: connection reset by peer"' + apply_on: Line.Raw + onsuccess: next_stage + statics: + - meta: source_ip + expression: evt.Parsed.remote_ip + - meta: service + value: adguardhome_dot + - meta: log_type + value: dot_connection_reset + - target: evt.StrTime + expression: evt.Parsed.year + "/" + evt.Parsed.month + "/" + evt.Parsed.day + " " + evt.Parsed.time diff --git a/scenarios/PumbaLP/adguardhome-dot-scan.md b/scenarios/PumbaLP/adguardhome-dot-scan.md new file mode 100644 index 00000000000..0ab11c2ee4c --- /dev/null +++ b/scenarios/PumbaLP/adguardhome-dot-scan.md @@ -0,0 +1,23 @@ +```markdown +# adguardhome-dot-scan + +Detect DoT (DNS-over-TLS, port 853) scanners and probers targeting AdGuard Home. + +## Description + +A legitimate DNS-over-TLS client connects cleanly with a proper TLS handshake. Repeated connection resets from the same IP indicate a scanner or prober testing port 853 without proper TLS support. + +Triggers a ban after **5 connection resets within 10 minutes** from the same IP. + +## Requirements + +Requires the `PumbaLP/adguardhome-dot-errors` parser. + +## Tested against + +- AdGuard Home v0.107.x +- Confirmed working in production (blocked real scanners) + +## MITRE ATT&CK + +- T1046 – Network Service Discovery diff --git a/scenarios/PumbaLP/adguardhome-dot-scan.yaml b/scenarios/PumbaLP/adguardhome-dot-scan.yaml new file mode 100644 index 00000000000..690a4316ea4 --- /dev/null +++ b/scenarios/PumbaLP/adguardhome-dot-scan.yaml @@ -0,0 +1,25 @@ +type: leaky +name: PumbaLP/adguardhome-dot-scan +description: "Detect DoT (DNS-over-TLS, port 853) scanners and probers via repeated connection resets on AdGuard Home" +# +# A legitimate DNS-over-TLS client connects cleanly with a proper TLS handshake. +# Repeated connection resets from the same IP indicate a scanner or prober +# testing port 853 without proper TLS support. +# +# Capacity: 5 resets within 10 minutes triggers a ban. +# Tested against AdGuard Home v0.107.x +# +filter: "evt.Meta.log_type == 'dot_connection_reset' && evt.Meta.service == 'adguardhome_dot'" +groupby: evt.Meta.source_ip +capacity: 5 +leakspeed: "10m" +blackhole: 5m +labels: + service: adguardhome + type: scan + spoofable: 0 + confidence: 3 + classification: + - attack.T1046 + behavior: "network:scan" + remediation: true From 583698517d91ac6e1fa6bd299cc04c0e96f88cb0 Mon Sep 17 00:00:00 2001 From: PumbaLP Date: Tue, 2 Jun 2026 19:06:09 +0200 Subject: [PATCH 2/3] fix: address reviewer comments, update IP and formatting --- .../adguardhome-dot-errors.log | 12 ++--- .tests/adguardhome-dot-errors/parser.assert | 2 +- .../adguardhome-dot-scan.log | 6 +++ .tests/adguardhome-dot-scan/parser.assert | 51 +------------------ .tests/adguardhome-dot-scan/scenario.assert | 2 +- .../PumbaLP/adguardhome-dot-errors.md | 10 +++- scenarios/PumbaLP/adguardhome-dot-scan.md | 1 - 7 files changed, 24 insertions(+), 60 deletions(-) diff --git a/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log b/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log index 607e7df60c0..80a2a69510d 100644 --- a/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log +++ b/.tests/adguardhome-dot-errors/adguardhome-dot-errors.log @@ -1,6 +1,6 @@ -2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59208: read: connection reset by peer" -2026/04/04 20:41:42.123456 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59209: read: connection reset by peer" -2026/04/04 20:41:43.234567 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59210: read: connection reset by peer" -2026/04/04 20:41:44.345678 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59211: read: connection reset by peer" -2026/04/04 20:41:45.456789 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59212: read: connection reset by peer" -2026/04/04 20:41:46.567890 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59213: read: connection reset by peer" +2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59208: read: connection reset by peer" +2026/04/04 20:41:42.123456 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59209: read: connection reset by peer" +2026/04/04 20:41:43.234567 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59210: read: connection reset by peer" +2026/04/04 20:41:44.345678 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59211: read: connection reset by peer" +2026/04/04 20:41:45.456789 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59212: read: connection reset by peer" +2026/04/04 20:41:46.567890 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59213: read: connection reset by peer" diff --git a/.tests/adguardhome-dot-errors/parser.assert b/.tests/adguardhome-dot-errors/parser.assert index 8dbbb9da221..cde4e7a6e35 100644 --- a/.tests/adguardhome-dot-errors/parser.assert +++ b/.tests/adguardhome-dot-errors/parser.assert @@ -1,4 +1,4 @@ results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Success == true -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["source_ip"] == "85.217.140.42" +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["source_ip"] == "192.168.1.50" results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["log_type"] == "dot_connection_reset" results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["service"] == "adguardhome_dot" diff --git a/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log b/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log index 16f4d3f8414..469eee12f69 100644 --- a/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log +++ b/.tests/adguardhome-dot-scan/adguardhome-dot-scan.log @@ -4,3 +4,9 @@ 2026/04/04 20:41:44.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59204: read: connection reset by peer" 2026/04/04 20:41:45.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59205: read: connection reset by peer" 2026/04/04 20:41:46.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59206: read: connection reset by peer" +2026/04/04 20:41:41.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59201: read: connection reset by peer" +2026/04/04 20:41:42.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59202: read: connection reset by peer" +2026/04/04 20:41:43.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59203: read: connection reset by peer" +2026/04/04 20:41:44.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59204: read: connection reset by peer" +2026/04/04 20:41:45.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59205: read: connection reset by peer" +2026/04/04 20:41:46.000000 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->1.2.3.4:59206: read: connection reset by peer" diff --git a/.tests/adguardhome-dot-scan/parser.assert b/.tests/adguardhome-dot-scan/parser.assert index 37ab142a6e3..b38c9037fe5 100644 --- a/.tests/adguardhome-dot-scan/parser.assert +++ b/.tests/adguardhome-dot-scan/parser.assert @@ -1,50 +1 @@ -len(results["s01-parse"]["PumbaLP/adguardhome-dot-errors"]) == 6 -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Success == true -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["day"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["month"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["remote_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["time"] == "20:41:41.000000" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Parsed["year"] == "2026" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["log_type"] == "dot_connection_reset" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["service"] == "adguardhome_dot" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["source_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Whitelisted == false -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Success == true -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["day"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["month"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["remote_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["time"] == "20:41:42.000000" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Parsed["year"] == "2026" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Meta["log_type"] == "dot_connection_reset" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Meta["service"] == "adguardhome_dot" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Meta["source_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][1].Evt.Whitelisted == false -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Success == true -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["day"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["month"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["remote_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["time"] == "20:41:43.000000" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Parsed["year"] == "2026" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Meta["log_type"] == "dot_connection_reset" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Meta["service"] == "adguardhome_dot" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Meta["source_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][2].Evt.Whitelisted == false -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Success == true -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["day"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["month"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["remote_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["time"] == "20:41:44.000000" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Parsed["year"] == "2026" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Meta["log_type"] == "dot_connection_reset" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Meta["service"] == "adguardhome_dot" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Meta["source_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][3].Evt.Whitelisted == false -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Success == true -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["day"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["month"] == "04" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["remote_ip"] == "1.2.3.4" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["time"] == "20:41:45.000000" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Parsed["year"] == "2026" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Meta["log_type"] == "dot_connection_reset" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Meta["service"] == "adguardhome_dot" -results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][4].Evt.Meta["source_ip"] == "1.2.3.4" +len(results["s01-parse"]["PumbaLP/adguardhome-dot-errors"]) >= 6 diff --git a/.tests/adguardhome-dot-scan/scenario.assert b/.tests/adguardhome-dot-scan/scenario.assert index 03455618a29..dd6befe054d 100644 --- a/.tests/adguardhome-dot-scan/scenario.assert +++ b/.tests/adguardhome-dot-scan/scenario.assert @@ -1 +1 @@ -len(results) == 0 +len(results) >= 1 diff --git a/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md index cbf4e68fbf5..ed50f7122fe 100644 --- a/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md +++ b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md @@ -9,7 +9,10 @@ AdGuard Home logs connection reset errors when a client connects to port 853 (Do This parser extracts the remote IP address and sets the `dot_connection_reset` log type for use by the `PumbaLP/adguardhome-dot-scan` scenario. ## Matched log example -2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->85.217.140.42:59208: read: connection reset by peer" + +```text +2026/04/04 20:41:41.673779 [error] dnsproxy: reading msg proto=tcp err="reading len: read tcp 172.20.2.2:853->192.168.1.50:59208: read: connection reset by peer" +``` ## Limitations - Only `connection reset by peer` errors contain a remote IP and are actionable. @@ -25,8 +28,13 @@ container_name: - adguardhome labels: type: adguardhome +``` + Or with log file: + +```yaml filenames: - /var/log/AdGuardHome.log labels: type: adguardhome +``` diff --git a/scenarios/PumbaLP/adguardhome-dot-scan.md b/scenarios/PumbaLP/adguardhome-dot-scan.md index 0ab11c2ee4c..0bc45b3c360 100644 --- a/scenarios/PumbaLP/adguardhome-dot-scan.md +++ b/scenarios/PumbaLP/adguardhome-dot-scan.md @@ -1,4 +1,3 @@ -```markdown # adguardhome-dot-scan Detect DoT (DNS-over-TLS, port 853) scanners and probers targeting AdGuard Home. From a3edfd9d73cf17cd72bc7c9378bcbbae923a7e1d Mon Sep 17 00:00:00 2001 From: PumbaLP Date: Fri, 5 Jun 2026 22:40:56 +0200 Subject: [PATCH 3/3] fix: use message instead of Line.Raw, fix scenario assert overflow validation --- .tests/adguardhome-dot-scan/parser.assert | 4 +++- .tests/adguardhome-dot-scan/scenario.assert | 4 +++- parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.tests/adguardhome-dot-scan/parser.assert b/.tests/adguardhome-dot-scan/parser.assert index b38c9037fe5..9ddd16ce2fd 100644 --- a/.tests/adguardhome-dot-scan/parser.assert +++ b/.tests/adguardhome-dot-scan/parser.assert @@ -1 +1,3 @@ -len(results["s01-parse"]["PumbaLP/adguardhome-dot-errors"]) >= 6 +len(results["s01-parse"]["PumbaLP/adguardhome-dot-errors"]) == 6 +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Success == true +results["s01-parse"]["PumbaLP/adguardhome-dot-errors"][0].Evt.Meta["source_ip"] == "192.0.2.42" diff --git a/.tests/adguardhome-dot-scan/scenario.assert b/.tests/adguardhome-dot-scan/scenario.assert index dd6befe054d..46a0769b452 100644 --- a/.tests/adguardhome-dot-scan/scenario.assert +++ b/.tests/adguardhome-dot-scan/scenario.assert @@ -1 +1,3 @@ -len(results) >= 1 +len(results) == 1 +results[0].Overflow.Alert.Source.IP == "192.0.2.42" +results[0].Overflow.Alert.Scenario == "PumbaLP/adguardhome-dot-scan" diff --git a/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml index a60a9d7e452..55a573cfe56 100644 --- a/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml +++ b/parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml @@ -23,7 +23,7 @@ filter: "evt.Line.Labels.type == 'adguardhome'" nodes: - grok: pattern: '%{YEAR:year}/%{MONTHNUM:month}/%{MONTHDAY:day} %{TIME:time} \[error\] dnsproxy: reading msg proto=tcp err="reading len: read tcp [^>]+->%{IP:remote_ip}:%{INT}: read: connection reset by peer"' - apply_on: Line.Raw + apply_on: message onsuccess: next_stage statics: - meta: source_ip