DNP3 Is Not Just Port 20000
Master and outstation roles, class polls, event classes, Select-Before-Operate, and the protocol fields that tell you who read what and who operated what.
Most monitoring for DNP3 stops at the port.
A rule watches TCP 20000, an allow-list names the hosts that may use it, and the boundary is declared covered.
That answers one question — who connected.
It leaves the two that matter unanswered.
Who read what.
And who operated what.
DNP3 is a language for remote control and event reporting.
This article walks through its core model, what makes it different, how its control path works, and which fields to monitor if you want to know what actually happened on your grid.
The Core Model: Master And Outstation
DNP3 has two roles.
A master sends requests.
An outstation stores points, reports events, and accepts commands.
What a master sends:
- reads
- writes
- controls
- time sync
- class polls
The outstation is not a passive register bank.
It maintains a picture of the field, and it keeps a record of how that picture changed since the master last looked.
What Makes DNP3 Different: It Is Event-Oriented
This is the property most security tooling gets wrong, because it is the property Modbus does not have.
A DNP3 outstation can report:
- the current value
- the changed value
- the event class
- a timestamp
- device status
Data is organized into classes.
Class 0 is static data — the current state of the points assigned to it.
Classes 1, 2 and 3 carry events, so a master can poll some changes more often than others.
One caveat that trips people up: the standard, IEEE 1815, does not rank Classes 1, 2 and 3.
They are three event groupings.
Which one carries urgent data is a site configuration decision, not a protocol property.
Mapping Class 1 to the most urgent points is a common convention, not a rule, so do not assume a Class 1 event is important on a network you have not looked at.
The consequence is worth stating plainly.
You can see not only what is true now, but what changed since the master last looked.
An analog value that crossed its deadband and came back is recorded in the event classes and absent from a static read.
Outstations can also send unsolicited responses — events pushed without a poll — so what the master asked for is not the whole traffic picture either.
For a defender that cuts both ways.
The event record is evidence, timestamped and ordered.
It is not attribution: base DNP3 has no authentication, Secure Authentication is optional and rarely deployed, and an event ties to a point index rather than to whoever caused it.
The record is also a buffer, and buffers can be filled.
The Control Path
DNP3 defines two control methods, and both are standard.
The first is Select-Before-Operate.
The SELECT arms a specific point for a specific action.
The OPERATE executes it.
The outstation validates that the OPERATE matches what was selected, and answers with a status.
The second is DIRECT_OPERATE, which carries the control in a single exchange.
It is faster.
It is not a shortcut around a required step — IEEE 1815 treats it as a co-equal method, and plenty of environments use it deliberately.
The distinction matters for detection, not for judgement.
A control arriving as a single DIRECT_OPERATE looks different on the wire from the two-step sequence, so if your environment normally uses one form, the other appearing is a fact worth knowing.
Neither is malicious by itself.
The problem is that if you alert only on a connection to port 20000, both forms look identical to you — and so does a read.
What To Monitor Instead
Do not monitor only TCP 20000.
The fields that carry meaning:
- source DNP3 address — which master claims to be talking, independent of IP; a 16-bit link address, not an identity
- application function — read, write, control, restart, time sync
- object group — what kind of data: binary, analog, counter, control block
- variation — the encoding, including whether a timestamp is present
- point index — which specific breaker, feeder, or measurement
- SELECT and OPERATE sequence — whether control followed the expected path
- restart commands — cold and warm restart, rare, high impact, worth alerting on
- IIN flags — the outstation's own status bits, including its complaints
- event buffer overflow — events were generated and lost
Two of those deserve extra attention.
IIN flags are the Internal Indications the outstation returns in every response.
They are the device telling you about itself: restarted, needs time sync, buffer overflowed, configuration corrupt.
A device reporting its own restart is information that arrives whether or not anyone was watching for it.
Event buffer overflow means the outstation generated more events than it could hold.
Something happened and the record of it is gone.
Whatever the cause — a genuine burst of field activity, a polling failure, or deliberate flooding — an overflow is a gap in the evidence, and a monitoring stack that ignores the flag will not know its own history has holes.
The Question Worth Asking
The real question is not only who connected.
The real question is who read what, who operated what, and whether the outstation accepted it.
A connection log answers none of those.
A monitoring stack that reads DNP3 at the application layer answers all three.
The difference shows up on the day you need to reconstruct what moved a breaker.
OT security must be testable.
Not documented.
Try It Yourself
- Start free: github.com/zakharb/labshock — the lab runs locally with Docker, no cloud.
- Firegate is the substation zone: 6 kV, RTUs, SCADA, feeders and breakers, at labshocksecurity.com.
- Open a live DNP3 session, read the fields, map the points, then send one command through SELECT and OPERATE and watch the breaker move.
- Already monitor DNP3 in production? Check what your IDS reported about step 3: discord.gg/bpmaQFfW76
More on education
