Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .tests/adguardhome-dot-errors/adguardhome-dot-errors.log
Original file line number Diff line number Diff line change
@@ -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"
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
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"
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
7 changes: 7 additions & 0 deletions .tests/adguardhome-dot-errors/config.yaml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions .tests/adguardhome-dot-errors/parser.assert
Original file line number Diff line number Diff line change
@@ -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"
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
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"
1 change: 1 addition & 0 deletions .tests/adguardhome-dot-errors/scenario.assert
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
len(results) == 0
6 changes: 6 additions & 0 deletions .tests/adguardhome-dot-scan/adguardhome-dot-scan.log
Original file line number Diff line number Diff line change
@@ -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"
7 changes: 7 additions & 0 deletions .tests/adguardhome-dot-scan/config.yaml
Original file line number Diff line number Diff line change
@@ -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
50 changes: 50 additions & 0 deletions .tests/adguardhome-dot-scan/parser.assert
Original file line number Diff line number Diff line change
@@ -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"
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
1 change: 1 addition & 0 deletions .tests/adguardhome-dot-scan/scenario.assert
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
len(results) == 0
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
6 changes: 6 additions & 0 deletions collections/PumbaLP/adguardhome-dot.yaml
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions parsers/s01-parse/PumbaLP/adguardhome-dot-errors.md
Original file line number Diff line number Diff line change
@@ -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
Comment thread
PumbaLP marked this conversation as resolved.
36 changes: 36 additions & 0 deletions parsers/s01-parse/PumbaLP/adguardhome-dot-errors.yaml
Original file line number Diff line number Diff line change
@@ -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
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
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
Comment thread
PumbaLP marked this conversation as resolved.
23 changes: 23 additions & 0 deletions scenarios/PumbaLP/adguardhome-dot-scan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
```markdown
Comment thread
PumbaLP marked this conversation as resolved.
Outdated
# 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
25 changes: 25 additions & 0 deletions scenarios/PumbaLP/adguardhome-dot-scan.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading