Home / Learn / Security

Troubleshooting BACnet/SC When You Can't Read the Traffic

On BACnet/SC you lose the plain-text capture you've relied on for years. You don't lose the ability to diagnose. The shape of the connection tells you most of what the payload used to.

Scott Draper · Senior Building Automation Specialist, Niagara N4 Certified

For twenty years, the answer to a strange BACnet problem has been: put Wireshark on the segment and read what the devices are actually saying. On BACnet/SC that stops working. Point Wireshark at an SC connection and you'll see a handshake, then a stream of “Application Data” you can't read. That's the design doing its job.

The good news is that most SC faults happen before any BACnet is exchanged, and those stages are visible. DNS isn't encrypted. TCP isn't encrypted. The start of the TLS handshake isn't encrypted. Read the shape of the connection, add the device's own status, and you can place nearly every fault. This article is the method I use. It assumes you know the connection sequence from how BACnet/SC works.

What Wireshark shows you, with and without keys

Without the TLS keys (the normal case)

  • DNS queries and answers, if the hub URI uses a name.
  • TCP: SYN, SYN-ACK, ACK, retransmissions, resets, FINs. All in the clear.
  • TLS ClientHello from the node, including the server name (SNI) it's asking for, and the hub's ServerHello.
  • After that, only Application Data records. In TLS 1.3 the certificates and alerts are encrypted too, so you can't read the reason a handshake failed — only that it stopped.

With a TLS key log

If one endpoint can write a TLS key log (the SSLKEYLOGFILE-style file), give it to Wireshark under Preferences › Protocols › TLS › (Pre)-Master-Secret log filename. Wireshark then decrypts the session, shows the WebSocket upgrade, and decodes BVLC-SC with the bscvlc dissector (Wireshark 3.6 and later). You see the Connect-Request, the Connect-Accept or NAK, every Encapsulated-NPDU and the BACnet inside it.

The catch: most embedded controllers can't export their keys. Key logs usually come from software hubs or test tools. So in the field, plan on working without them. Decryption is a bonus when you can get it.

The connection-pattern method

Capture between the node and the hub — a mirror port on the switch, or on the hub's machine if it's a software hub — and filter to the hub's port. Then walk the connection in order. Each stage either happened or it didn't, and the first stage that didn't is where your fault is.

1. Did DNS answer?

If the URI uses a name, look for the query and the answer. No answer, or an answer of “no such name”, and the node never gets as far as TCP. Also check the answer is the address you expect — a stale record pointing at the old hub is its own fault.

2. Was the SYN answered?

A SYN followed by retransmissions with no reply means something between the node and the hub is silently dropping it. That's almost always a firewall. A SYN answered by a reset means the packet got there and nothing is listening on that port — the hub function is off, the service is down, or the hub is listening on a different port than the URI says.

3. Did the TLS handshake complete, or close immediately?

If you see ClientHello, ServerHello, a little encrypted traffic and then the connection closes within a second or so, repeating on every reconnect attempt, one side rejected the other. That's a certificate or authentication problem: expired certificate, wrong CA, clock out, or a firewall inspecting TLS and substituting its own certificate.

4. Did the WebSocket upgrade happen?

Only visible with keys. Without them, a session that survives the handshake and carries a few records before closing is a hint the problem is above TLS — an upgrade or BACnet-level refusal. Check the device status next.

5. Connect-Accept or NAK?

With keys: bscvlc.function == 6 shows Connect-Requests, and the answer is either Connect-Accept or a BVLC-Result NAK with an error code. A NAK for a duplicate VMAC is the classic cloned-config fault.

6. Are heartbeats flowing?

A healthy idle connection is a long-lived TCP session with small encrypted records in both directions every so often. If the session instead dies on a regular cycle and reconnects, suspect something in the path forgetting idle connections.

Symptom table

