
C言語とlibmodbusを使用して書かれた、マルチスレッド対応のModbus/TCP検出スキャナーです。
libmodbus を使用して Modbus/TCP サービスを検出するためのマルチスレッド C スキャナです。
このスキャナは TCP ポート 502 が開いていることだけに依存しません。代わりに Modbus/TCP 接続を確立し、アプリケーション層の Modbus リクエストを送信します。有効な Modbus レスポンスが、Modbus サービスが存在することを示す主要な指標として使用されます。
Modbus は、PLC、RTU、HMI、SCADA システム、センサー、メーター、その他の産業用デバイスで一般的に使用される産業用通信プロトコルです。
Modbus/TCP は Modbus アプリケーションプロトコルを TCP 上で転送します。
標準の Modbus/TCP ポートは次のとおりです:
TCP/502
一般的な通信フローは次のとおりです:
Scanner
|
| TCP connection → 502
|
| Modbus/TCP request
v
Modbus Device
|
| Modbus/TCP response
v
Scanner
接続直後にバナーを提供するプロトコルとは異なり、Modbus/TCP は一般に、デバイスがアプリケーション層のレスポンスを生成する前に、クライアントが有効な Modbus リクエストを送信することを要求します。
スキャナは 2 段階で検出を実行します。
スキャナは次の場所への TCP 接続の確立を試みます:
<target>:502
接続を確立できない場合、ターゲットは Modbus/TCP に応答していないものとして扱われます。
ただし、TCP/502 ポートが開いているだけでは、Modbus の十分な証拠とは見なされません。
接続後、スキャナは libmodbus を使用して Modbus リクエストを送信します。
主要なプローブは次のとおりです:
modbus_read_input_registers(ctx, 0, 1, ®);
これにより、次の Modbus ファンクションコードが生成されます:
0x04 - Read Input Registers
このリクエストは、アドレス 0 から始まる 1 つの入力レジスタをターゲットに要求します。
ターゲットが有効な Modbus レスポンスを返した場合、スキャナはサービスが検出されたと見なします。
Modbus/TCP パケットは次のもので構成されます:
+----------------------+----------------------+
| MBAP Header | PDU |
+----------------------+----------------------+
MBAP Header:
+------------------+
| Transaction ID | 2 bytes
| Protocol ID | 2 bytes
| Length | 2 bytes
| Unit Identifier | 1 byte
+------------------+
PDU:
+------------------+
| Function Code | 1 byte
| Data | N bytes
+------------------+
MBAP ヘッダーは Modbus/TCP に固有です。
スキャナの最初のプローブはファンクションコード 0x04 を使用します。
代表的なリクエストは次のとおりです:
00 01 00 00 00 06 01 04 00 00 00 01
これを分解すると:
00 01 Transaction Identifier
00 00 Protocol Identifier
00 06 Length
01 Unit Identifier
04 Function Code
00 00 Starting Address
00 01 Quantity
00 01
トランザクションを識別します。
トランザクション識別子は通常 Modbus クライアントライブラリによって管理されるため、値は異なる場合があります。
00 00
値 0 は Modbus を識別します。
00 06
長さフィールドに続くバイト数を指定します。
01
ターゲットの Modbus ユニットを識別します。
04
ファンクションコード 0x04 は次のことを意味します:
Read Input Registers
00 00
スキャナはレジスタアドレス 0 から開始します。
00 01
スキャナは 1 つのレジスタを要求します。
リクエストに対する成功したレスポンスには、ファンクションコード 0x04 と要求されたレジスタデータが含まれます。
代表的なレスポンスは次のようになります:
00 01 00 00 00 05 01 04 02 00 00
これを分解すると:
00 01 Transaction Identifier
00 00 Protocol Identifier
00 05 Length
01 Unit Identifier
04 Function Code
02 Byte Count
00 00 Register Value
検出にとって重要な部分は、ターゲットが Modbus リクエストを正常に処理し、有効な Modbus アプリケーション層レスポンスを返すことです。
実際のレジスタ値はデバイスに依存します。
単に次のことを確認するだけでは:
TCP/502 = OPEN
サービスが Modbus であることを必ずしも証明しません。
ポート番号は慣例です。別のアプリケーションが TCP/502 で待ち受ける可能性があり、Modbus デバイスもその構成によって異なる動作をする場合があります。
したがって、スキャナは次を使用します:
TCP connectivity
+
Modbus protocol response
=
Modbus detection
これにより、アプリケーション層の検出は単純なポートスキャンよりも意味のあるものになります。
一部のデバイスは、レジスタ構成またはサポートされているファンクションコードのため、最初の 0x04 リクエストに応答しない場合があります。
したがって、スキャナは最初のリクエストが失敗した場合に 2 番目のリクエストを試みます:
modbus_read_bits(ctx, 0, 1, bits);
これはファンクションコードを使用します:
0x01 - Read Coils
代表的なリクエストは次のとおりです:
00 02 00 00 00 06 01 01 00 00 00 01
分解:
00 02 Transaction Identifier
00 00 Protocol Identifier
00 06 Length
01 Unit Identifier
01 Function Code
00 00 Starting Address
00 01 Quantity
スキャナは、いずれかの Modbus 操作が成功したレスポンスを受信したときに、ターゲットが検出されたと見なします。
Target IP
|
v
TCP connection
port 502
|
+------+------+
| |
Failed Connected
| |
v v
Ignore Function 0x04
|
+------+------+
| |
Valid Failed
| |
v v
MODBUS FOUND Function 0x01
|
+------+------+
| |
Valid Failed
| |
v v
MODBUS FOUND No detection
スキャナは、プロトコルフレームを手動で構築するのではなく、libmodbus を使用して Modbus/TCP パケットを構築および解析します。
主要な操作は次のとおりです:
modbus_read_input_registers(ctx, 0, 1, ®);
これが失敗した場合:
modbus_read_bits(ctx, 0, 1, bits);
その後、接続が閉じられ、libmodbus コンテキストが解放されます。
これにより、プロトコル処理は Modbus ライブラリ内に保持され、スキャナは次の処理を担当します:
スキャナは短い接続および応答タイムアウトを使用します:
#define TIMEOUT_SEC 2
これにより、到達不能または応答しない単一のホストがワーカーを過度に長くブロックするのを防ぎます。
産業用ネットワークには比較的応答が遅いデバイスが含まれる可能性があるため、タイムアウト値は環境に応じて調整する必要がある場合があります。
ターゲットは複数のワーカースレッドに分割されます。
例:
Thread 1 → targets 1–64
Thread 2 → targets 65–128
Thread 3 → targets 129–192
Thread 4 → targets 193–254
各ワーカーは独立して Modbus/TCP 検出を試みます。
これにより、各ターゲットを順番に待つのではなく、複数のホストを同時にテストできます。
肯定的な結果は、ターゲットがスキャナによって理解された Modbus リクエストに正常に応答したことを意味します。
これは必ずしも次のものを識別するわけではありません:
これらは別個のフィンガープリンティングまたは評価タスクです。
スキャナは主に Modbus/TCP サービス検出ツールです。
検出方法は意図的に保守的です。
デバイスが Modbus 対応であっても、次の場合には検出に失敗する可能性があります:
したがって:
No response ≠ Definitively not Modbus
これは、スキャナが試行したプローブを使用して成功したレスポンスを取得できなかったことを意味します。
必要な依存関係をインストールし、次のコマンドでコンパイルします:
make
または直接:
gcc -Wall -Wextra -O2 -o modbus modbus.c -lmodbus -lpthread
実行:
./modbus -i 192.168.1.0 -s /24 -t 10 -o results.txt
例:
[+] Modbus detected: 192.168.1.20:502
[+] Modbus detected: 192.168.1.42:502
[+] Scanned: 254 | Found: 2 Modbus
[+] Results saved to: results.txt
スキャナは、TCP ポート検出のみに依存するのではなく、実際のプロトコル対話を実行して Modbus/TCP サービスを検出します。
検出プロセスは次のとおりです:
Connect to TCP/502
↓
Send Modbus Function Code 0x04
↓
Receive valid Modbus response?
↓
YES → Modbus detected
|
NO
↓
Send Modbus Function Code 0x01
↓
Receive valid Modbus response?
↓
YES → Modbus detected
|
NO
↓
No detection
重要な原則は単純です:
ポートだけでなくプロトコルを検出します。