Skip to content

fix(sonicwall): recover addresses, firewall actions and event outcomes - #2743

Closed
kryonsx wants to merge 2 commits into
utmstack:v11from
kryonsx:codex/data-engine-firewall-sonicwall-20260924
Closed

kryonsx wants to merge 2 commits into
utmstack:v11from
kryonsx:codex/data-engine-firewall-sonicwall-20260924

Conversation

@kryonsx

@kryonsx kryonsx commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Problem

On the current EventProcessor, the SonicWall filter misses most outcomes and many source addresses:

  • Addresses. The address step splits src and dst only in the form ip:port:interface. The grok step writes nothing unless every pattern matches, and the filter then deletes the original value. So ip:port (used by VPN negotiation events) and ip::interface (used by user login events) lose their address completely. On one deployment this was most of the traffic.
  • Firewall action. When fw_action is the last key on the line, the rescue grok cannot bound it, and the fallback rename still reads log.fwaction. go-sdk v1.1.35 and later keep the underscore (log.fw_action), so those events get no action and no outcome. That was about a quarter of drops on one deployment and most drops on another.
  • Outcomes. Only fw_action gives an outcome (forward gives success, drop gives denied). Events whose firewall action is NA get none, including failed logins, failed or refused VPN negotiations, allowed logins and closed connections.
  • CEF header. The CEF header step captures its fields with the lazy {{.data}} template alone. The grok step rejects an empty match, so the step never writes.

The administrator authentication-failure rule counts event 29, which is "Administrator login allowed", as a failure. Its message branch also matches SSO probe failures and policy denials, and its history counts any event from the same address. Grouping by address and user turns a password spray into one alert per user name, and grouping only nests repeats, so every attempt that passes the history check still creates an alert.

Change

  • Addresses: separate steps for ip:port:interface, ip:port and ip::interface. The original value is deleted only after an address was read, and a bare value moves to origin.ip or target.ip only when it is an IP address.
  • Firewall action: a fallback reads fw_action under both spellings when the rescue does not.
  • Outcomes for events without a firewall decision, by the meaning of their message:
    • success: logins allowed (29, 31, 236, 237, 238, 1080), "IKEv2 Authentication successful" (942), "IKEv2 negotiation complete" (978), and "Connection Closed" (537) when bytes came back.
    • failure: logins denied due to bad credentials (32, 33, 200), a timed-out pending login (34), XAUTH, RADIUS and LDAP failures (140, 243, 244, 746, 747), an expired password (1035), a failed SSO probe (1117), and failed IKE negotiations (402, 658, 953, 967, 1305).
    • denied: "User login denied - not allowed by Policy rule" (986) and "SSLVPN service is not allowed on " (1079).
    • An explicit fw_action still takes precedence.
  • CEF header: each header field uses a non-empty pattern.
  • Rule sonicwall_admin_auth_failures (v2.2.0): counts logins denied due to bad credentials that carry failure. Its history counts failures from the same address, and alerts are deduplicated by address, which keeps one alert per source for seven days.
  • Filter version 4.1.0.

Validation

All results use the latest versions: EventProcessor 8a3ade7, with every parser and rule plugin on go-sdk v1.1.36, and v11 d2479c1a.

  • Real records in the playground: 42 retained records from four deployments, across 20 event types: closed connections with and without returned bytes, allowed web requests, dropped traffic, blocked botnet sources, IPS prevention and detection, bad-credential logins, allowed logins, policy denials, refused SSL VPN attempts, SSO probe failures, failed and completed IKE negotiations, and statistics and port-scan reports. The unchanged filter passed 7/42: it missed all 13 expected failures, all 10 denials and 10 of 12 successes, and lost the source address on 17 records. This branch passed 42/42, with the expected outcome and the addresses written in each raw line, and no event errors.
  • Edge cases in the playground: six fabricated records: a CEF "Connection Closed" line, an IKE failure with ip:port, a login failure with ip::interface, a source without an address, a bare source address, and an allowed WAN login. The unchanged filter passed 0/6. This branch passed 6/6, including the CEF header fields.
  • Rule: the rule conditions were evaluated with go-sdk v1.1.36 on this branch's output for the 42 real records. The current condition matched 9: the 5 logins denied due to bad credentials, plus 2 logins denied by policy and 2 failed SSO probes, which are not credential guessing. The new condition matched exactly the 5. The full plugins/alerts suite passes.

