namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient; /// /// OPC UA Client (gateway) driver configuration. Bound from DriverConfig JSON at /// driver-host registration time. Models the settings documented in /// docs/v2/driver-specs.md §8. /// /// /// This driver connects to a REMOTE OPC UA server and re-exposes its address space /// through the local OtOpcUa server — the opposite direction from the usual "server /// exposes PLC data" flow. Tier A (pure managed, OPC Foundation reference SDK); universal /// protections cover it. /// public sealed class OpcUaClientDriverOptions { /// /// Remote OPC UA endpoint URL, e.g. opc.tcp://plc.internal:4840. Convenience /// shortcut for a single-endpoint deployment — equivalent to setting /// to a list with this one URL. When both are provided, /// the list wins and is ignored. /// public string EndpointUrl { get; init; } = "opc.tcp://localhost:4840"; /// /// Ordered list of candidate endpoint URLs for failover. The driver tries each in /// order at and on session drop; /// the first URL that successfully connects wins. Typical use-case: an OPC UA server /// pair running in hot-standby (primary 4840 + backup 4841) where either can serve /// the same address space. Leave unset (or empty) to use /// as a single-URL shortcut. /// public IReadOnlyList EndpointUrls { get; init; } = []; /// /// Per-endpoint connect-attempt timeout during the failover sweep. Short enough that /// cycling through several dead servers doesn't blow the overall init budget, long /// enough to tolerate a slow TLS handshake on a healthy server. Applied independently /// of which governs steady-state operations. /// public TimeSpan PerEndpointConnectTimeout { get; init; } = TimeSpan.FromSeconds(3); /// /// Security policy to require when selecting an endpoint. Either a /// enum constant or a free-form string (for /// forward-compatibility with future OPC UA policies not yet in the enum). /// Matched against EndpointDescription.SecurityPolicyUri suffix — the driver /// connects to the first endpoint whose policy name matches AND whose mode matches /// . When set to /// the driver picks any unsecured endpoint regardless of policy string. /// public OpcUaSecurityPolicy SecurityPolicy { get; init; } = OpcUaSecurityPolicy.None; /// Security mode. public OpcUaSecurityMode SecurityMode { get; init; } = OpcUaSecurityMode.None; /// Authentication type. public OpcUaAuthType AuthType { get; init; } = OpcUaAuthType.Anonymous; /// User name (required only for ). public string? Username { get; init; } /// Password (required only for ). public string? Password { get; init; } /// /// Filesystem path to the user-identity certificate (PFX/PEM). Required when /// is . The driver /// loads the cert + private key, which the remote server validates against its /// TrustedUserCertificates store to authenticate the session's user token. /// Leave unset to use the driver's application-instance certificate as the user /// token (not typical — most deployments have a separate user cert). /// public string? UserCertificatePath { get; init; } /// /// Optional password that unlocks when the PFX is /// protected. PEM files generally have their password on the adjacent key file; this /// knob only applies to password-locked PFX. /// public string? UserCertificatePassword { get; init; } /// Server-negotiated session timeout. Default 120s per driver-specs.md §8. public TimeSpan SessionTimeout { get; init; } = TimeSpan.FromSeconds(120); /// Client-side keep-alive interval. public TimeSpan KeepAliveInterval { get; init; } = TimeSpan.FromSeconds(5); /// Initial reconnect delay after a session drop. public TimeSpan ReconnectPeriod { get; init; } = TimeSpan.FromSeconds(5); /// /// When true, the driver accepts any self-signed / untrusted server certificate. /// Dev-only — must be false in production so MITM attacks against the opc.tcp /// channel fail closed. /// public bool AutoAcceptCertificates { get; init; } = false; /// /// Application URI the driver reports during session creation. Must match the /// subject-alt-name on the client certificate if one is used, which is why it's a /// config knob rather than hard-coded. /// public string ApplicationUri { get; init; } = "urn:localhost:OtOpcUa:GatewayClient"; /// /// Friendly name sent to the remote server for diagnostics. Shows up in the remote /// server's session-list so operators can identify which gateway instance is calling. /// public string SessionName { get; init; } = "OtOpcUa-Gateway"; /// Connect + per-operation timeout. public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(10); /// /// Root NodeId to mirror. Default null = ObjectsFolder (i=85). Set to /// a scoped root to restrict the address space the driver exposes locally — useful /// when the remote server has tens of thousands of nodes and only a subset is /// needed downstream. /// public string? BrowseRoot { get; init; } /// /// Cap on total nodes discovered during DiscoverAsync. Default 10_000 — /// bounds memory on runaway remote servers without being so low that normal /// deployments hit it. When the cap is reached discovery stops and a warning is /// written to the driver health surface; the partially-discovered tree is still /// projected into the local address space. /// public int MaxDiscoveredNodes { get; init; } = 10_000; /// /// Max hierarchical depth of the browse. Default 10 — deep enough for realistic /// OPC UA information models, shallow enough that cyclic graphs can't spin the /// browse forever. /// public int MaxBrowseDepth { get; init; } = 10; /// /// Per-subscription tuning knobs applied when the driver creates data + alarm /// subscriptions on the upstream session. Defaults preserve the previous hard-coded /// values so existing deployments see no behaviour change. /// public OpcUaSubscriptionDefaults Subscriptions { get; init; } = new(); /// /// Server-certificate validation knobs applied during the /// CertificateValidator.CertificateValidation callback. Surfaces explicit /// handling for revoked certs (always rejected, never auto-accepted), unknown /// revocation status (rejected only when /// is set), SHA-1 signature rejection, and minimum RSA key size. Defaults preserve /// existing behaviour wherever possible — the one tightening is /// =true /// since SHA-1 is spec-deprecated for OPC UA. /// public OpcUaCertificateValidationOptions CertificateValidation { get; init; } = new(); } /// /// Knobs governing the server-certificate validation callback. Plumbed onto /// rather than the top-level /// options to keep cert-related config grouped together. /// /// /// /// CRL discovery: the OPC UA SDK reads CRL files automatically from the /// crl/ sub-directory of each cert store (own, trusted, issuers). Drop the /// issuer's .crl in that folder and the SDK picks it up — no driver-side wiring /// required. When the directory is absent or empty, the SDK reports /// BadCertificateRevocationUnknown, which this driver gates with /// . /// /// /// /// Reject server certificates whose signature uses SHA-1. Default true — SHA-1 was /// deprecated by the OPC UA spec and is treated as a hard fail in production. Flip to /// false only for short-term interop with legacy controllers. /// /// /// When the SDK can't determine revocation status (no CRL present, or stale CRL), /// reject the cert if true; allow if false. Default false — many /// plant deployments don't run CRL infrastructure, and a hard-fail default would break /// them on first connection. Set true in environments with a managed PKI. /// /// /// Minimum RSA key size (bits) accepted. Certs with shorter keys are rejected. Default /// 2048 matches the current OPC UA spec floor; raise to 3072 or 4096 for stricter /// deployments. Non-RSA keys (ECC) bypass this check. /// public sealed record OpcUaCertificateValidationOptions( bool RejectSHA1SignedCertificates = true, bool RejectUnknownRevocationStatus = false, int MinimumCertificateKeySize = 2048); /// /// Tuning surface for OPC UA subscriptions created by . /// Lifted from the per-call hard-coded literals so operators can tune publish cadence, /// keep-alive ratio, and alarm-vs-data prioritisation without recompiling the driver. /// Defaults match the original hard-coded values (KeepAlive=10, Lifetime=1000, /// MaxNotifications=0 unlimited, Priority=0, MinPublishingInterval=50ms). /// /// /// Number of consecutive empty publish cycles before the server sends a keep-alive /// response. Default 10 — high enough to suppress idle traffic, low enough that the /// client notices a stalled subscription within ~5x the publish interval. /// /// /// Number of consecutive missed publish responses before the server tears down the /// subscription. Must be ≥3× per OPC UA spec; default 1000 /// gives ~100 keep-alives of slack which is conservative on flaky networks. /// /// /// Cap on notifications returned per publish response. 0 = unlimited (the OPC UA /// spec sentinel). Lower this to bound publish-message size on bursty servers. /// /// /// Subscription priority for data subscriptions (0..255). Higher = scheduled ahead of /// lower. Default 0 matches the SDK's default for ordinary tag subscriptions. /// /// /// Floor (ms) applied to publishingInterval requests. Sub-floor values are /// clamped up so wire-side negotiations don't waste round-trips on intervals the server /// will only round up anyway. Default 50ms. /// /// /// Subscription priority for the alarm subscription (0..255). Higher than /// by default (1 vs 0) so alarm publishes aren't starved during /// data-tag bursts. /// public sealed record OpcUaSubscriptionDefaults( int KeepAliveCount = 10, uint LifetimeCount = 1000, uint MaxNotificationsPerPublish = 0, byte Priority = 0, int MinPublishingIntervalMs = 50, byte AlarmsPriority = 1); /// OPC UA message security mode. public enum OpcUaSecurityMode { None, Sign, SignAndEncrypt, } /// /// OPC UA security policies recognized by the driver. Maps to the standard /// http://opcfoundation.org/UA/SecurityPolicy# URI suffixes the SDK uses for /// endpoint matching. /// /// /// and are deprecated per OPC UA /// spec v1.04 — they remain in the enum only for brownfield interop with older servers. /// Prefer , , or /// for new deployments. /// public enum OpcUaSecurityPolicy { /// No security. Unsigned, unencrypted wire. None, /// Deprecated (OPC UA 1.04). Retained for legacy server interop. Basic128Rsa15, /// Deprecated (OPC UA 1.04). Retained for legacy server interop. Basic256, /// Recommended baseline for current deployments. Basic256Sha256, /// Current OPC UA policy; AES-128 + SHA-256 + RSA-OAEP. Aes128_Sha256_RsaOaep, /// Current OPC UA policy; AES-256 + SHA-256 + RSA-PSS. Aes256_Sha256_RsaPss, } /// User authentication type sent to the remote server. public enum OpcUaAuthType { Anonymous, Username, Certificate, }