Project

General

Profile

Actions

Feature #9205

open
LS

dnp3: events for link-layer recovery, optional resync on bad start bytes

Feature #9205: dnp3: events for link-layer recovery, optional resync on bad start bytes

Added by Lucas Sotomayor 3 days ago. Updated 3 days ago.

Status:
In Review
Priority:
Normal
Assignee:
-
Target version:
Effort:
Difficulty:
Label:

Description

The DNP3 link-layer parser recovers from some link errors (since 8.0.7, a bad link CRC or an impossible LENGTH resynchronizes on the next start sequence) but not from others: octets that are not a start sequence are still a fatal parser error, which ends DNP3 inspection of the flow.

DNP3 endpoints differ in exactly this respect. opendnp3 always resynchronizes; dnp3-rs exposes the choice as LinkErrorMode::{Discard, Close} (Discard resynchronizes, Close ends the session). A device configured to resynchronize processes frames behind a link error that a stop-on-error device never sees, and the setting is not visible on the wire. On a corpus of 320 DNP3 streams with one link-layer defect each, the frames a device processes depend on that setting in 272.

Proposal:

  1. A new event, dnp3.policy_divergence, set on a transaction whose frame was parsed after a link-layer error on the same flow direction. It marks the frames whose processing by the device depends on its recovery setting. No change in parser behaviour.
  2. A new option, app-layer.protocols.dnp3.resync-on-bad-start (default no). When yes, octets that are not a start sequence are skipped (new event dnp3.bad_start_bytes) instead of ending inspection; the probing parser looks for a start sequence with a valid header CRC further in; after a bad transport CRC the parser resynchronizes from the next octet. This is the opendnp3 / dnp3-rs Discard policy.

Measured on the corpus above: with the option off, logged transactions are identical to 8.0.7 and the new event fires on 96 streams; with it on, Suricata reports the frames opendnp3 processes on 304 of 320 streams (144 before), the streams on which the device processes a frame Suricata does not log go from 176 to 16, and the divergence event fires on exactly the 272 setting-dependent streams (no false positive). A 20-minute benign master/outstation capture raises no new event.

I have an implementation (two commits: code, docs) and will open a PR referencing this ticket. Follows up on GHSA-3j7x-8qr3-x69c and GHSA-93vw-3m29-vx6x.

LS Updated by Lucas Sotomayor 3 days ago Actions #1

  • Status changed from New to In Review
Actions

Also available in: PDF Atom