← Articles
Networking/6 min read/ views

Getting a Legacy OPC DA Server Through DCOM Without Losing a Day to It

Why OPC Classic (DA/HDA) links fail across DCOM — RPC endpoint mapper on 135, dynamic port ranges, server identity — and the fastest way through it.

NetworkingOPC UATroubleshootingSCADA

You inherit a plant with a working OPC server. It's a KEPServerEX or Matrikon box sitting next to the PLCs, and the old SCADA read from it fine for years. Now the new SCADA node is on a different machine, you point its OPC DA client at the server, browse for tags, and get back 0x800706BA — The RPC server is unavailable. Or worse, it browses, connects, and then throws 0x80070005 — Access is denied the moment you try to add an item. Nothing in the OPC server's own log explains it, because the failure never reached the OPC layer. It died in DCOM.

This is the tax on OPC Classic. DA, HDA, and A&E are COM interfaces, and the moment the client and server live on separate machines, COM becomes DCOM — Microsoft's remote object plumbing from the late 1990s, with all the authentication baggage that implies. The OPC Foundation moved to UA specifically to escape this. But you don't get to rewrite the field, so you learn to get DCOM out of your way.

What actually happens when a remote OPC DA client connects

There are two network conversations, and people only think about one of them.

First the client contacts the RPC endpoint mapper on TCP 135 on the server machine. This is the phone book. The client asks "where does the OPCEnum service / the OPC server object live?" and the mapper answers with a dynamically assigned port — by default somewhere in 49152–65535 on modern Windows, 1024–65535 on older builds. The client then opens a second connection to that dynamic port to actually talk to the object.

So a firewall rule that opens port 135 and nothing else gives you exactly the failure that fools everyone: browse works (it's endpoint-mapper traffic), then the real session can't connect because the dynamic port is blocked. 0x800706BA at connect time, after a successful browse, is this until proven otherwise.

The third thing people forget: DCOM authenticates both directions. The client authenticates to the server, and then the server authenticates back to the client to deliver callbacks — OPC DA data changes arrive as COM callbacks, not polls. If the two machines can't agree on an identity for that reverse call (different local accounts, no matching password, no domain trust), you get a connection that reads on demand but never delivers subscription updates, or an Access is denied that only shows up under load.

The checklist that fixes most of them

Work it in this order. Don't skip to firewall rules before the accounts line up.

  1. Install the OPC Core Components on the client machine. The OPCEnum.exe service and the proxy/stub DLLs (opcproxy.dll, opccomn_ps.dll) have to exist on both ends. The OPC Foundation redistributable installs them. A client box that never had an OPC server installed usually doesn't have them, and browsing silently returns nothing.

  2. Make the identities match. The reliable pattern on non-domain machines is a local account with the same username and password on both boxes — for example opcuser / same password, member of a group you'll grant DCOM rights to. On a domain, use a domain service account. This is the single most common root cause of the "reads but no updates" symptom, and it's the fix DCOMCNFG can't do for you.

  3. Set the server's DCOM identity deliberately. In dcomcnfg → Component Services → DCOM Config, find the OPC server (and OPCEnum), Properties → Identity. Leaving it on "The launching user" means the server runs as whoever connected, and callback auth gets ambiguous. Set it to "This user" with your dedicated account so the process runs as one known identity every time.

  4. Grant Launch/Activation and Access permissions. On the server's DCOM Config entry, Security tab: add your account/group to both Launch and Activation Permissions and Access Permissions with Remote rights checked. Do the same on the machine-wide "My Computer" properties (COM Security) — a per-server grant with the machine-wide default still denying remote access gets you nowhere.

  5. Pin the dynamic port range, then open the firewall for it. In Component Services → My Computer → Properties → Default Protocols, edit "Connection-oriented TCP/IP" and set an explicit range — I use something small and boringly memorable like 5000–5020, enough for a handful of servers. Then the firewall rule is finite: TCP 135 plus TCP 5000–5020, both directions, scoped to the two host addresses. Reboot after changing the range; DCOM reads it at startup.

If DA data still won't flow after that, capture on the wire (tcpdump/Wireshark) and watch for the client's SYN to the dynamic port getting no answer — that's still a firewall or range problem, not OPC.

The lazy answer most integrators eventually take

Every hour spent hardening DCOM is an hour spent on a protocol you're trying to retire. And from a security standpoint DCOM is genuinely hard to lock down — IEC 62443 zone-and-conduit thinking does not want a fleet of dynamic RPC ports punched between a control zone and a supervisory zone. Auditors hate it, and they're right to.

So the move that saves the day is a COM tunneller: a small agent on the OPC server box and another on the client box that talk plain, single-port TCP between themselves and present a local OPC server/client to the software on each end. Cogent DataHub, Matrikon OPC Tunneller, and KEPServerEX's own tunnelling all do this. DCOM never crosses the network — it's local on each machine, where it's trivial. You open one TCP port, you can wrap it in TLS, and the reverse-callback authentication problem disappears because the callback is now local too. For anything crossing a subnet or a security boundary, this is what I reach for first now, before I open dcomcnfg at all.

And if you have any leverage over the roadmap: the real fix is to put an OPC UA wrapper in front of the DA server (most vendors ship one — KEPServerEX exposes UA and DA from the same runtime) and connect the new SCADA over UA. One TCP port, certificate-based trust, no DCOM. The legacy DA server keeps talking to the PLCs; only the northbound link changes. That's the version you want to be running in five years, and it's usually a configuration change, not a migration.

A last practical note: when you're stuck, prove which layer failed before you touch anything. telnet server 135 (or Test-NetConnection) confirms the endpoint mapper is reachable. If 135 answers but the session dies, it's the dynamic port or the callback identity — not the OPC server, not the tags, not the cable someone will inevitably ask you to reseat.