Production context

  • Four deployments send SonicWall logs, about 286 million records in 30 days. None of them has an outcome on events without a firewall decision today.
  • Over 30 days, SonicWall reported about 298,000 logins denied due to bad credentials, 207,000 failed SSO probes, 89,000 logins denied by policy, 18,000 refused SSL VPN attempts and about 16,000 allowed internal logins. Over 7 days, one deployment reported about 365,000 failed IKE negotiations from outside addresses.
  • "Connection Closed" is 93% of one deployment's traffic. Every close with a received-byte count had data back, while 15–26% of closes had no received bytes; those keep no outcome.
  • Rule volume, simulated from retained records. With the current rule and the new addresses, a quiet day on one deployment would open about 205 alert groups (one per address and user name), and another deployment about 85 from SSO probe failures and policy denials; both are above the 50-per-day switch-off. On that first deployment's busiest day of the last week, 41 addresses made 41,227 bad-credential attempts: grouping by address alone would still create 40,756 alerts, while deduplicating by address creates 15. On a third deployment, 27 addresses made about 3,000 attempts a day at about one every 12 minutes each, which stays under the rule's threshold of 5 in 15 minutes; the threshold was not changed.

Limits

  • SonicWall's documentation site refused the allowlisted fetcher, so event meanings come from the observed message text.
  • Other rescued fields (msg, usr, note and the rest) are deleted before their rescue runs, so they are lost when they are the last key on the line. In 8,000 sampled records only uuid was ever last (91 records), which loses the event UUID; this change leaves that behavior as it is.
  • The playground results apply to the recorded engine build; deployed behavior after rollout remains unverified. History queries were simulated from retained records, not executed. No customer configuration was changed. Records and identifiers stay private.

🤖 Generated with Claude Code

kryonsx and others added 2 commits September 24, 2026 19:18
The address step splits src and dst only as ip:port:interface. The grok
step writes nothing unless every pattern matches and the filter then
deletes the value, so ip:port (VPN negotiation events) and
ip::interface (user logins) lose their address. When fw_action is the
last key, the rescue grok cannot bound it and the fallback rename reads
log.fwaction, while go-sdk v1.1.35 and later keep the underscore, so
those events get no action and no outcome. Events whose firewall action
is NA get no outcome at all, and the CEF header step captures its fields
with a lone lazy pattern, which the grok step rejects.

Each address shape now has its own step, and the original value is
deleted only after an address was read. A fallback reads fw_action
under both spellings. Events without a firewall decision get an outcome
from the meaning of their message: allowed logins and completed IKEv2
negotiations give success, as does Connection Closed when bytes came
back; bad credentials, RADIUS, LDAP, XAUTH and SSO failures and failed
IKE negotiations give failure; policy and zone refusals give denied.
The CEF header fields use a non-empty pattern.

The administrator authentication-failure rule counted "Administrator
login allowed" (29) as a failure and, through its message branch, SSO
probe failures and policy denials. It now counts logins denied due to
bad credentials with a failure outcome, its history counts failures from
the same address, and alerts group by address, so a password spray is
one alert instead of one per user name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Grouping by address only nests repeats: every attempt that passes the
history check still creates a child alert. On the busiest day in the
last week one deployment had 41,227 bad-credential denials from 41
addresses, which would create 40,756 alerts. Deduplicating by address
creates 15 and keeps one alert per source for seven days.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@osmontero

Copy link
Copy Markdown
Member

Subsumed by #2756, which carries this filter+rule fix plus a committed raw-replay contract test (sonicwall_contract_test.go, verified to fail on base and pass on head). Merge #2756 instead.

@osmontero osmontero closed this Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants