Summary

  • Zeek’s conn.log records what one configured sensor inferred from observed traffic; its compact fields are not a packet-by-packet transcript or a view from everywhere on the path.
  • A defensible finding preserves the log’s schema, Zeek version, scripts, capture conditions, clock, loss evidence and UID-linked records—and says explicitly when no packet capture exists.

The elegance of a reduced event

Paxson’s 1998 paper on Bro, the system later renamed Zeek, described two deliberately separate layers. An event engine reduced a filtered packet stream into higher-level network events. A policy-script interpreter decided what those events meant for a particular site. This was not merely an implementation convenience. A monitor watching a busy link could not treat every byte as if storage and analysis were unlimited, and a security policy needed to change without hard-wiring every decision into the packet engine.

That architecture is the intellectual ancestor of the compact connection row. Reduction makes high-volume traffic investigable. It also creates an evidentiary boundary. The row is an output of observation, filtering, state tracking and interpretation. It is not the traffic itself.

The original paper was unusually candid about the boundary. Packet drops could defeat monitoring because the missing packet might contain the very activity that identified an intruder. Filters and snapshot length determined which traffic reached user space. The event engine then performed integrity checks, maintained connection state and decided whether to record a full packet, a header or nothing. The monitor was designed on the assumption that attackers might understand and try to overwhelm or evade it. Those are not historical curiosities. They are reasons to attach operating context to every modern claim made from a log.

What one conn.log row actually says

The current Zeek documentation calls conn.log foundational and says it primarily captures layer-three and layer-four facts: who talked to whom, when, for how long and using which protocol. It covers TCP and UDP, while the script reference also explains that UDP and ICMP “connections” use flow semantics. The word connection therefore does not promise one universal transport meaning.

Some fields are straightforward only after their frame is stated. ts is the time of the first packet Zeek saw, not proof of the first packet that existed anywhere. uid is a unique identifier for the connection inside Zeek’s record system and lets an analyst join related protocol logs. It is a correlation handle, not an identity issued by either endpoint.

conn_state summarizes the state Zeek inferred. S0 means an attempt was seen without a reply; SF denotes normal establishment and termination; other codes capture rejection, reset and partially observed closing patterns. The crucial verbs are seen and inferred. A sensor placed on another segment, behind another capture filter or during a loss interval may produce a different summary of the same endpoint exchange.

history is even easier to overread. Its letters encode observed state events: uppercase for the originator, lowercase for the responder. In ShADadFf, for example, the notation compresses a SYN, handshake, acknowledgements, data and closing events. But several flags are recorded at most once per direction, while others repeat logarithmically. The string is compact state history, not a chronological list of packets. It cannot be expanded backwards into the packets that produced it.

Byte and duration fields also carry design choices. For TCP, orig_bytes and resp_bytes are derived from sequence numbers and the reference warns they can be inaccurate, including for large connections. duration omits some trailing non-productive packets after a direction closes, even though history may reflect them. Packet and IP-byte counters are optional because they depend on the connection-size analyser. Local and remote flags depend on Site::local_nets; without that configuration, they remain empty. A missing value can therefore mean configuration, not absence in the network.

Loss is evidence about the witness

Zeek gives operators two especially useful ways to interrogate the witness. missed_bytes counts bytes missed in content gaps and represents packet loss; a non-zero value will normally disrupt protocol analysis even if some earlier analysis completed. capture_loss.log estimates missing traffic from gaps in TCP sequence numbers. The documentation is careful: Zeek sees a gap and assumes the missing traffic corresponds to loss. That estimate is informative, but it is rooted in TCP observations and is not a universal meter for everything the sensor failed to receive.

reporter.log records internal warnings and errors about traffic handling and computational conditions. Together, the connection row, capture-loss record and reporter messages can answer a better question than “Is the log true?” They can show what the sensor was in a position to observe, what analysis completed and where confidence must narrow.

A zero in missed_bytes does not establish that there was no loss upstream of the capture interface, no asymmetric route, no filter excluding relevant packets and no blind interval before the process started. Equally, a loss estimate does not automatically invalidate every field in every row. Evidence becomes stronger when the limitation is located in time, direction and processing stage rather than turned into a blanket disclaimer.

A preservation bundle, not a detached row

If a conn.log finding may be used months later for incident reconstruction, disciplinary action, litigation, insurance or regulator reporting, preserve the conditions that gave the row its meaning. The minimum bundle should contain the raw log and exact schema; the Zeek release; loaded scripts and relevant configuration; sensor interface, network placement and capture filter; clock source, timezone and measured offsets; capture-loss and reporter records covering the interval; and the UID-related DNS, HTTP, TLS, notice or other logs that support the interpretation.

Where policy and retention permit, add an immutable packet-capture slice or a verifiable hash linked to its controlled location. The PCAP is not automatically perfect evidence—it too has a vantage, snap length, loss profile and chain of custody—but it allows later reviewers to test a compact inference against lower-level observations. When no PCAP was retained, say so. “This Zeek sensor observed and summarized…” is a stronger professional sentence than an absolute claim the evidence cannot sustain.

Versioning matters because the schema changes. The current documentation notes, for example, that ip_proto was added in Zeek 7.1. Scripts can add fields, disable behaviour or change what is logged. A CSV header, JSON schema or documentation snapshot therefore belongs beside the record. Without it, a later tool may silently assign today’s meaning to yesterday’s column.

Sources