Wer WatchGuard-Firewall-Logs über einen Syslog-Collector in Wazuh einspeist, trifft schnell auf diese frustrierende Meldung:
No decoder matched
Genau das ist Nikola passiert:
Die Logs der WatchGuard-Firewall landen per rsyslog → lokale Datei → Wazuh-Agent → Manager im System, tauchen in archives.log auf – aber keiner der gefundenen WatchGuard-Decoder von GitHub greift.
In diesem Artikel schauen wir uns an:
- warum „No decoder matched“ erscheint
- wie man einen sinnvollen Decoder-Aufbau für WatchGuard-Logs gestaltet
- wie man aus einfachen „Allow/Deny“-Regeln zu reichhaltig geparsten Events kommt
1. Ausgangssituation: WatchGuard-Logs aus SyslogCollector
Die Logs kommen von einer WatchGuard-Firewall, z. B.:
2025-11-21T00:28:01.556323+00:00 D1-ROM1-FW-A 80D802B41D509 D1-ROM1-FW firewall: msg_id="3000-0148" Allow Collector Firebox 73 udp 20 64 10.x.x.x 208.x.x.x 46616 53 geo_dst="USA" record_type="AAAA" question="mail.mydomain.com" (DNS-00)
2025-11-21T00:28:01.556528+00:00 D1-ROM1-FW-A 80D802B41D509 D1-ROM1-FW firewall: msg_id="3000-0148" Deny WAN - Aruba Firebox 40 tcp 20 239 194.x.x.x 209.x.x.x 41277 591 offset 5 S 1497867397 win 4 geo_src="BGR" geo_dst="ITA" flags="SR" duration="0" sent_pkts="1" rcvd_pkts="0" sent_bytes="40" rcvd_bytes="0" (Unhandled External Packet-00)
2025-11-21T00:28:01.946033+00:00 D1-ROM1-FW-A 80D802B41D509 D1-ROM1-FW https-proxy[4148]: msg_id="2CFF-0000" Allow Collector WAN - Aruba tcp 10.x.x.x 213.x.x.x 42018 443 msg="HTTPS Request" proxy_act="Default-HTTPS-Client" tls_profile="TLS-Client-HTTPS.Standard" ...
Typisch:
- Syslog-Prefix (Datum, Host
SysLogCollector, Pfad, Timestamp) - dann der eigentliche WatchGuard-Teil mit:
- Host / Device-Name (
D1-ROM1-FW-A,D1-ROM1-FW) - Subsystem (
firewall:,https-proxy[...]) msg_id="...", Action (Allow/Deny), Richtlinie, Bytes, Protokoll, Zonen, IPs, Ports, Geo-Infos, Kategorien etc.
- Host / Device-Name (
Die vorhandenen Community-Decoder passten nicht exakt zum Format – Ergebnis:
Kein Decoder matcht → Wazuh behandelt die Zeilen nur als plain Logtext.
2. Wichtiger Punkt: „No decoder matched“ heißt nicht „Log ist kaputt“ – sondern „Decoder passt nicht“
[Bony John] hat es schön auf den Punkt gebracht:
- Wenn „No decoder matched“ angezeigt wird,
→ kein vorhandener Decoder trifft auf das Format zu.
Das kann bedeuten:
- Regex des Decoders ist falsch oder zu streng
- Prematch passt nicht
- Logformat weicht von der erwarteten WatchGuard-Variante ab
- oder der „Decoder von GitHub“ war für ein anderes WatchGuard-Template geschrieben
Darum ist der richtige Weg: Eigene Decoder schreiben, passend zu den echten Logs.
3. Lösung: Parent-/Child-Decoder für WatchGuard-Logs
Statt zig Einzeldecoder im Blindflug zu testen, hat Bony ein sauberes, mehrstufiges Decoder-Design vorgeschlagen.
3.1 Parent-Decoder: Erkennen, dass es überhaupt WatchGuard ist
Beispiel:
<decoder name="watchguard">
<prematch>D1-ROM1-FW</prematch>
</decoder>
Das:
- prüft nur, ob der String
D1-ROM1-FWim Log vorkommt - markiert das Event als „WatchGuard-Log“
- dient als Anker für weitere Child-Decoder
Du könntest hier genauso gut auf firewall: oder https-proxy[ matchen – Hauptsache stabil.
3.2 Erster Child-Decoder: Basisdaten für alle Varianten
Ein erster Child-Decoder extrahiert Felder, die in den meisten Logs gleich strukturiert vorkommen, z. B.:
- Device-ID / -Host
msg_id- Action (
Allow/Deny) - Policy / Rule Name
- Bytes / Protokoll / Zonen
- Quell- und Ziel-IP/Port
Beispiel (vereinfacht):
<decoder name="watchguard">
<parent>watchguard</parent>
<regex>(\w+)\s*(\S*)\s*(\S*):\s*msg_id="(\S*)"\s*(\w*)\s*(\.*)\s+(\d+)\s*(\w+)\s*(\d*)\s*(\d*)\s+(\S*)\s*(\S*)\s*(\d*)\s*(\d*)\s*</regex>
<order>device_id,device_name,device_type,msg_id,action,policy,bytes,protocol,src_zone,dst_zone,srcip,dstip,srcport,dstport</order>
</decoder>
Das ist nur ein Beispiel – wichtig ist das Muster:
parent="watchguard"→ knüpft an das Prematch anregex→ zieht in einem Schwung die gemeinsamen Felderorder→ bennent sie sauber (action,srcip,dstip, …)
3.3 Weitere Child-Decoder: Spezifische Events (DNS, TCP Deny, HTTPS)
Nach dem Port-Block ändern sich die Logs – DNS-, TCP- und HTTPS-Events haben unterschiedliche Zusatzfelder.
Darum nutzt Bony weitere Child-Decoder für die unterschiedlichen Endstücke:
- DNS-Events, z. B.:
<decoder name="watchguard"> <parent>watchguard</parent> <regex>geo_dst="(\w*)" record_type="(\S*)" question="(\S*)" \((\S*)\)</regex> <order>geo_dst,record_type,domain,category</order> </decoder> - TCP-Deny-Events mit Geo-Daten, Flags, Duration, Packet-/Byte-Counts:
<decoder name="watchguard"> <parent>watchguard</parent> <regex>offset (\d*)\s*(\w*)\s*(\d*)\s*\.*geo_src="(\w*)"\s*geo_dst="(\S*)"\s*flags="(\S*)"\s*duration="(\d*)"\s*sent_pkts="(\d*)" rcvd_pkts="(\d*)" sent_bytes="(\d*)" rcvd_bytes="(\d*)"\s*\((\.*)\)$</regex> <order>offset,tcp_flag,seq_id,geo_src,geo_dst,flags,duration,sent_pkts,rcvd_pkts,sent_bytes,rcvd_bytes,category</order> </decoder>
Für HTTPS-Proxy-Logs (https-proxy[...]) könnte man nach dem gleichen Muster einen weiteren Child-Decoder bauen, der z. B. msg="HTTPS Request", tls_version, sni, action, app_id, Bytes etc. extrahiert.
4. Nikos eigenes Setup: Minimaldecoder + einfache Regeln
Niko hatte sich am Wochenende bereits selbst einen Einstieg gebaut:
Predecoder:
<decoder name="firewall_log">
<prematch>^\.*firewall:</prematch>
</decoder>
Dann mehrere kleine Child-Decoder:
msg_id="..."→ FeldIDfqdn_dst_match="..."→ FeldFQDN_DST(Allow)bzw.(Deny)→ FeldAction(tcp)/(udp)→ FeldPROTOCOL
Und dazu Regeln:
<group name="Watchguard,">
<rule id="110000" level="0">
<decoded_as>firewall_log</decoded_as>
<description>WatchGuard-FW-Event</description>
</rule>
<rule id="110001" level="5">
<if_sid>110000</if_sid>
<match>Deny</match>
<description>Packet Was Denied.</description>
</rule>
<rule id="110002" level="5">
<if_sid>110000</if_sid>
<match>Allow</match>
<description>Packet Was Allowed.</description>
</rule>
</group>
Das ist ein guter, pragmatischer Start:
- Man sieht schnell: „Allow“ vs. „Deny“
- Events werden schon im SIEM sichtbar hervorgehoben
Bony bestätigt das sinngemäß:
Das funktioniert – aber du kannst noch viel mehr aus den Logs herausholen.
5. Wann lohnt sich ein „voller“ Decoder?
Ein minimaler Decoder reicht, wenn du:
- nur Alerts „Allow vs. Deny“ brauchst
- keine tiefe Analyse nach Geo, Ports, Policies, Bytes etc. machst
Ein „reicher“ Decoder wie der von Bony lohnt sich, wenn du:
- Dashboards zu:
- Top-Policies, Top-Geo-Quellen/-Ziele, abgewiesenen Ports usw. willst
- gezielte Regeln bauen möchtest:
- z. B. „Deny aus bestimmten Ländern zu sensiblen Ports mit bestimmten Flags“
- später Threat Hunting machen willst, z. B.:
- SYN-Scans, auffällige Offsets, viel Traffic zu wenig IPs usw.
Dann zahlen sich saubere Felder wie geo_src, geo_dst, duration, sent_pkts, category absolut aus.
6. Fazit
Der Thread zeigt sehr schön:
- „No decoder matched“ ist keine Sackgasse – sondern der Startpunkt für maßgeschneiderte Lösungen.
- WatchGuard-Logs sind strukturiert genug, um mit Parent-/Child-Decodern sauber aufgelöst zu werden.
- Man kann klein anfangen (Allow/Deny) und schrittweise mehr Felder ergänzen.
- Mit einem guten Decoder-Set erhält man nicht nur Events, sondern ein mächtiges Netzwerk-Observability-Werkzeug.