Kommunikationstreiber für den Datenaustausch mit S7-1200/1500 Steuerungen.
Dies ist aktuell ein Entwicklungsstand und nicht für den Produktiveinsatz vorgesehen.
Ziel ist es, einen Kommunikationstreiber zu entwickeln, welcher den Zugriff auf den Variablenhaushalt von S7 1200/1500 Steuerungen über den symbolischen Zugriff auf sogenannte "optimierte" Bereiche erlaubt.
Diese Implementierung ist vollständig in C# verfasst. Für die TLS-Verschlüsselung wird die OpenSSL-Bibliothek verwendet.
Der Kommunikationstreiber unterstützt ausschließlich CPUs mit einer Firmware welche die sichere Kommunikation über das TLS-Protokoll erlaubt. Das wären nach aktuellem Wissensstand
- S7 1200 mit einer Firmware >= V4.3 (TLS 1.3 ab V4.5)
- S7 1500 mit einer Firmware >= V2.9
Wichtig ist dabei, dass nicht nur nur eine CPU mit entsprechender Firmware vorhanden ist, sondern auch in der Entwicklungsumgebung mit der ensprechenden Version projektiert wurde. Das ist nur mit einer TIA-Portal Version >= V17 möglich.
Für die TLS-Kommunikation wird OpenSSL verwendet. Ist OpenSSL in der entsprechenden Version installiert, dann sollte ein entsprechender Systempfad zum Installationsverzeichnis eingetragen sein. Die notwendigen dlls sind aber auch im Projekt abgelegt, und werden im Buildprozess in der notwendigen Version (x86 oder x64) in das Ausgabeverzeichnis kopiert. Die notwendigen dlls mit Dateinamen je nach verwendetem Betriebssystem:
Für 32 Bit (x86):
- libcrypto-3.dll
- libssl-3.dll
Für 64 Bit (x64):
- libcrypto-3-x64.dll
- libssl-3-x64.dll
Mit folgenden Geräten wurde bisher erfolgreich getestet:
- S7 1211 mit Firmware V4.5
- TIA Plcsim V17 (mit Nettoplcsim)
- TIA Plcsim V18 (mit Nettoplcsim)
Aufgrund der Verschlüsselung können die übertragenen Daten ohne weitere Informationen mit Wireshark nicht mehr eingesehen werden. Zur Treiberentwicklung ist im Projekt eine Funktion integriert, welche die ausgehandelten Secrets in eine Textdatei (key_YYYYMMDD_hhmmss.log) ausgibt. Mit diesen Informationen ist es Wireshark möglich die Kommunikation zu entschlüsseln und darzustellen. Wichtig ist dabei, dass die Aufzeichnung den TLS-Verbindungsaufbau enthalten muss!
Um Wireshark diese Information verfügbar zu machen, existieren zwei Möglichkeiten:
- Die Log-Datei in ein Verzeichnis abzulegen und Wireshark dieses bekannt zu machen. Dazu in Wireshark Menü → Einstellungen aufrufen. Unter Protocols den Punkt TLS anwählen, und im Feld (Pre)-Master-Secret log filename die entsprechende Datei auswählen
- Die Secrets direkt in die Wireshark-Aufzeichnung integrieren
Zur Weitergabe an andere Personen zur Analyse, ist Punkt 2 zu bevorzugen, da alles notwendige in einer Aufzeichnung vorhanden ist. Die Integration geschieht über das Programm "editcap.exe" im Wireshark Installationsverzeichnis. Dazu muss eine Aufzeichnung in Wireshark mit der Endung .pcapng gespeichert werden.
Über die Eingabeaufforderung werden mit folgender Anweisung in die Aufzeichnung "test-capture.pcapng" die Secrets aus "key.log" integriert, und in der Datei "test-capture-with-keys.pcapng" gespeichert. Wird letztere Datei dann in Wireshark geöffnet, kann die Kommunikation dort entschlüsselt, dekodiert und dem Protokoll entsprechend dargestellt werden. Die key.log kann bei Bedarf anschließend gelöscht werden.
"C:\Program Files\Wireshark\editcap.exe" --inject-secrets tls,key.log test-capture.pcapng test-capture-with-keys.pcapng
Zur Vereinfachung habe ich ein kleines Hilfsprogramm mit einer grafischen Oberfläche geschrieben, auf das die Dateien per Drag&Drop gezogen werden können, und das auf Tastendruck editcap aufruft. Das Programm ist hier verfügbar:
https://github.com/thomas-v2/PcapKeyInjector
Damit Wireshark das S7comm-Plus Protokoll dekodieren kann, ist die entsprechende dll in das Wireshark Installationsverzeichnis abzulegen. Näheres dazu, und Download der dll bei Sourceforge unter:
https://sourceforge.net/projects/s7commwireshark/
Bei einigen Datentypen ist es notwendig, zur Verarbeitung der Antwort der SPS den Typ vorab zu kennen, um ihn in ein sinnvollen Datentyp in .Net zu konvertieren. Dazu wird die PlcTag Klasse bereitgestellt.
In der Tabelle sind alle in der SPS zur Zeit (TIA V18) möglichen Datentypen aufgeführt, mit dem Datentyp in dem sie auf dem Netzwerk im S7comm-Plus-Protokoll übertragen werden, sowie welchen .Net Datentyp in den PlcTag-Klassen daraus resultiert.
Supported | PLC Datentyp | PLC Kategorie | PLC Info | Netzwerk Datentyp | .Net Datentyp PlcTag | Sonstiges |
---|---|---|---|---|---|---|
✓ | AOM_IDENT | Hardwaredatentypen | ValueDWord | PlcTagDWord -> uint | ||
✓ | Any | Zeiger | Parameter | ValueUSIntArray[10] | byte[10] | |
✓ | Array[n..m] | Zugriff auf Einzelelemente direkt möglich | ||||
✓ | Block_FB | Parametertypen | Parameter | ValueUInt | PlcTagUInt -> ushort | |
✓ | Block_FC | Parametertypen | Parameter | ValueUInt | PlcTagUInt -> ushort | |
✓ | Bool | Binärzahlen | ValueBool | bool | ||
✓ | Byte | Bitfolgen | ValueByte | byte | ||
✓ | CONN_ANY | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | CONN_OUC | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | CONN_PRG | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | CONN_R_ID | Hardwaredatentypen | ValueDWord | PlcTagDWord -> uint | ||
✓ | CREF | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | Char | Zeichenfolgen | ValueUSInt | char | Encoding Voreinstellung ISO-8859-1 für non-ASCII | |
✓ | Counter | Parametertypen | Parameter | ValueUInt | PlcTagUInt -> ushort | |
✓ | Date | Datum und Uhrzeit | ValueUInt | DateTime | TODO: Nur Datum gültig! | |
✓ | Date_And_Time | Datum und Uhrzeit | ValueUSIntArray[8] | DateTime | ||
✓ | DB_ANY | Hardwaredatentypen | ValueUInt | PlcTagUInt -> ushort | ||
✓ | DB_DYN | Hardwaredatentypen | ValueUInt | PlcTagUInt -> ushort | ||
✓ | DB_WWW | Hardwaredatentypen | ValueUInt | PlcTagUInt -> ushort | ||
✓ | DInt | Ganzzahlen | ValueDInt | int | ||
✓ | DTL | Datum und Uhrzeit | ValueStruct / packed | DateTime + uint (for ns) | Nanosekunden extern, da kein .Net Typ mit ns. Experimental! | |
✓ | DWord | Bitfolgen | ValueDWord | uint | ||
✓ | EVENT_ANY | Hardwaredatentypen | ValueDWord | PlcTagDWord -> uint | ||
✓ | EVENT_ATT | Hardwaredatentypen | ValueDWord | PlcTagDWord -> uint | ||
✓ | EVENT_HWINT | Hardwaredatentypen | ValueDWord | PlcTagDWord -> uint | ||
✓ | ErrorStruct | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | |||
✓ | HW_ANY | Hardwaredatentypen | ValueWord | |||
✓ | HW_DEVICE | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_DPMASTER | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_DPSLAVE | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_HSC | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_IEPORT | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_INTERFACE | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_IO | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_IOSYSTEM | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_MODULE | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_PTO | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_PWM | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | HW_SUBMODULE | Hardwaredatentypen | ValueWord | PlcTagWord -> ushort | ||
✓ | IEC_COUNTER | Systemdatentypen | ValueStruct / packed | 33554462, Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_DCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_LCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_LTIMER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_SCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_TIMER | Systemdatentypen | ValueStruct / packed | 33554463, Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_UCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_UDCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_ULCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | IEC_USCOUNTER | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | Int | Ganzzahlen | ValueInt | short | ||
✓ | LDT | Datum und Uhrzeit | ValueTimestamp | ulong | ||
✓ | LInt | Ganzzahlen | ValueLInt | long | ||
✓ | LReal | Gleitpunktzahlen | ValueLReal | double | ||
✓ | LTime | Zeiten | ValueTimespan | long | Anzahl ns | |
✓ | LTime_Of_Day (LTOD) | Datum und Uhrzeit | ValueULInt | ulong | Anzahl ns seit 00:00:00 Uhr | |
✓ | LWord | Bitfolgen | ValueLWord | ulong | ||
✓ | NREF | Systemdatentypen | ValueStruct / packed | Zugriff auf Einzelelemente direkt möglich | ||
✓ | OB_ANY | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_ATT | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_CYCLIC | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_DELAY | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_DIAG | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_HWINT | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_PCYCLE | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_STARTUP | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_TIMEERROR | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | OB_TOD | Hardwaredatentypen | ValueInt | PlcTagInt -> short | ||
✓ | PIP | Hardwaredatentypen | ValueUInt | PlcTagUInt -> ushort | ||
✓ | Pointer | Zeiger | Parameter | ValueUSIntArray[6] | byte[6] | |
✓ | PORT | Hardwaredatentypen | ValueUInt | PlcTagUInt -> ushort | ||
✓ | RTM | Hardwaredatentypen | ValueUInt | PlcTagUInt -> ushort | ||
✓ | Real | Gleitpunktzahlen | ValueReal | float | ||
✓ | Remote | Zeiger | Parameter | ValueUSIntArray[10] | PlcTagAny -> byte[10] | Identisch zu Any-Pointer |
✓ | S5Time | Zeiten | ValueWord | ushort, ushort | TODO: TimeBase, TimeValue. Vereinheitlichen? | |
✓ | SInt | Ganzzahlen | ValueSInt | sbyte | ||
✓ | String | Zeichenfolgen | ValueUSIntArray[stringlen + 2] | string | Encoding Voreinstellung ISO-8859-1 für non-ASCII | |
✓ | Struct | Zugriff auf Einzelelemente direkt möglich | ||||
✓ | Time | Zeiten | ValueDInt | int | Anzahl ms mit Vorzeichen | |
✓ | Time_Of_Day (TOD) | Datum und Uhrzeit | ValueUDInt | uint | Anzahl ms seit 00:00:00 Uhr | |
✓ | Timer | Parametertypen | Parameter | ValueUInt | PlcTagUInt -> ushort | |
✓ | UDInt | Ganzzahlen | ValueUDInt | uint | ||
✓ | UInt | Ganzzahlen | ValueUInt | ushort | ||
✓ | ULInt | Ganzzahlen | ValueULInt | ulong | ||
✓ | USInt | Ganzzahlen | ValueUSInt | byte | ||
✗ | Variant | Zeiger | Parameter | Erhält keine Adresse | ||
✓ | WChar | Zeichenfolgen | ValueUInt | char | ||
✓ | WString | Zeichenfolgen | ValueUIntArray[stringlen + 2] | string | ||
✓ | Word | Bitfolgen | ValueWord | ushort |
Soweit nicht anders vermerkt, gilt für alle Quellcodes die GNU Lesser General Public License, Version 3 oder später.
- Thomas Wiens - Initial work - thomas-v2