Add S7CommPlus V2 protocol support (TLS + IntegrityId)#646
Open
gijzelaerr wants to merge 18 commits intos7commplus-scaffoldingfrom
Open
Add S7CommPlus V2 protocol support (TLS + IntegrityId)#646gijzelaerr wants to merge 18 commits intos7commplus-scaffoldingfrom
gijzelaerr wants to merge 18 commits intos7commplus-scaffoldingfrom
Conversation
7f2dd2d to
61ba9f0
Compare
* Add S7CommPlus protocol scaffolding for S7-1200/1500 support Adds the snap7.s7commplus package as a foundation for future S7CommPlus protocol support, targeting all S7-1200/1500 PLCs (V1/V2/V3/TLS). Includes: - Protocol constants (opcodes, function codes, data types, element IDs) - VLQ encoding/decoding (Variable-Length Quantity, the S7CommPlus wire format) - Codec for frame headers, request/response headers, and typed values - Connection skeleton with multi-version support (V1/V2/V3/TLS) - Client stub with symbolic variable access API - 86 passing tests for VLQ and codec modules The wire protocol (VLQ, data types, object model) is the same across all protocol versions -- only the session authentication layer differs. The protocol version is auto-detected from the PLC's CreateObject response. Reference: thomas-v2/S7CommPlusDriver (C#, LGPL-3.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus server emulator, async client, and integration tests Server emulator (snap7/s7commplus/server.py): - Full PLC memory model with thread-safe data blocks - Named variable registration with type metadata - Handles CreateObject/DeleteObject session management - Handles Explore (browse registered DBs and variables) - Handles GetMultiVariables/SetMultiVariables (read/write) - Multi-client support (threaded) - CPU state management Async client (snap7/s7commplus/async_client.py): - asyncio-based S7CommPlus client with Lock for concurrent safety - Same API as sync client: db_read, db_write, db_read_multi, explore - Native COTP/TPKT transport using asyncio streams Updated sync client and connection to be functional for V1: - CreateObject/DeleteObject session lifecycle - Send/receive with S7CommPlus framing over COTP/TPKT - db_read, db_write, db_read_multi operations Integration tests (25 new tests): - Server unit tests (data blocks, variables, CPU state) - Sync client <-> server: connect, read, write, multi-read, explore - Async client <-> server: connect, read, write, concurrent reads - Data persistence across client sessions - Multiple concurrent clients with unique sessions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Clean up security-focused wording in S7CommPlus docstrings Reframe protocol version descriptions around interoperability rather than security vulnerabilities. Remove CVE references and replace implementation-specific language with neutral terminology. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: remove pytest-asyncio dependency, fix formatting Rewrite async tests to use asyncio.run() instead of @pytest.mark.asyncio since pytest-asyncio is not a project dependency. Also apply ruff formatting fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add pytest-asyncio dependency and use native async tests Add pytest-asyncio to test dependencies and set asyncio_mode=auto. Restore async test methods with @pytest.mark.asyncio instead of asyncio.run() wrappers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI and add S7CommPlus end-to-end tests Fix ruff formatting violations and mypy type errors in S7CommPlus code that caused pre-commit CI to fail. Add end-to-end test suite for validating S7CommPlus against a real S7-1200/1500 PLC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Enhance S7CommPlus connection with variable-length TSAP support and async client improvements Support bytes-type remote TSAP (e.g. "SIMATIC-ROOT-HMI") in ISOTCPConnection, extend S7CommPlus protocol handling, and improve async client and server emulator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add extensive debug logging to S7CommPlus protocol stack for real PLC diagnostics Adds hex dumps and detailed parsing at every protocol layer (ISO-TCP, S7CommPlus connection, client) plus 6 new diagnostic e2e tests that probe different payload formats and function codes against real hardware. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus wire format for real PLC compatibility Rewrite client payload encoding/decoding to use the correct S7CommPlus protocol format with ItemAddress structures (SymbolCrc, AccessArea, AccessSubArea, LIDs), ObjectQualifier, and proper PValue response parsing. Previously the client used a simplified custom format that only worked with the emulated server, causing ERROR2 responses from real S7-1200/1500 PLCs. - client.py: Correct GetMultiVariables/SetMultiVariables request format - async_client.py: Reuse corrected payload builders from client.py - codec.py: Add ItemAddress, ObjectQualifier, PValue encode/decode - protocol.py: Add Ids constants (DB_ACCESS_AREA_BASE, etc.) - server.py: Update to parse/generate the corrected wire format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix S7CommPlus LID byte offsets to use 1-based addressing S7CommPlus protocol uses 1-based LID byte offsets, but the client was sending 0-based offsets. This caused real PLCs to reject all db_read and db_write requests. Also fixes lint issues in e2e test file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add S7CommPlus session setup and legacy S7 fallback for data operations Implement the missing SetMultiVariables session handshake step that echoes ServerSessionVersion (attr 306) back to the PLC after CreateObject. Without this, PLCs reject data operations with ERROR2 (0x05A9). For PLCs that don't provide ServerSessionVersion or don't support S7CommPlus data operations, the client transparently falls back to the legacy S7 protocol. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Potential fix for code scanning alert no. 9: Binding a socket to all network interfaces Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Add CLI tools for direct PLC interaction (read, write, dump, info) Expand the snap7 CLI beyond snap7-server with subcommands for reading, writing, dumping, and inspecting PLCs directly from the terminal. Closes #621 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix CI: skip CLI tests when click is not installed Uses pytest.importorskip("click") so test collection doesn't fail in CI environments that only install the test dependencies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Rename CLI entry point from snap7 to s7, add discover hook Renames the CLI command from `snap7` to `s7` for a cleaner interface. Adds a hook to auto-register `s7 discover` when the discovery module is available, so both PRs compose cleanly when merged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds db_read_*/db_write_* convenience methods for bool, byte, int, uint, word, dint, udint, dword, real, lreal, string, and wstring types. Closes #617 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds 70 tests validating TPKT, COTP, and S7 protocol encoding against the specification at byte level. Closes #620 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add examples cookbook and troubleshooting documentation Based on analysis of 312 issues and discussions, the two biggest sources of user confusion are S7-1200/1500 configuration and data type handling. These new pages address the most common questions. examples.rst: rack/slot reference table, PLC address mapping guide, complete data types cookbook (BOOL through DATE_AND_TIME), memory areas, analog I/O, multi-variable read, and server setup for testing. troubleshooting.rst: error message reference table, S7-1200/1500 TIA Portal configuration steps, connection recovery patterns, timeout configuration, thread safety, and protocol limitations FAQ. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add PLC support matrix documentation Add a new page documenting which Siemens PLC families are supported, their protocol capabilities, PUT/GET configuration requirements, and alternatives for unsupported PLCs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds the snap7.s7commplus package as a foundation for future S7CommPlus protocol support, targeting all S7-1200/1500 PLCs (V1/V2/V3/TLS). Includes: - Protocol constants (opcodes, function codes, data types, element IDs) - VLQ encoding/decoding (Variable-Length Quantity, the S7CommPlus wire format) - Codec for frame headers, request/response headers, and typed values - Connection skeleton with multi-version support (V1/V2/V3/TLS) - Client stub with symbolic variable access API - 86 passing tests for VLQ and codec modules The wire protocol (VLQ, data types, object model) is the same across all protocol versions -- only the session authentication layer differs. The protocol version is auto-detected from the PLC's CreateObject response. Reference: thomas-v2/S7CommPlusDriver (C#, LGPL-3.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server emulator (snap7/s7commplus/server.py): - Full PLC memory model with thread-safe data blocks - Named variable registration with type metadata - Handles CreateObject/DeleteObject session management - Handles Explore (browse registered DBs and variables) - Handles GetMultiVariables/SetMultiVariables (read/write) - Multi-client support (threaded) - CPU state management Async client (snap7/s7commplus/async_client.py): - asyncio-based S7CommPlus client with Lock for concurrent safety - Same API as sync client: db_read, db_write, db_read_multi, explore - Native COTP/TPKT transport using asyncio streams Updated sync client and connection to be functional for V1: - CreateObject/DeleteObject session lifecycle - Send/receive with S7CommPlus framing over COTP/TPKT - db_read, db_write, db_read_multi operations Integration tests (25 new tests): - Server unit tests (data blocks, variables, CPU state) - Sync client <-> server: connect, read, write, multi-read, explore - Async client <-> server: connect, read, write, concurrent reads - Data persistence across client sessions - Multiple concurrent clients with unique sessions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reframe protocol version descriptions around interoperability rather than security vulnerabilities. Remove CVE references and replace implementation-specific language with neutral terminology. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite async tests to use asyncio.run() instead of @pytest.mark.asyncio since pytest-asyncio is not a project dependency. Also apply ruff formatting fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pytest-asyncio to test dependencies and set asyncio_mode=auto. Restore async test methods with @pytest.mark.asyncio instead of asyncio.run() wrappers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix ruff formatting violations and mypy type errors in S7CommPlus code that caused pre-commit CI to fail. Add end-to-end test suite for validating S7CommPlus against a real S7-1200/1500 PLC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…sync client improvements Support bytes-type remote TSAP (e.g. "SIMATIC-ROOT-HMI") in ISOTCPConnection, extend S7CommPlus protocol handling, and improve async client and server emulator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… diagnostics Adds hex dumps and detailed parsing at every protocol layer (ISO-TCP, S7CommPlus connection, client) plus 6 new diagnostic e2e tests that probe different payload formats and function codes against real hardware. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite client payload encoding/decoding to use the correct S7CommPlus protocol format with ItemAddress structures (SymbolCrc, AccessArea, AccessSubArea, LIDs), ObjectQualifier, and proper PValue response parsing. Previously the client used a simplified custom format that only worked with the emulated server, causing ERROR2 responses from real S7-1200/1500 PLCs. - client.py: Correct GetMultiVariables/SetMultiVariables request format - async_client.py: Reuse corrected payload builders from client.py - codec.py: Add ItemAddress, ObjectQualifier, PValue encode/decode - protocol.py: Add Ids constants (DB_ACCESS_AREA_BASE, etc.) - server.py: Update to parse/generate the corrected wire format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
S7CommPlus protocol uses 1-based LID byte offsets, but the client was sending 0-based offsets. This caused real PLCs to reject all db_read and db_write requests. Also fixes lint issues in e2e test file. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement the missing SetMultiVariables session handshake step that echoes ServerSessionVersion (attr 306) back to the PLC after CreateObject. Without this, PLCs reject data operations with ERROR2 (0x05A9). For PLCs that don't provide ServerSessionVersion or don't support S7CommPlus data operations, the client transparently falls back to the legacy S7 protocol. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements V2 protocol support for S7-1200/1500 PLCs with modern firmware: - TLS 1.3 activation between InitSSL and CreateObject - OMS exporter secret extraction for legitimation key derivation - Dual IntegrityId counters (read vs write) in V2 PDU headers - Password legitimation module (legacy SHA-1 XOR + new AES-256-CBC) - V2 server emulator with TLS and IntegrityId tracking - 39 new tests covering all V2 components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cryptography as optional dep: pip install python-snap7[s7commplus] - Implement connection.authenticate() with challenge/response flow - Wire up legitimation in client.connect(password=...) - Auto-detect legacy (SHA-1 XOR) vs new (AES-256-CBC) auth mode - Add legitimation protocol methods: get challenge, send response - 46 tests now (was 39), including AES roundtrip verification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
89275fb to
4fd702a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Architecture
V2 changes are minimal on top of the V1 scaffolding:
connection.py: TLS activation, IntegrityId insend_request()protocol.py:READ_FUNCTION_CODESset,LegitimationIdenumlegitimation.py: New module for password authenticationserver.py: V2 emulation for unit testsclient.py/async_client.py:passwordparameter (legitimation deferred)Test plan
🤖 Generated with Claude Code