Address PR review feedback (3 unresolved threads)

* Docs/PacketCapture.md: removed the duplicate 'MCP tool reference' section, moved into Docs/McpServer.md where the rest of the MCP tool surface lives.
* Docs/PacketCaptureFileFormats.md: inlined into Docs/PacketCapture.md (as 'File format reference' section) and deleted the standalone file. Removed the link from Docs/README.md.
* Docs/MigrationGuide.md: removed the orphaned 'Packet capture diagnostics hooks' TOC entry (the corresponding section was already removed in 67e803c, the TOC entry was missed).
This commit is contained in:
Marc Schier
2026-06-08 08:15:00 +02:00
parent c781514ad5
commit daf3c8a8b2
5 changed files with 103 additions and 109 deletions
+16 -1
View File
@@ -20,10 +20,25 @@ The MCP server wraps the OPC UA .NET Standard client library, translating betwee
| **Configuration** | `GetConfiguration`, `SetConfiguration` | View/modify client settings for current session |
| **NodeSet Export** | `ExportNodeSet`, `ExportNodeSetPerNamespace` | Export address space to NodeSet2 XML |
| **Convenience** | `ReadValue`, `ReadValues`, `WriteValue`, `BrowseAll`, `CallMethod`, `ReadNode`, `Cancel` | Simplified high-level operations |
| **Packet Capture** | `list_interfaces`, `start_capture`, `stop_capture`, `list_captures`, `get_capture`, `capture_now`, `list_active_channels`, `dump_keys`, `decode_pcap_with_keys`, `summarize_service_calls`, `replay_pcap` | OPC UA-aware packet capture, offline decode, service-call summaries, replay |
All OPC UA types (NodeId, DataValue, Variant, StatusCode, etc.) are represented as JSON for LLM-friendly interaction.
The MCP server also includes an OPC UA packet-capture diagnostics category for capture, offline decode, service-call summaries, and replay. See [Packet Capture](PacketCapture.md) for the capture sources, keylog formats, and `list_interfaces` / `start_capture` / `decode_pcap_with_keys` / `replay_pcap` tool flow.
The packet-capture tools are described in detail in [Packet Capture](PacketCapture.md). For convenience the per-tool surface is:
| Tool | Description | Parameters |
|---|---|---|
| `list_interfaces` | Enumerates NICs available to SharpPcap. | None |
| `start_capture` | Starts a capture session. | `source`; optional interface, filter, endpoint, limits, folder |
| `stop_capture` | Stops an active session and finalizes artifacts. | `sessionId` |
| `list_captures` | Lists capture sessions. | Optional `state` |
| `get_capture` | Returns an artifact or formatted analysis. | `sessionId`, `format`, optional packet/partial controls |
| `capture_now` | Starts, waits, stops, and returns output. | Capture options plus output `format` |
| `list_active_channels` | Lists in-process secure channels with current tokens. | None |
| `dump_keys` | Emits keylog data. | Optional `sessionId`, `format`, `includeExpired` |
| `decode_pcap_with_keys` | Decodes an existing pcap and keylog offline. | `pcapPath`, `keylogPath`, `format`, optional `maxFrames` |
| `summarize_service_calls` | Reports service counts, latency, and errors. | `sessionId` or `pcapPath` + `keylogPath`, optional `top` |
| `replay_pcap` | Replays as a mock server or mock client. | `pcapPath`, `keylogPath`, `mode`, endpoints, `speed` |
## Resources
-1
View File
@@ -70,7 +70,6 @@
- [New `INodeCache.InvalidateNode` member](#new-inodecacheinvalidatenode-member)
- [Time and Timer abstraction (`TimeProvider`)](#time-and-timer-abstraction-timeprovider)
- [Subscriptions and Transports](#subscriptions-and-transports)
- [Packet capture diagnostics hooks](#packet-capture-diagnostics-hooks)
- [Durable subscriptions and reshaped Subscription tree](#durable-subscriptions-and-reshaped-subscription-tree)
- [PubSub](#pubsub)
- [Reverse connect](#reverse-connect)
+87 -17
View File
@@ -117,25 +117,95 @@ Every stack-supported profile can be decoded because the offline decoder reuses
- `opc.tcp` reverse connect: full support; the TCP stream is decoded through the same Part 6 framing.
- `opc.https`: best-effort. The pcap can be captured, but decoding encrypted TLS payloads requires an external TLS keylog such as `SSLKEYLOGFILE`.
## MCP tool reference
| Tool | Description | Parameters |
|---|---|---|
| `list_interfaces` | Enumerates NICs available to SharpPcap. | None |
| `start_capture` | Starts a capture session. | `source`; optional interface, filter, endpoint, limits, folder |
| `stop_capture` | Stops an active session and finalizes artifacts. | `sessionId` |
| `list_captures` | Lists capture sessions. | Optional `state` |
| `get_capture` | Returns an artifact or formatted analysis. | `sessionId`, `format`, optional packet/partial controls |
| `capture_now` | Starts, waits, stops, and returns output. | Capture options plus output `format` |
| `list_active_channels` | Lists in-process secure channels with current tokens. | None |
| `dump_keys` | Emits keylog data. | Optional `sessionId`, `format`, `includeExpired` |
| `decode_pcap_with_keys` | Decodes an existing pcap and keylog offline. | `pcapPath`, `keylogPath`, `format`, optional `maxFrames` |
| `summarize_service_calls` | Reports service counts, latency, and errors. | `sessionId` or `pcapPath` + `keylogPath`, optional `top` |
| `replay_pcap` | Replays as a mock server or mock client. | `pcapPath`, `keylogPath`, `mode`, endpoints, `speed` |
## File format reference
See [PacketCaptureFileFormats.md](PacketCaptureFileFormats.md) for `.uakeys.json`, `.uakeys.txt`, pcap synthesis, and Wireshark interop details.
The library writes two artifacts per session: a pcap of the captured chunks and a keylog of the activated tokens.
### `.uakeys.json` format
`.uakeys.json` is JSON Lines (JSONL): one UTF-8 JSON object per line. Each object describes one activated OPC UA secure-channel token.
| Field | Type | Meaning |
|---|---|---|
| `channelId` | `uint32` | OPC UA secure-channel id. |
| `tokenId` | `uint32` | Secure-channel token id used in symmetric chunks. |
| `securityPolicyUri` | `string` | OPC UA security policy URI. |
| `securityMode` | `string` | One of `None`, `Sign`, or `SignAndEncrypt`. |
| `createdAt` | `string` | Token creation time as ISO-8601 UTC. |
| `lifetimeMs` | `int` | Token lifetime in milliseconds. |
| `clientNonce` | base64 `string` | Client nonce for key derivation. |
| `serverNonce` | base64 `string` | Server nonce for key derivation. |
| `clientSigningKey` | base64 `string` | Client-to-server signing key; omitted for `None`. |
| `clientEncryptingKey` | base64 `string` | Client-to-server encryption key; omitted for `None`. |
| `clientInitializationVector` | base64 `string` | Client-to-server IV; omitted for `None`. |
| `serverSigningKey` | base64 `string` | Server-to-client signing key; omitted for `None`. |
| `serverEncryptingKey` | base64 `string` | Server-to-client encryption key; omitted for `None`. |
| `serverInitializationVector` | base64 `string` | Server-to-client IV; omitted for `None`. |
Worked example:
```json
{"channelId":1001,"tokenId":7,"securityPolicyUri":"http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256","securityMode":"SignAndEncrypt","createdAt":"2026-06-06T11:48:00Z","lifetimeMs":3600000,"clientNonce":"Y2xpZW50","serverNonce":"c2VydmVy","clientSigningKey":"MDEyMw==","clientEncryptingKey":"NDU2Nw==","clientInitializationVector":"ODlhYg==","serverSigningKey":"Y2RlZg==","serverEncryptingKey":"MDEyMw==","serverInitializationVector":"NDU2Nw=="}
```
For `SecurityMode=None`, key fields are omitted:
```json
{"channelId":1002,"tokenId":1,"securityPolicyUri":"http://opcfoundation.org/UA/SecurityPolicy#None","securityMode":"None","createdAt":"2026-06-06T11:49:00Z","lifetimeMs":3600000,"clientNonce":"","serverNonce":""}
```
### `.uakeys.txt` format
`.uakeys.txt` is a Wireshark-style, single-line keylog format. The file begins with this header:
```text
# OPC UA channel key log v1
```
Each record uses a single space as the field separator:
```text
OPCUA_CHANNEL <channelId-hex> <tokenId-hex> <securityPolicyUri> <securityMode> <client_signing_hex> <client_encrypting_hex> <client_iv_hex> <server_signing_hex> <server_encrypting_hex> <server_iv_hex>
```
Hex values are uppercase with no separators. `-` denotes a null or empty field. Lines beginning with `#` are comments.
Worked example:
```text
# OPC UA channel key log v1
OPCUA_CHANNEL 000003E9 00000007 http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 SignAndEncrypt 30313233 34353637 38396162 63646566 30313233 34353637
OPCUA_CHANNEL 000003EA 00000001 http://opcfoundation.org/UA/SecurityPolicy#None None - - - - - -
```
### PCAP file format
Produced `.pcap` files use standard libpcap and are compatible with Wireshark and other readers.
NIC captures preserve real link-layer and IP/TCP headers. In-process taps write BSD-loopback records (`link_type=0`) and synthesize IP/TCP headers around each OPC UA chunk so dissectors see TCP traffic while the UA Secure Conversation chunk bytes remain exact.
For synthesized in-process captures:
- Client endpoint: `127.0.1.x`
- Server endpoint: `127.0.2.x`
- `x = channelId & 0xFF`
- Server port: `4840`
- Client port: `49152 + (channelId & 0x3FFF)`
The synthesized addresses are deterministic local analysis identifiers, not real endpoints.
### Wireshark interop
Wireshark's bundled OPC UA dissector can read the generated pcap files and understands HEL, ACK, OPN, MSG, and CLO framing. It cannot decrypt encrypted MSG or CLO chunks because it does not know the OPC UA symmetric keys.
The `.uakeys.txt` format is line-oriented and Wireshark-style so a future Lua plugin can:
1. Load `# OPC UA channel key log v1` files.
2. Index records by `channelId` and `tokenId`.
3. Match OPC UA symmetric chunks to a token id.
4. Pass the matching signing, encrypting, and IV material to the decoder.
This only defines the future plugin format; no delivery date is promised.
## Security considerations
-89
View File
@@ -1,89 +0,0 @@
# OPC UA Packet Capture File Formats
This document defines the keylog and pcap conventions used by `OPCFoundation.NetStandard.Opc.Ua.Bindings.Pcap`.
## `.uakeys.json` format
`.uakeys.json` is JSON Lines (JSONL): one UTF-8 JSON object per line. Each object describes one activated OPC UA secure-channel token.
| Field | Type | Meaning |
|---|---|---|
| `channelId` | `uint32` | OPC UA secure-channel id. |
| `tokenId` | `uint32` | Secure-channel token id used in symmetric chunks. |
| `securityPolicyUri` | `string` | OPC UA security policy URI. |
| `securityMode` | `string` | One of `None`, `Sign`, or `SignAndEncrypt`. |
| `createdAt` | `string` | Token creation time as ISO-8601 UTC. |
| `lifetimeMs` | `int` | Token lifetime in milliseconds. |
| `clientNonce` | base64 `string` | Client nonce for key derivation. |
| `serverNonce` | base64 `string` | Server nonce for key derivation. |
| `clientSigningKey` | base64 `string` | Client-to-server signing key; omitted for `None`. |
| `clientEncryptingKey` | base64 `string` | Client-to-server encryption key; omitted for `None`. |
| `clientInitializationVector` | base64 `string` | Client-to-server IV; omitted for `None`. |
| `serverSigningKey` | base64 `string` | Server-to-client signing key; omitted for `None`. |
| `serverEncryptingKey` | base64 `string` | Server-to-client encryption key; omitted for `None`. |
| `serverInitializationVector` | base64 `string` | Server-to-client IV; omitted for `None`. |
Worked example:
```json
{"channelId":1001,"tokenId":7,"securityPolicyUri":"http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256","securityMode":"SignAndEncrypt","createdAt":"2026-06-06T11:48:00Z","lifetimeMs":3600000,"clientNonce":"Y2xpZW50","serverNonce":"c2VydmVy","clientSigningKey":"MDEyMw==","clientEncryptingKey":"NDU2Nw==","clientInitializationVector":"ODlhYg==","serverSigningKey":"Y2RlZg==","serverEncryptingKey":"MDEyMw==","serverInitializationVector":"NDU2Nw=="}
```
For `SecurityMode=None`, key fields are omitted:
```json
{"channelId":1002,"tokenId":1,"securityPolicyUri":"http://opcfoundation.org/UA/SecurityPolicy#None","securityMode":"None","createdAt":"2026-06-06T11:49:00Z","lifetimeMs":3600000,"clientNonce":"","serverNonce":""}
```
## `.uakeys.txt` format
`.uakeys.txt` is a Wireshark-style, single-line keylog format. The file begins with this header:
```text
# OPC UA channel key log v1
```
Each record uses a single space as the field separator:
```text
OPCUA_CHANNEL <channelId-hex> <tokenId-hex> <securityPolicyUri> <securityMode> <client_signing_hex> <client_encrypting_hex> <client_iv_hex> <server_signing_hex> <server_encrypting_hex> <server_iv_hex>
```
Hex values are uppercase with no separators. `-` denotes a null or empty field. Lines beginning with `#` are comments.
Worked example:
```text
# OPC UA channel key log v1
OPCUA_CHANNEL 000003E9 00000007 http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 SignAndEncrypt 30313233 34353637 38396162 63646566 30313233 34353637
OPCUA_CHANNEL 000003EA 00000001 http://opcfoundation.org/UA/SecurityPolicy#None None - - - - - -
```
## PCAP file format
Produced `.pcap` files use standard libpcap and are compatible with Wireshark and other readers.
NIC captures preserve real link-layer and IP/TCP headers. In-process taps write BSD-loopback records (`link_type=0`) and synthesize IP/TCP headers around each OPC UA chunk so dissectors see TCP traffic while the UA Secure Conversation chunk bytes remain exact.
For synthesized in-process captures:
- Client endpoint: `127.0.1.x`
- Server endpoint: `127.0.2.x`
- `x = channelId & 0xFF`
- Server port: `4840`
- Client port: `49152 + (channelId & 0x3FFF)`
The synthesized addresses are deterministic local analysis identifiers, not real endpoints.
## Wireshark interop
Wireshark's bundled OPC UA dissector can read the generated pcap files and understands HEL, ACK, OPN, MSG, and CLO framing. It cannot decrypt encrypted MSG or CLO chunks because it does not know the OPC UA symmetric keys.
The `.uakeys.txt` format is line-oriented and Wireshark-style so a future Lua plugin can:
1. Load `# OPC UA channel key log v1` files.
2. Index records by `channelId` and `tokenId`.
3. Match OPC UA symmetric chunks to a token id.
4. Pass the matching signing, encrypting, and IV material to the decoder.
This only defines the future plugin format; no delivery date is promised.
-1
View File
@@ -12,7 +12,6 @@ Here is a list of available documentation for different topics:
* Using the [Reverse Connect](ReverseConnect.md) for the UA-TCP transport.
* Support for the [TransferSubscriptions](TransferSubscription.md) service set.
* [Observability](Observability.md) support in the stack.
* Packet capture, dissection, and replay diagnostics are documented in [Packet Capture](PacketCapture.md); the companion [Packet Capture File Formats](PacketCaptureFileFormats.md) page defines the `.uakeys.json`, `.uakeys.txt`, and pcap conventions.
* Support for [WellKnownRoles & RoleBasedUserManagement](RoleBasedUserManagement.md).
* Pluggable [Identity Providers](IdentityProviders.md) — interfaces (`IClientIdentityProvider`, `IUserTokenAuthenticator`, `IAccessTokenProvider`, `ITokenIssuer`, `IIdentityClaims`) plus the OPC 10000-6 §6.5.2.2 `IssuerEndpointUrl` JSON parser for OAuth2 / OIDC / Entra / JWT flows.
* Support for [ECC Certificates](EccProfiles.md).