What you seeMost likely causeWhat to do
DNS query, no answer or “no such name”Hub name in the URI doesn't resolve from the node's networkCheck the record with IT, check the node's DNS server setting, or use the IP in the URI if that's the site standard.
SYN, retransmissions, no replyFirewall dropping the hub portGive IT the exact source, destination and TCP port. Confirm the port matches the URI.
SYN answered with RSTNothing listening on that portCheck the hub function is enabled and running, and which port it's actually on.
Handshake starts, connection closes straight away, repeatsCertificate: expired, wrong CA, or device clock wrongRead the certificate dates and issuer on both ends; check the clock. See the certificates article.
Everything failed at once after a firewall changeFirewall TLS inspection replacing the hub's certificateAsk IT to exempt the SC flows from inspection.
Works, then drops every few minutes, reconnectsFirewall or NAT idle timeout shorter than the heartbeat intervalRaise the idle timeout for these flows, or shorten the heartbeat so it beats the timeout.
All nodes connected to the failover hubPrimary hub down, unreachable, or its certificate or port wrongTroubleshoot the primary as if it were one node. The site works, but it has no redundancy left.
One node's Connect-Request NAKed, or two devices knocking each other offDuplicate VMAC (or UUID) from a cloned configurationRegenerate the SC identity on the copied device.
SC device still sending UDP 47808 broadcastsOld BACnet/IP port left enabled after migrationDisable it if it's not meant to be there, and check the device isn't reachable by both paths.

Notice the split: rows one to three are network faults, visible in clear text. Rows four and five are trust faults, visible only as a pattern. The rest are behaviour over time. You can get a long way just by deciding which group you're in.

Useful display filters

FilterWhat it shows
tcp.port == 443Traffic to or from the hub port. Change the number to whatever is in the hub URI.
tcp.flags.reset == 1Resets. On a SYN, it means nothing is listening.
tcp.analysis.retransmissionRetransmitted segments, including unanswered SYNs.
tls.handshake.type == 1ClientHellos — one per connection attempt. Count them to see how often a node is retrying.
dnsName lookups, including the hub name.
bscvlcDecoded BVLC-SC (keys required).
bscvlc.function == 6Connect-Requests (keys required).

With decryption, fields like bscvlc.orig_virtual_address, bscvlc.dest_virtual_address, bscvlc.connect_uuid, bscvlc.result, bscvlc.error_code and bscvlc.hub_conn_state let you filter to one node, find NAKs, or check which hub the Advertisements report.

Counting ClientHellos is underrated. A node with a certificate problem retries on its reconnect timer, which is configurable and typically backs off from seconds to minutes. A steady drip of ClientHellos from one address, each followed by a quick close, is a fingerprint you can spot from across the room.

Read the device before the wire

Honestly, on most SC calls I don't open a capture first. The SC Network Port object and the device's SC status page usually tell me more, faster:

  • Hub connection state — connected to primary, failover, or nothing.
  • The configured hub URIs — check the host and port against what the hub actually uses. A typo here explains a surprising number of calls.
  • Failed-connection records, where the device keeps them, often with a reason or error code and a timestamp.
  • Certificate details — issuer and validity dates.
  • The device clock.

Do the same on the hub device. Its view of which nodes are connected, and which were refused, is often the fastest way to find the one device that's different. The capture is how you prove which stage fails when the status pages don't agree, or when you need to show IT evidence.

Firewall TLS inspection

This one deserves its own section, because it's the fault that isn't your fault and looks exactly like yours.

Many corporate firewalls decrypt and re-encrypt TLS so they can inspect it. To do that, the firewall presents its own certificate to the client in place of the real server's. For a web browser on a managed laptop, that works because the laptop trusts the firewall's CA. A BACnet/SC node doesn't. It sees a certificate that wasn't signed by the site CA and refuses the connection — which is exactly what mutual authentication is supposed to do.

The tell is timing: every SC connection crossing that firewall fails at once, right after a firewall upgrade or policy change, with the handshake-then-close pattern. Nodes on the same side as the hub keep working. The fix is on IT's side: exempt the SC flows from inspection. Have that conversation with the source, destination and port in hand — segmentation and talking to IT covers how to ask.

A short checklist

  • Read the node's SC status and the hub's connection list first.
  • Check the URI: host, port, and that DNS resolves it from the node's network.
  • Capture on the hub port and find the first stage that fails.
  • Short handshake-then-close: certificates and clocks. No SYN reply: firewall. RST: nothing listening.
  • Regular drops: idle timeouts. Everyone on failover: the primary hub.
  • Keep the BAS Port Reference handy for the other ports on the same network.

If you're planning a site rather than fixing one, the rollout planning article is about avoiding most of this table in the first place. And if a fault looks less like a misconfiguration and more like someone else's hands on your system, stop and read security incident first steps before you change anything.

Go deeper

The layer-by-layer method, applied to every building protocol

Finding the first layer that fails is the whole method, on SC or anywhere else. BAS Communication teaches it across BACnet, Modbus, LonWorks, OPC UA and gateways, written for the tech with the laptop open.

Get BAS Communication — A Field Reference

Found a wrong number or a broken link? Tell me and I’ll fix it.