mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 09:38:19 +00:00
Major revisions to Modbus analyzer support (not quite done yet).
- Renamed many data structures to align with most recent standard. - Reworked modbus events to make them more canonically "Bro". - Converted the Modbus analyzer to a simpler style for easier maintenance. - Modbus coil related events still don't work (I haven't finished the function for converting the data structures). - Modbus file record events remain incomplete.
This commit is contained in:
parent
a48963f82b
commit
009efbcb27
11 changed files with 1098 additions and 1139 deletions
|
@ -53,14 +53,6 @@ type string_vec: vector of string;
|
|||
## then remove this alias.
|
||||
type addr_vec: vector of addr;
|
||||
|
||||
|
||||
## A vector of integers.
|
||||
##
|
||||
## .. todo:: We need this type definition only for declaring builtin functions via
|
||||
## ``bifcl``. We should extend ``bifcl`` to understand composite types directly and
|
||||
## then remove this alias.
|
||||
type int_vec:vector of int;
|
||||
|
||||
## A table of strings indexed by strings.
|
||||
##
|
||||
## .. todo:: We need this type definition only for declaring builtin functions via
|
||||
|
@ -2465,6 +2457,16 @@ type bittorrent_benc_dir: table[string] of bittorrent_benc_value;
|
|||
## bt_tracker_response_not_ok
|
||||
type bt_tracker_headers: table[string] of string;
|
||||
|
||||
type ModbusCoils: vector of bool;
|
||||
type ModbusRegisters: vector of count;
|
||||
|
||||
type ModbusHeaders: record {
|
||||
tid: count;
|
||||
pid: count;
|
||||
uid: count;
|
||||
function_code: count;
|
||||
};
|
||||
|
||||
module SOCKS;
|
||||
export {
|
||||
## This record is for a SOCKS client or server to provide either a
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
@load ./consts
|
||||
@load ./main
|
67
scripts/base/protocols/modbus/consts.bro
Normal file
67
scripts/base/protocols/modbus/consts.bro
Normal file
|
@ -0,0 +1,67 @@
|
|||
|
||||
module Modbus;
|
||||
|
||||
export {
|
||||
## Standard defined Modbus function codes.
|
||||
const function_codes = {
|
||||
[0x01] = "READ_COILS",
|
||||
[0x02] = "READ_DISCRETE_INPUTS",
|
||||
[0x03] = "READ_HOLDING_REGISTERS",
|
||||
[0x04] = "READ_INPUT_REGISTERS",
|
||||
[0x05] = "WRITE_SINGLE_COIL",
|
||||
[0x06] = "WRITE_SINGLE_REGISTER",
|
||||
[0x07] = "READ_EXCEPTION_STATUS",
|
||||
[0x08] = "DIAGNOSTICS",
|
||||
[0x0B] = "GET_COMM_EVENT_COUNTER",
|
||||
[0x0C] = "GET_COMM_EVENT_LOG",
|
||||
[0x0F] = "WRITE_MULTIPLE_COILS",
|
||||
[0x10] = "WRITE_MULTIPLE_REGISTERS",
|
||||
[0x11] = "REPORT_SLAVE_ID",
|
||||
[0x14] = "READ_FILE_RECORD",
|
||||
[0x15] = "WRITE_FILE_RECORD",
|
||||
[0x16] = "MASK_WRITE_REGISTER",
|
||||
[0x17] = "READ_WRITE_MULTIPLE_REGISTERS",
|
||||
[0x18] = "READ_FIFO_QUEUE",
|
||||
[0x2B] = "ENCAP_INTERFACE_TRANSPORT",
|
||||
|
||||
# Machine/vendor/network specific functions
|
||||
[0x09] = "PROGRAM_484",
|
||||
[0x0A] = "POLL_484",
|
||||
[0x0D] = "PROGRAM_584_984",
|
||||
[0x0E] = "POLL_584_984",
|
||||
[0x12] = "PROGRAM_884_U84",
|
||||
[0x13] = "RESET_COMM_LINK_884_U84",
|
||||
[0x28] = "PROGRAM_CONCEPT",
|
||||
[0x7D] = "FIRMWARE_REPLACEMENT",
|
||||
[0x7E] = "PROGRAM_584_984_2",
|
||||
[0x7F] = "REPORT_LOCAL_ADDRESS",
|
||||
|
||||
# Exceptions
|
||||
[0x81] = "READ_COILS_EXCEPTION",
|
||||
[0x82] = "READ_DISCRETE_INPUTS_EXCEPTION",
|
||||
[0x83] = "READ_HOLDING_REGISTERS_EXCEPTION",
|
||||
[0x84] = "READ_INPUT_REGISTERS_EXCEPTION",
|
||||
[0x85] = "WRITE_SINGLE_COIL_EXCEPTION",
|
||||
[0x86] = "WRITE_SINGLE_REGISTER_EXCEPTION",
|
||||
[0x87] = "READ_EXCEPTION_STATUS_EXCEPTION",
|
||||
[0x8F] = "WRITE_MULTIPLE_COILS_EXCEPTION",
|
||||
[0x90] = "WRITE_MULTIPLE_REGISTERS_EXCEPTION",
|
||||
[0x94] = "READ_FILE_RECORD_EXCEPTION",
|
||||
[0x95] = "WRITE_FILE_RECORD_EXCEPTION",
|
||||
[0x96] = "MASK_WRITE_REGISTER_EXCEPTION",
|
||||
[0x97] = "READ_WRITE_MULTIPLE_REGISTERS_EXCEPTION",
|
||||
[0x98] = "READ_FIFO_QUEUE_EXCEPTION",
|
||||
} &default=function(i: count):string { return fmt("unknown-%d", i); } &redef;
|
||||
|
||||
const exception_codes = {
|
||||
[0x01] = "ILLEGAL_FUNCTION",
|
||||
[0x02] = "ILLEGAL_DATA_ADDRESS",
|
||||
[0x03] = "ILLEGAL_DATA_VALUE",
|
||||
[0x04] = "SLAVE_DEVICE_FAILURE",
|
||||
[0x05] = "ACKNOWLEDGE",
|
||||
[0x06] = "SLAVE_DEVICE_BUSY",
|
||||
[0x08] = "MEMORY_PARITY_ERROR",
|
||||
[0x0A] = "GATEWAY_PATH_UNAVAILABLE",
|
||||
[0x0B] = "GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND",
|
||||
} &default=function(i: count):string { return fmt("unknown-%d", i); } &redef;
|
||||
}
|
|
@ -1,12 +1,26 @@
|
|||
##! Base Modbus analysis script. For now it does not do anything else than
|
||||
##! activating the analyzer for connections on Modbus port 502/tcp.
|
||||
##! Base Modbus analysis script.
|
||||
|
||||
module Modbus;
|
||||
|
||||
export {
|
||||
|
||||
}
|
||||
|
||||
# Configure DPD and the packet filter.
|
||||
redef capture_filters += { ["modbus"] = "tcp port 502" };
|
||||
redef dpd_config += { [ANALYZER_MODBUS] = [$ports = set(502/tcp)] };
|
||||
redef likely_server_ports += { 502/tcp };
|
||||
|
||||
|
||||
event modbus_exception(c: connection, header: ModbusHeaders, code: count)
|
||||
{
|
||||
print fmt("%.6f %s There was an exception: %s", network_time(), c$id, exception_codes[code]);
|
||||
}
|
||||
|
||||
event modbus_message(c: connection, header: ModbusHeaders, is_orig: bool)
|
||||
{
|
||||
#if ( function_codes[header$function_code] in set("READ_MULTIPLE_REGISTERS", "READ_WRITE_REGISTERS", "WRITE_MULTIPLE_REGISTERS") )
|
||||
# return;
|
||||
|
||||
print fmt("%.6f %s %s: %s", network_time(), c$id, is_orig ? "request":"response", function_codes[header$function_code]);
|
||||
}
|
||||
|
|
|
@ -33,9 +33,9 @@ void ModbusTCP_Analyzer::Undelivered(int seq, int len, bool orig)
|
|||
interp->NewGap(orig, len);
|
||||
}
|
||||
|
||||
void ModbusTCP_Analyzer::EndpointEOF(TCP_Reassembler* endp)
|
||||
void ModbusTCP_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(endp);
|
||||
interp->FlowEOF(endp->IsOrig());
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
|
|
66
src/Modbus.h
66
src/Modbus.h
|
@ -1,9 +1,7 @@
|
|||
|
||||
#ifndef MODBUS_H
|
||||
#define MODBUS_H
|
||||
|
||||
#include "TCP.h"
|
||||
|
||||
#include "modbus_pac.h"
|
||||
|
||||
class ModbusTCP_Analyzer : public TCP_ApplicationAnalyzer {
|
||||
|
@ -15,7 +13,7 @@ public:
|
|||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual void EndpointEOF(TCP_Reassembler* endp);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new ModbusTCP_Analyzer(conn); }
|
||||
|
@ -23,40 +21,34 @@ public:
|
|||
// Put event names in this function
|
||||
static bool Available()
|
||||
{
|
||||
return modbus_read_coils_request
|
||||
|| modbus_read_coils_response
|
||||
|| modbus_read_input_discretes_request
|
||||
|| modbus_read_input_discretes_response
|
||||
|| modbus_read_multi_request
|
||||
|| modbus_read_multi_response
|
||||
|| modbus_read_input_request
|
||||
|| modbus_read_input_response
|
||||
|| modbus_write_single_request
|
||||
|| modbus_write_single_response
|
||||
|| modbus_write_coil_request
|
||||
|| modbus_write_coil_response
|
||||
|| modbus_force_coils_request
|
||||
|| modbus_force_coils_response
|
||||
|| modbus_read_reference_request
|
||||
|| modbus_read_reference_response
|
||||
|| modbus_read_single_reference_request
|
||||
|| modbus_read_single_reference_response
|
||||
|| modbus_write_reference_request
|
||||
|| modbus_write_reference_response
|
||||
|| modbus_write_single_reference
|
||||
|| modbus_write_multi_request
|
||||
|| modbus_write_multi_response
|
||||
|| modbus_mask_write_request
|
||||
|| modbus_mask_write_response
|
||||
|| modbus_read_write_request
|
||||
|| modbus_read_write_response
|
||||
|| modbus_read_FIFO_request
|
||||
|| modbus_read_FIFO_response
|
||||
|| modbus_read_except_request
|
||||
|| modbus_read_except_response
|
||||
|| modbus_exception
|
||||
|| modbus_request
|
||||
|| modbus_response;
|
||||
return modbus_message
|
||||
| modbus_exception
|
||||
| modbus_read_coils_request
|
||||
| modbus_read_coils_response
|
||||
| modbus_read_discrete_inputs_request
|
||||
| modbus_read_discrete_inputs_response
|
||||
| modbus_read_holding_registers_request
|
||||
| modbus_read_holding_registers_response
|
||||
| modbus_read_input_registers_request
|
||||
| modbus_read_input_registers_response
|
||||
| modbus_write_single_coil_request
|
||||
| modbus_write_single_coil_response
|
||||
| modbus_write_single_register_request
|
||||
| modbus_write_single_register_response
|
||||
| modbus_write_multiple_coils_request
|
||||
| modbus_write_multiple_coils_response
|
||||
| modbus_write_multiple_registers_request
|
||||
| modbus_write_multiple_registers_response
|
||||
| modbus_read_file_record_request
|
||||
| modbus_read_file_record_response
|
||||
| modbus_write_file_record_request
|
||||
| modbus_write_file_record_response
|
||||
| modbus_mask_write_register_request
|
||||
| modbus_mask_write_register_response
|
||||
| modbus_read_write_multiple_registers_request
|
||||
| modbus_read_write_multiple_registers_response
|
||||
| modbus_read_fifo_queue_request
|
||||
| modbus_read_fifo_queue_response;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
297
src/event.bif
297
src/event.bif
|
@ -6547,175 +6547,146 @@ event netflow_v5_header%(h: nf_v5_header%);
|
|||
## .. bro:see:: netflow_v5_record
|
||||
event netflow_v5_record%(r: nf_v5_record%);
|
||||
|
||||
## Event that passes request header only
|
||||
## Event for any function code whether or not it's supported.
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count%);
|
||||
|
||||
## Event that passes response header only
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count%);
|
||||
|
||||
## Event that passes modbus request function code =1
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_coils_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bcount: count%);
|
||||
|
||||
## Event that passes modbus request function code =2
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_input_discretes_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bcount: count%);
|
||||
|
||||
## Event that passes modbus request function code =3
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_multi_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, wcount: count, len: count%);
|
||||
|
||||
## Event that passes modbus request function code =4
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_input_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, wcount: count, len: count%);
|
||||
|
||||
## Event that passes modbus request function code =5
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_coil_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, onOff: count, other: count%);
|
||||
|
||||
## Event that passes modbus request function code =6
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, len: count, ref: count, value: count%);
|
||||
|
||||
## Event that passes modbus request function code =15
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_force_coils_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bitCount: count, byteCount: count, coils: string%);
|
||||
|
||||
## Event that passes modbus request function code=16
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_multi_request%(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, ref: count, wCount: count, bCount: count, len: count%);
|
||||
|
||||
## Event that passes modbus request function code=20
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_reference_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, refCount: count, t: int_vec%);
|
||||
|
||||
## Event that passes modbus request function code=20 for single reference
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_single_reference_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, refType: count, refNumber: count, wordCount: count%);
|
||||
|
||||
## Event that passes modbus request function code=21
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_reference_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, t: int_vec%);
|
||||
|
||||
## Event that passes modbus request/response function code=21 for single reference
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_reference%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, refType: count, refNumber: count, wordCount: count, t: int_vec%);
|
||||
|
||||
## Event that passes modbus request function code=22
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_mask_write_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, andMask: count, orMask: count%);
|
||||
|
||||
## Event that passes modbus request function code=23
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_write_request%(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, refRead: count, wcRead: count, refWrite: count, wcWrite: count, bCount: count, len: count%);
|
||||
|
||||
## Event that passes modbus request function code=24
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_FIFO_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count%);
|
||||
|
||||
## Event that passes modbus request function code=7
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_except_request%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, len: count%);
|
||||
|
||||
## Event that passes modbus response function code=1
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_coils_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, bcount: count, bits: string%);
|
||||
|
||||
## Event that passes modbus response function code=2
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_input_discretes_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, bcount: count, bits: string%);
|
||||
|
||||
## Event that passes modbus response function code=3
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_multi_response%(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, bCount: count, len: count%);
|
||||
|
||||
## Event that passes modbus response function code=4
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_input_response%(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, bCount: count, len: count%);
|
||||
|
||||
## Event that passes modbus request function code =5
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_coil_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, onOff: count, other: count%);
|
||||
|
||||
## Event that passes modbus response function code=6
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, len: count, ref: count, value: count%);
|
||||
|
||||
## Event that passes modbus response function code=15
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_force_coils_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bitCount: count%);
|
||||
|
||||
## Event that passes modbus response function code=16
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_multi_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, wcount: count, len: count%);
|
||||
|
||||
## Event that passes modbus response function code=20
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_reference_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, t: int_vec%);
|
||||
|
||||
## Event that passes modbus response function code=20 for single reference
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_single_reference_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, refType: count, t: int_vec%);
|
||||
|
||||
## Event that passes modbus response function code=21
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_reference_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, t: int_vec%);
|
||||
|
||||
## Event that passes modbus response function code=22
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_mask_write_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, andMask: count, orMask: count%);
|
||||
|
||||
## Event that passes modbus response function code=23
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_write_response%(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, bCount: count, len: count%);
|
||||
|
||||
## Event that passes modbus response function code=24
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_FIFO_response%(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, bcount: count%);
|
||||
|
||||
## Event that passes modbus response function code=7
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_except_response%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, status: count, len: count%);
|
||||
event modbus_message%(c: connection, header: ModbusHeaders, is_orig: bool%);
|
||||
|
||||
## Event that parses modbus exception
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_exception%(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, code: count%);
|
||||
event modbus_exception%(c: connection, header: ModbusHeaders, code: count%);
|
||||
|
||||
## Event that passes modbus request function code=1
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_coils_request%(c: connection, header: ModbusHeaders, start_address: count, quantity: count%);
|
||||
|
||||
## Event that passes modbus response function code=1
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_coils_response%(c: connection, header: ModbusHeaders, coils: ModbusCoils%);
|
||||
|
||||
## Event that passes modbus request function code=2
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_discrete_inputs_request%(c: connection, header: ModbusHeaders, start_address: count, quantity: count%);
|
||||
|
||||
## Event that passes modbus response function code=2
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_discrete_inputs_response%(c: connection, header: ModbusHeaders, coils: ModbusCoils%);
|
||||
|
||||
## Event that passes modbus request function code=3
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_holding_registers_request%(c: connection, header: ModbusHeaders, start_address: count, quantity: count%);
|
||||
|
||||
## Event that passes modbus response function code=3
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_holding_registers_response%(c: connection, header: ModbusHeaders, registers: ModbusRegisters%);
|
||||
|
||||
## Event that passes modbus request function code =4
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_input_registers_request%(c: connection, header: ModbusHeaders, start_address: count, quantity: count%);
|
||||
|
||||
## Event that passes modbus response function code=4
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_input_registers_response%(c: connection, header: ModbusHeaders, registers: ModbusRegisters%);
|
||||
|
||||
## Event that passes modbus request function code=5
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_coil_request%(c: connection, header: ModbusHeaders, start_address: count, on_off: count, other: count%);
|
||||
|
||||
## Event that passes modbus request function code=5
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_coil_response%(c: connection, header: ModbusHeaders, start_address: count, on_off: count, other: count%);
|
||||
|
||||
## Event that passes modbus request function code=6
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_register_request%(c: connection, header: ModbusHeaders, start_address: count, value: count%);
|
||||
|
||||
## Event that passes modbus response function code=6
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_single_register_response%(c: connection, header: ModbusHeaders, start_address: count, value: count%);
|
||||
|
||||
|
||||
## Event that passes modbus request function code=15
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_multiple_coils_request%(c: connection, header: ModbusHeaders, start_address: count, coils: ModbusCoils%);
|
||||
|
||||
## Event that passes modbus response function code=15
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_multiple_coils_response%(c: connection, header: ModbusHeaders, start_address: count, quantity: count%);
|
||||
|
||||
## Event that passes modbus request function code=16
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_multiple_registers_request%(c: connection, header: ModbusHeaders, start_address: count, registers: ModbusRegisters%);
|
||||
|
||||
## Event that passes modbus response function code=16
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_multiple_registers_response%(c: connection, header: ModbusHeaders, start_address: count, quantity: count%);
|
||||
|
||||
## Event that passes modbus request function code=20
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_file_record_request%(c: connection, header: ModbusHeaders%);
|
||||
|
||||
## Event that passes modbus response function code=20
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_file_record_response%(c: connection, header: ModbusHeaders%);
|
||||
|
||||
## Event that passes modbus request function code=21
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_file_record_request%(c: connection, header: ModbusHeaders%);
|
||||
|
||||
## Event that passes modbus response function code=21
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_write_file_record_response%(c: connection, header: ModbusHeaders%);
|
||||
|
||||
## Event that passes modbus request function code=22
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_mask_write_register_request%(c: connection, header: ModbusHeaders, start_address: count, and_mask: count, or_mask: count%);
|
||||
|
||||
## Event that passes modbus response function code=22
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_mask_write_register_response%(c: connection, header: ModbusHeaders, start_address: count, and_mask: count, or_mask: count%);
|
||||
|
||||
## Event that passes modbus request function code=23
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_write_multiple_registers_request%(c: connection, header: ModbusHeaders, read_start_address: count, read_quantity: count, write_start_address: count, write_registers: ModbusRegisters%);
|
||||
|
||||
## Event that passes modbus response function code=23
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_write_multiple_registers_response%(c: connection, header: ModbusHeaders, written_registers: ModbusRegisters%);
|
||||
|
||||
## Event that passes modbus request function code=24
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_fifo_queue_request%(c: connection, header: ModbusHeaders, start_address: count%);
|
||||
|
||||
## Event that passes modbus response function code=24
|
||||
##
|
||||
## TODO-Dina: Document event.
|
||||
event modbus_read_fifo_queue_response%(c: connection, header: ModbusHeaders, fifos: ModbusRegisters%);
|
||||
|
||||
## Raised for informational messages reported via Bro's reporter framework. Such
|
||||
## messages may be generated internally by the event engine and also by other
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,76 +6,67 @@
|
|||
# Useful references: http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
|
||||
# http://www.simplymodbus.ca/faq.htm
|
||||
|
||||
|
||||
analyzer ModbusTCP withcontext {
|
||||
connection: ModbusTCP_Conn;
|
||||
flow: ModbusTCP_Flow;
|
||||
};
|
||||
|
||||
connection ModbusTCP_Conn( bro_analyzer: BroAnalyzer) {
|
||||
upflow = ModbusTCP_Flow(true);
|
||||
downflow = ModbusTCP_Flow(false);
|
||||
};
|
||||
|
||||
enum function_codes {
|
||||
# Class 0
|
||||
READ_MULTIPLE_REGISTERS = 3,
|
||||
WRITE_MULTIPLE_REGISTERS = 16,
|
||||
|
||||
# Class 1
|
||||
READ_COILS = 1,
|
||||
READ_INPUT_DISCRETES = 2,
|
||||
READ_INPUT_REGISTERS = 4,
|
||||
WRITE_COIL = 5,
|
||||
WRITE_SINGLE_REGISTER = 6,
|
||||
READ_EXCEPTION_STATUS = 7,
|
||||
|
||||
# Class 2
|
||||
FORCE_MULTIPLE_COILS = 15,
|
||||
READ_GENERAL_REFERENCE = 20,
|
||||
WRITE_GENERAL_REFERENCE = 21,
|
||||
MASK_WRITE_REGISTER = 22,
|
||||
READ_WRITE_REGISTERS = 23,
|
||||
READ_FIFO_QUEUE = 24,
|
||||
# Standard functions
|
||||
READ_COILS = 0x01,
|
||||
READ_DISCRETE_INPUTS = 0x02,
|
||||
READ_HOLDING_REGISTERS = 0x03,
|
||||
READ_INPUT_REGISTERS = 0x04,
|
||||
WRITE_SINGLE_COIL = 0x05,
|
||||
WRITE_SINGLE_REGISTER = 0x06,
|
||||
READ_EXCEPTION_STATUS = 0x07,
|
||||
DIAGNOSTICS = 0x08,
|
||||
GET_COMM_EVENT_COUNTER = 0x0B,
|
||||
GET_COMM_EVENT_LOG = 0x0C,
|
||||
WRITE_MULTIPLE_COILS = 0x0F,
|
||||
WRITE_MULTIPLE_REGISTERS = 0x10,
|
||||
REPORT_SLAVE_ID = 0x11,
|
||||
READ_FILE_RECORD = 0x14,
|
||||
WRITE_FILE_RECORD = 0x15,
|
||||
MASK_WRITE_REGISTER = 0x16,
|
||||
READ_WRITE_MULTIPLE_REGISTERS = 0x17,
|
||||
READ_FIFO_QUEUE = 0x18,
|
||||
ENCAP_INTERFACE_TRANSPORT = 0x2B,
|
||||
|
||||
# Machine/vendor/network specific functions
|
||||
DIAGNOSTICS = 8,
|
||||
PROGRAM_484 = 9,
|
||||
POLL_484 = 10,
|
||||
GET_COMM_EVENT_COUNTERS = 11,
|
||||
GET_COMM_EVENT_LOG = 12,
|
||||
PROGRAM_584_984 = 13,
|
||||
POLL_584_984 = 14,
|
||||
REPORT_SLAVE = 17,
|
||||
PROGRAM_884_U84 = 18,
|
||||
RESET_COMM_LINK_884_U84 = 19,
|
||||
PROGRAM_CONCEPT = 40,
|
||||
FIRMWARE_REPLACEMENT = 125,
|
||||
PROGRAM_584_984_2 = 126,
|
||||
REPORT_LOCAL_ADDRESS = 127,
|
||||
PROGRAM_484 = 0x09,
|
||||
POLL_484 = 0x0A,
|
||||
PROGRAM_584_984 = 0x0D,
|
||||
POLL_584_984 = 0x0E,
|
||||
PROGRAM_884_U84 = 0x12,
|
||||
RESET_COMM_LINK_884_U84 = 0x13,
|
||||
PROGRAM_CONCEPT = 0x28,
|
||||
FIRMWARE_REPLACEMENT = 0x7D,
|
||||
PROGRAM_584_984_2 = 0x7E,
|
||||
REPORT_LOCAL_ADDRESS = 0x7F,
|
||||
|
||||
# Exceptions
|
||||
READ_MULTIPLE_REGISTERS_EXCEPTION = 0x83,
|
||||
WRITE_MULTIPLE_REGISTERS_EXCEPTION = 0x90,
|
||||
# Exceptions (not really function codes but they are used similarly)
|
||||
READ_COILS_EXCEPTION = 0x81,
|
||||
READ_INPUT_DISCRETES_EXCEPTION = 0x82,
|
||||
READ_DISCRETE_INPUTS_EXCEPTION = 0x82,
|
||||
READ_HOLDING_REGISTERS_EXCEPTION = 0x83,
|
||||
READ_INPUT_REGISTERS_EXCEPTION = 0x84,
|
||||
WRITE_COIL_EXCEPTION = 0x85,
|
||||
WRITE_SINGLE_COIL_EXCEPTION = 0x85,
|
||||
WRITE_SINGLE_REGISTER_EXCEPTION = 0x86,
|
||||
READ_EXCEPTION_STATUS_EXCEPTION = 0x87,
|
||||
FORCE_MULTIPLE_COILS_EXCEPTION = 0x8F,
|
||||
READ_GENERAL_REFERENCE_EXCEPTION = 0x94,
|
||||
WRITE_GENERAL_REFERENCE_EXCEPTION = 0x95,
|
||||
WRITE_MULTIPLE_COILS_EXCEPTION = 0x8F,
|
||||
WRITE_MULTIPLE_REGISTERS_EXCEPTION = 0x90,
|
||||
READ_FILE_RECORD_EXCEPTION = 0x94,
|
||||
WRITE_FILE_RECORD_EXCEPTION = 0x95,
|
||||
MASK_WRITE_REGISTER_EXCEPTION = 0x96,
|
||||
READ_WRITE_REGISTERS_EXCEPTION = 0x97,
|
||||
READ_WRITE_MULTIPLE_REGISTERS_EXCEPTION = 0x97,
|
||||
READ_FIFO_QUEUE_EXCEPTION = 0x98,
|
||||
};
|
||||
|
||||
# Main Modbus/TCP PDU
|
||||
type ModbusTCP_PDU(is_orig: bool) = case is_orig of {
|
||||
true -> request: ModbusTCP_RequestPDU;
|
||||
false -> response: ModbusTCP_ResponsePDU;
|
||||
} &byteorder = bigendian;
|
||||
type ModbusTCP_PDU(is_orig: bool) = record {
|
||||
header: ModbusTCP_TransportHeader;
|
||||
body: case is_orig of {
|
||||
true -> request: ModbusTCP_Request(header);
|
||||
false -> response: ModbusTCP_Response(header);
|
||||
};
|
||||
} &length=header.len+6, &byteorder=bigendian, &let {
|
||||
deliver: bool = $context.flow.deliver_message(header);
|
||||
};
|
||||
|
||||
type ModbusTCP_TransportHeader = record {
|
||||
tid: uint16; # Transaction identifier
|
||||
|
@ -85,374 +76,324 @@ type ModbusTCP_TransportHeader = record {
|
|||
fc: uint8; # MODBUS function code (see function_codes enum)
|
||||
};
|
||||
|
||||
type Reference(header: ModbusTCP_TransportHeader) = record {
|
||||
refType: uint8;
|
||||
refNumber: uint32;
|
||||
wordCount: uint16;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadSingleReferenceReq(header.tid, header.pid, header.uid, header.fc, refType, refNumber, wordCount);
|
||||
};
|
||||
|
||||
type ReferenceWithData (header: ModbusTCP_TransportHeader) = record {
|
||||
refType: uint8;
|
||||
refNumber: uint32;
|
||||
wordCount: uint16;
|
||||
registerValue: uint16[wordCount] &length = 2*wordCount; # TODO: check that the array length is calculated correctly
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteSingleReference(header.tid, header.pid, header.uid, header.fc, refType, refNumber, wordCount, this);
|
||||
};
|
||||
|
||||
type ReferenceResponse(header: ModbusTCP_TransportHeader)= record{
|
||||
byteCount: uint8;
|
||||
refType: uint8;
|
||||
registerValue: uint16[wordCount];
|
||||
} &let {
|
||||
wordCount : uint8 = byteCount/2;
|
||||
deliver: bool =$context.flow.deliver_ReadSingleReferenceRes(header.tid, header.pid, header.uid, header.fc, byteCount, refType, this);
|
||||
};
|
||||
|
||||
|
||||
type Exception(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
code: uint8;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_Exception(header.tid, header.pid, header.uid, header.fc, code);
|
||||
};
|
||||
|
||||
|
||||
type ModbusTCP_RequestPDU = record {
|
||||
header: ModbusTCP_TransportHeader;
|
||||
data: case header.fc of {
|
||||
|
||||
# Class 0
|
||||
READ_MULTIPLE_REGISTERS -> readMultipleRegisters: ReadMultipleRegistersRequest(header.len-2, header);
|
||||
WRITE_MULTIPLE_REGISTERS -> writeMultipleRegisters: WriteMultipleRegistersRequest(header.len-2, header);
|
||||
|
||||
# Class 1
|
||||
READ_COILS -> readCoils: ReadCoilsRequest(header.len-2, header);
|
||||
READ_INPUT_DISCRETES -> readInputDiscretes: ReadInputDiscretesRequest(header.len-2, header);
|
||||
READ_INPUT_REGISTERS -> readInputRegisters: ReadInputRegistersRequest(header.len-2, header);
|
||||
WRITE_COIL -> writeCoil: WriteCoilRequest(header.len-2, header);
|
||||
WRITE_SINGLE_REGISTER -> writeSingleRegister: WriteSingleRegisterRequest(header.len-2, header);
|
||||
READ_EXCEPTION_STATUS -> readExceptionStatus: ReadExceptionStatusRequest(header.len-2, header);
|
||||
|
||||
# Class 2
|
||||
FORCE_MULTIPLE_COILS -> forceMultipleCoils: ForceMultipleCoilsRequest(header.len-2, header);
|
||||
READ_GENERAL_REFERENCE -> readGeneralreference: ReadGeneralReferenceRequest(header.len-2, header);
|
||||
WRITE_GENERAL_REFERENCE -> writeGeneralReference: WriteGeneralReferenceRequest(header.len-2, header);
|
||||
MASK_WRITE_REGISTER -> maskWriteRegister: MaskWriteRegisterRequest(header.len-2, header);
|
||||
READ_WRITE_REGISTERS -> readWriteRegisters: ReadWriteRegistersRequest(header.len-2, header);
|
||||
READ_FIFO_QUEUE -> readFIFOQueue: ReadFIFOQueueRequest(header.len-2, header);
|
||||
type ModbusTCP_Request(header: ModbusTCP_TransportHeader) = case header.fc of {
|
||||
READ_COILS -> readCoils: ReadCoilsRequest(header);
|
||||
READ_DISCRETE_INPUTS -> readDiscreteInputs: ReadDiscreteInputsRequest(header);
|
||||
READ_HOLDING_REGISTERS -> readHoldingRegisters: ReadHoldingRegistersRequest(header);
|
||||
READ_INPUT_REGISTERS -> readInputRegisters: ReadInputRegistersRequest(header);
|
||||
WRITE_SINGLE_COIL -> writeSingleCoil: WriteSingleCoilRequest(header);
|
||||
WRITE_SINGLE_REGISTER -> writeSingleRegister: WriteSingleRegisterRequest(header);
|
||||
#READ_EXCEPTION_STATUS -> readExceptionStatus: ReadExceptionStatusRequest(header);
|
||||
#DIAGNOSTICS -> diagnostics: DiagnosticsRequest(header);
|
||||
#GET_COMM_EVENT_COUNTER -> getCommEventCounter: GetCommEventCounterRequest(header);
|
||||
#GET_COMM_EVENT_LOG -> getCommEventLog: GetCommEventLogRequest(header);
|
||||
WRITE_MULTIPLE_COILS -> writeMultipleCoils: WriteMultipleCoilsRequest(header);
|
||||
WRITE_MULTIPLE_REGISTERS -> writeMultRegisters: WriteMultipleRegistersRequest(header);
|
||||
#REPORT_SLAVE_ID
|
||||
READ_FILE_RECORD -> readFileRecord: ReadFileRecordRequest(header);
|
||||
WRITE_FILE_RECORD -> writeFileRecord: WriteFileRecordRequest(header);
|
||||
MASK_WRITE_REGISTER -> maskWriteRegister: MaskWriteRegisterRequest(header);
|
||||
READ_WRITE_MULTIPLE_REGISTERS -> readWriteMultipleRegisters: ReadWriteMultipleRegistersRequest(header);
|
||||
READ_FIFO_QUEUE -> readFIFOQueue: ReadFIFOQueueRequest(header);
|
||||
#ENCAP_INTERFACE_TRANSPORT
|
||||
|
||||
# All the rest
|
||||
default -> unknown: bytestring &restofdata;
|
||||
};
|
||||
|
||||
} &length = (header.len + 6),
|
||||
&let {
|
||||
deliver: bool =$context.flow.deliver_message(header.tid, header.pid, header.uid, header.fc, 1); #1 is flag for request
|
||||
};
|
||||
|
||||
# Class 0 requests
|
||||
|
||||
# REQUEST FC=3
|
||||
type ReadMultipleRegistersRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
wordCount: uint16 &check(wordCount <= 125);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadMultiRegReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, wordCount, 1, len);
|
||||
};
|
||||
|
||||
# REQUEST FC=16
|
||||
type WriteMultipleRegistersRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
wordCount: uint16 &check(wordCount <= 100);
|
||||
byteCount: uint8;
|
||||
registers: uint16[wordCount] &length = byteCount;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteMultiRegReq(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||
};
|
||||
|
||||
# Class 1 requests
|
||||
|
||||
# REQUEST FC=1
|
||||
type ReadCoilsRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
bitCount: uint16 &check(bitCount <= 2000);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadCoilsReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, bitCount);
|
||||
};
|
||||
|
||||
# REQUEST FC=2
|
||||
type ReadInputDiscretesRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
bitCount: uint16 &check(bitCount <= 2000);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadInputDiscReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, bitCount);
|
||||
};
|
||||
|
||||
# REQUEST FC=4
|
||||
type ReadInputRegistersRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
wordCount: uint16 &check(wordCount <= 125);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadInputRegReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, wordCount, 1, len);
|
||||
};
|
||||
|
||||
# REQUEST FC=5
|
||||
type WriteCoilRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
onOff: uint8 &check(onOff == 0x00 || onOff == 0xFF);
|
||||
other: uint8 &check(other == 0x00);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteCoilReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, onOff, other);
|
||||
};
|
||||
|
||||
# REQUEST FC=6
|
||||
type WriteSingleRegisterRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
registerValue: uint16;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteSingleRegReq(header.tid, header.pid, header.uid, header.fc, len, referenceNumber, registerValue);
|
||||
};
|
||||
|
||||
type ReadExceptionStatusRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadExceptStatReq(header.tid, header.pid, header.uid, header.fc, len);
|
||||
};
|
||||
|
||||
# Class 2 requests
|
||||
|
||||
# REQUEST FC=15
|
||||
type ForceMultipleCoilsRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
bitCount: uint16 &check(bitCount <= 800);
|
||||
byteCount: uint8 &check(byteCount == (bitCount + 7)/8);
|
||||
coils: bytestring &length = byteCount;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ForceMultiCoilsReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, bitCount, byteCount, coils);
|
||||
};
|
||||
|
||||
# REQUEST FC=20
|
||||
type ReadGeneralReferenceRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
references: Reference(header)[referenceCount] &length = byteCount;
|
||||
} &let {
|
||||
referenceCount: uint8 = byteCount/7;
|
||||
deliver: bool =$context.flow.deliver_ReadReferenceReq(header.tid, header.pid, header.uid, header.fc, referenceCount, references);
|
||||
};
|
||||
|
||||
# REQUEST FC=21
|
||||
type WriteGeneralReferenceRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
references: ReferenceWithData(header)[] &until($input.length() == 0) &length = byteCount;
|
||||
} &length = len,
|
||||
&let {
|
||||
deliver: bool =$context.flow.deliver_WriteReferenceReq(header.tid, header.pid, header.uid, header.fc, byteCount, references);
|
||||
};
|
||||
|
||||
# REQUESTeFC=22
|
||||
type MaskWriteRegisterRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
andMask: uint16;
|
||||
orMask: uint16;
|
||||
} &let{
|
||||
deliver: bool =$context.flow.deliver_MaskWriteRegReq(header.tid, header.pid, header.uid, header.fc, referenceNumber, andMask, orMask);
|
||||
};
|
||||
|
||||
# REQUEST FC=23
|
||||
type ReadWriteRegistersRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumberRead: uint16;
|
||||
wordCountRead: uint16 &check(wordCountRead <= 125);
|
||||
referenceNumberWrite: uint16;
|
||||
wordCountWrite: uint16 &check(wordCountWrite <= 100);
|
||||
byteCount: uint8 &check(byteCount == 2*wordCountWrite);
|
||||
registerValues: uint16[registerCount] &length = byteCount;
|
||||
} &length = len,
|
||||
&let{
|
||||
registerCount : uint8 = byteCount / 2;
|
||||
deliver: bool =$context.flow.deliver_ReadWriteRegReq(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||
};
|
||||
|
||||
# REQUEST FC=24
|
||||
type ReadFIFOQueueRequest(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
} &let{
|
||||
deliver: bool =$context.flow.deliver_ReadFIFOReq(header.tid, header.pid, header.uid, header.fc, referenceNumber);
|
||||
default -> unknown: empty &restofdata;
|
||||
};
|
||||
|
||||
# Responses
|
||||
#
|
||||
type ModbusTCP_ResponsePDU = record {
|
||||
header: ModbusTCP_TransportHeader;
|
||||
data: case header.fc of {
|
||||
|
||||
# Class 0
|
||||
READ_MULTIPLE_REGISTERS -> readMultipleRegisters: ReadMultipleRegistersResponse(header.len-2, header);
|
||||
WRITE_MULTIPLE_REGISTERS -> writeMultipleRegisters: WriteMultipleRegistersResponse(header.len-2, header);
|
||||
|
||||
# Class 1
|
||||
READ_COILS -> readCoils: ReadCoilsResponse(header.len-2, header);
|
||||
READ_INPUT_DISCRETES -> readInputDiscretes: ReadInputDiscretesResponse(header.len-2, header);
|
||||
READ_INPUT_REGISTERS -> readInputRegisters: ReadInputRegistersResponse(header.len-2, header);
|
||||
WRITE_COIL -> writeCoil: WriteCoilResponse(header.len-2, header);
|
||||
WRITE_SINGLE_REGISTER -> writeSingleRegister: WriteSingleRegisterResponse(header.len-2, header);
|
||||
READ_EXCEPTION_STATUS -> readExceptionStatus: ReadExceptionStatusResponse(header.len-2, header);
|
||||
FORCE_MULTIPLE_COILS -> forceMultipleCoils: ForceMultipleCoilsResponse(header.len-2, header);
|
||||
READ_GENERAL_REFERENCE -> readGeneralReference: ReadGeneralReferenceResponse(header.len-2, header);
|
||||
WRITE_GENERAL_REFERENCE -> writeGeneralReference: WriteGeneralReferenceResponse(header.len-2, header);
|
||||
MASK_WRITE_REGISTER -> maskWriteRegister: MaskWriteRegisterResponse(header.len-2, header);
|
||||
READ_WRITE_REGISTERS -> readWriteRegisters: ReadWriteRegistersResponse(header.len-2, header);
|
||||
READ_FIFO_QUEUE -> readFIFOQueue: ReadFIFOQueueResponse(header.len-2, header);
|
||||
type ModbusTCP_Response(header: ModbusTCP_TransportHeader) = case header.fc of {
|
||||
READ_COILS -> readCoils: ReadCoilsResponse(header);
|
||||
READ_DISCRETE_INPUTS -> readDiscreteInputs: ReadDiscreteInputsResponse(header);
|
||||
READ_HOLDING_REGISTERS -> readHoldingRegisters: ReadHoldingRegistersResponse(header);
|
||||
READ_INPUT_REGISTERS -> readInputRegisters: ReadInputRegistersResponse(header);
|
||||
WRITE_SINGLE_COIL -> writeSingleCoil: WriteSingleCoilResponse(header);
|
||||
WRITE_SINGLE_REGISTER -> writeSingleRegister: WriteSingleRegisterResponse(header);
|
||||
#READ_EXCEPTION_STATUS -> readExceptionStatus: ReadExceptionStatusResponse(header);
|
||||
#DIAGNOSTICS -> diagnostics: DiagnosticsResponse(header);
|
||||
#GET_COMM_EVENT_COUNTER -> getCommEventCounter: GetCommEventCounterResponse(header);
|
||||
#GET_COMM_EVENT_LOG -> getCommEventLog: GetCommEventLogResponse(header);
|
||||
WRITE_MULTIPLE_COILS -> writeMultipleCoils: WriteMultipleCoilsResponse(header);
|
||||
WRITE_MULTIPLE_REGISTERS -> writeMultRegisters: WriteMultipleRegistersResponse(header);
|
||||
#REPORT_SLAVE_ID
|
||||
READ_FILE_RECORD -> readFileRecord: ReadFileRecordResponse(header);
|
||||
WRITE_FILE_RECORD -> writeFileRecord: WriteFileRecordResponse(header);
|
||||
MASK_WRITE_REGISTER -> maskWriteRegister: MaskWriteRegisterResponse(header);
|
||||
READ_WRITE_MULTIPLE_REGISTERS -> readWriteMultipleRegisters: ReadWriteMultipleRegistersResponse(header);
|
||||
READ_FIFO_QUEUE -> readFIFOQueue: ReadFIFOQueueResponse(header);
|
||||
|
||||
# Exceptions
|
||||
READ_MULTIPLE_REGISTERS_EXCEPTION -> readMultipleRegistersException : Exception(header.len-2, header);
|
||||
WRITE_MULTIPLE_REGISTERS_EXCEPTION -> writeMultipleRegistersException: Exception(header.len-2, header);
|
||||
READ_COILS_EXCEPTION -> readCoilsException: Exception(header.len-2, header);
|
||||
READ_INPUT_DISCRETES_EXCEPTION -> readInputDiscretesException: Exception(header.len-2, header);
|
||||
READ_INPUT_REGISTERS_EXCEPTION -> readInputRegistersException: Exception(header.len-2, header);
|
||||
WRITE_COIL_EXCEPTION -> writeCoilException: Exception(header.len-2, header);
|
||||
WRITE_SINGLE_REGISTER_EXCEPTION -> writeSingleRegisterException: Exception(header.len-2, header);
|
||||
READ_EXCEPTION_STATUS_EXCEPTION -> readExceptionStatusException: Exception(header.len-2, header);
|
||||
FORCE_MULTIPLE_COILS_EXCEPTION -> forceMultipleCoilsException: Exception(header.len-2, header);
|
||||
READ_GENERAL_REFERENCE_EXCEPTION -> readGeneralReferenceException: Exception(header.len-2, header);
|
||||
WRITE_GENERAL_REFERENCE_EXCEPTION -> writeGeneralReferenceException: Exception(header.len-2, header);
|
||||
MASK_WRITE_REGISTER_EXCEPTION -> maskWriteRegisterException: Exception(header.len-2, header);
|
||||
READ_WRITE_REGISTERS_EXCEPTION -> readWriteRegistersException: Exception(header.len-2, header);
|
||||
READ_FIFO_QUEUE_EXCEPTION -> readFIFOQueueException: Exception(header.len-2, header);
|
||||
READ_HOLDING_REGISTERS_EXCEPTION -> readHoldingRegistersException: Exception(header);
|
||||
WRITE_MULTIPLE_REGISTERS_EXCEPTION -> writeMultRegistersException: Exception(header);
|
||||
READ_COILS_EXCEPTION -> readCoilsException: Exception(header);
|
||||
READ_DISCRETE_INPUTS_EXCEPTION -> readDiscreteInputsException: Exception(header);
|
||||
READ_INPUT_REGISTERS_EXCEPTION -> readInputRegistersException: Exception(header);
|
||||
WRITE_SINGLE_COIL_EXCEPTION -> writeCoilException: Exception(header);
|
||||
WRITE_SINGLE_REGISTER_EXCEPTION -> writeSingleRegisterException: Exception(header);
|
||||
READ_EXCEPTION_STATUS_EXCEPTION -> readExceptionStatusException: Exception(header);
|
||||
WRITE_MULTIPLE_COILS_EXCEPTION -> forceMultipleCoilsException: Exception(header);
|
||||
READ_FILE_RECORD_EXCEPTION -> readGeneralReferenceException: Exception(header);
|
||||
WRITE_FILE_RECORD_EXCEPTION -> writeGeneralReferenceException: Exception(header);
|
||||
MASK_WRITE_REGISTER_EXCEPTION -> maskWriteRegisterException: Exception(header);
|
||||
READ_WRITE_MULTIPLE_REGISTERS_EXCEPTION -> readWriteRegistersException: Exception(header);
|
||||
READ_FIFO_QUEUE_EXCEPTION -> readFIFOQueueException: Exception(header);
|
||||
|
||||
# All the rest
|
||||
default -> unknown: bytestring &restofdata;
|
||||
default -> unknown: empty &restofdata;
|
||||
};
|
||||
|
||||
} &length = (header.len+6),
|
||||
&let {
|
||||
deliver: bool =$context.flow.deliver_message(header.tid, header.pid, header.uid, header.fc,2); #2 is flag for response
|
||||
};
|
||||
|
||||
# Class 0 responses
|
||||
|
||||
# RESPONSE FC=3
|
||||
type ReadMultipleRegistersResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
registers: uint16[registerCount] &length = byteCount;
|
||||
type Exception(header: ModbusTCP_TransportHeader) = record {
|
||||
code: uint8;
|
||||
} &let {
|
||||
registerCount : uint8 = byteCount/2;
|
||||
deliver: bool =$context.flow.deliver_ReadMultiRegRes(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||
deliver: bool = $context.flow.deliver_Exception(header, this);
|
||||
};
|
||||
|
||||
|
||||
# RESPONSE FC=16
|
||||
type WriteMultipleRegistersResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
wordCount: uint16;
|
||||
# REQUEST FC=1
|
||||
type ReadCoilsRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16 &check(quantity <= 2000);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteMultiRegRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, wordCount, len);
|
||||
deliver: bool = $context.flow.deliver_ReadCoilsRequest(header, this);
|
||||
};
|
||||
|
||||
# Class 1 responses
|
||||
|
||||
# RESPONSE FC=1
|
||||
type ReadCoilsResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
bits: bytestring &length = byteCount;
|
||||
type ReadCoilsResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
bits: bytestring &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadCoilsRes(header.tid, header.pid, header.uid, header.fc, byteCount, bits);
|
||||
deliver: bool = $context.flow.deliver_ReadCoilsResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=2
|
||||
type ReadDiscreteInputsRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16 &check(quantity <= 2000);
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadDiscreteInputsRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=2
|
||||
type ReadInputDiscretesResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
bits: bytestring &length = byteCount;
|
||||
type ReadDiscreteInputsResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
bits: bytestring &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadInputDiscRes(header.tid, header.pid, header.uid, header.fc, byteCount, bits);
|
||||
deliver: bool = $context.flow.deliver_ReadDiscreteInputsResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=3
|
||||
type ReadHoldingRegistersRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16 &check(1 <= quantity && quantity <= 125);
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadHoldingRegistersRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=3
|
||||
type ReadHoldingRegistersResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
registers: uint16[] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadHoldingRegistersResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=4
|
||||
type ReadInputRegistersRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16 &check(1 <= quantity && quantity <= 125);
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadInputRegistersRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=4
|
||||
type ReadInputRegistersResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
registers: uint16[registerCount] &length = byteCount;
|
||||
type ReadInputRegistersResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
registers: uint16[] &length=byte_count;
|
||||
} &let {
|
||||
registerCount = byteCount/2;
|
||||
deliver: bool =$context.flow.deliver_ReadInputRegRes(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||
deliver: bool = $context.flow.deliver_ReadInputRegistersResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=5
|
||||
type WriteSingleCoilRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
on_off: uint8 &check(on_off == 0x00 || on_off == 0xFF);
|
||||
other: uint8 &check(other == 0x00);
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_WriteSingleCoilRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=5
|
||||
type WriteCoilResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
onOff: uint8 &check(onOff == 0x00 || onOff == 0xFF);
|
||||
type WriteSingleCoilResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
on_off: uint8 &check(on_off == 0x00 || on_off == 0xFF);
|
||||
other: uint8 &check(other == 0x00);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteCoilRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, onOff, other);
|
||||
deliver: bool = $context.flow.deliver_WriteSingleCoilResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=6
|
||||
type WriteSingleRegisterRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
value: uint16;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_WriteSingleRegisterRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=6
|
||||
type WriteSingleRegisterResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
registerValue: uint16;
|
||||
type WriteSingleRegisterResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
value: uint16;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_WriteSingleRegRes(header.tid, header.pid, header.uid, header.fc, len, referenceNumber, registerValue);
|
||||
deliver: bool = $context.flow.deliver_WriteSingleRegisterResponse(header, this);
|
||||
};
|
||||
|
||||
type ReadExceptionStatusResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
status: uint8;
|
||||
# REQUEST FC=15
|
||||
type WriteMultipleCoilsRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16 &check(quantity <= 0x07B0);
|
||||
byte_count: uint8 &check(byte_count == (quantity + 7)/8);
|
||||
coils: bytestring &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ReadExceptStatRes(header.tid, header.pid, header.uid, header.fc, status, len);
|
||||
deliver: bool = $context.flow.deliver_WriteMultipleCoilsRequest(header, this);
|
||||
};
|
||||
|
||||
# Class 2 responses
|
||||
|
||||
# RESPONSE FC=15
|
||||
type ForceMultipleCoilsResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
bitCount: uint16;
|
||||
type WriteMultipleCoilsResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16 &check(quantity <= 0x07B0);
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_ForceMultiCoilsRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, bitCount);
|
||||
deliver: bool = $context.flow.deliver_WriteMultipleCoilsResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=16
|
||||
type WriteMultipleRegistersRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16;
|
||||
byte_count: uint8;
|
||||
# We specify registers buffer with quantity and byte_count so that the analyzer
|
||||
# will choke if something doesn't match right (correct devices should make it right).
|
||||
registers: uint16[quantity] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_WriteMultipleRegistersRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=16
|
||||
type WriteMultipleRegistersResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
quantity: uint16;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_WriteMultipleRegistersResponse(header, this);
|
||||
};
|
||||
|
||||
|
||||
# Support data structure for following message type.
|
||||
type FileRecordRequest = record {
|
||||
ref_type: uint8;
|
||||
file_num: uint16;
|
||||
record_num: uint16;
|
||||
record_len: uint16;
|
||||
};
|
||||
|
||||
# REQUEST FC=20
|
||||
type ReadFileRecordRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
references: FileRecordRequest[] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadFileRecordRequest(header, this);
|
||||
};
|
||||
|
||||
# Support data structure for the following message type.
|
||||
type FileRecordResponse = record {
|
||||
file_len: uint8;
|
||||
ref_type: uint8;
|
||||
record_data: uint16[] &length=file_len;
|
||||
};
|
||||
|
||||
# RESPONSE FC=20
|
||||
type ReadGeneralReferenceResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
references: ReferenceResponse (header) [] &until($input.length()==0) &length = byteCount;
|
||||
} &length = len,
|
||||
&let{
|
||||
deliver: bool =$context.flow.deliver_ReadReferenceRes(header.tid, header.pid, header.uid, header.fc, byteCount, references);
|
||||
type ReadFileRecordResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
references: FileRecordResponse[] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadFileRecordResponse(header, this);
|
||||
};
|
||||
|
||||
# Support data structure for the two following message types.
|
||||
type ReferenceWithData = record {
|
||||
ref_type: uint8;
|
||||
file_num: uint16;
|
||||
record_num: uint16;
|
||||
word_count: uint16;
|
||||
register_value: uint16[word_count];
|
||||
};
|
||||
|
||||
# REQUEST FC=21
|
||||
type WriteFileRecordRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
references: ReferenceWithData[] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_WriteFileRecordRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=21
|
||||
type WriteGeneralReferenceResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
references: ReferenceWithData(header)[] &until($input.length() == 0) &length = byteCount;
|
||||
} &length = len,
|
||||
&let {
|
||||
deliver: bool =$context.flow.deliver_WriteReferenceRes(header.tid, header.pid, header.uid, header.fc, byteCount, references);
|
||||
type WriteFileRecordResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
references: ReferenceWithData[] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_WriteFileRecordResponse(header, this);
|
||||
};
|
||||
|
||||
|
||||
# REQUEST FC=22
|
||||
type MaskWriteRegisterRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
and_mask: uint16;
|
||||
or_mask: uint16;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_MaskWriteRegisterRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=22
|
||||
type MaskWriteRegisterResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
referenceNumber: uint16;
|
||||
andMask: uint16;
|
||||
orMask: uint16;
|
||||
type MaskWriteRegisterResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
and_mask: uint16;
|
||||
or_mask: uint16;
|
||||
} &let {
|
||||
deliver: bool =$context.flow.deliver_MaskWriteRegRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, andMask, orMask);
|
||||
deliver: bool = $context.flow.deliver_MaskWriteRegisterResponse(header, this);
|
||||
};
|
||||
|
||||
|
||||
# REQUEST FC=23
|
||||
type ReadWriteMultipleRegistersRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
read_start_address: uint16;
|
||||
read_quantity: uint16 &check(read_quantity <= 125);
|
||||
write_start_address: uint16;
|
||||
write_quantity: uint16 &check(write_quantity <= 100);
|
||||
write_byte_count: uint8;
|
||||
write_register_values: uint16[write_quantity] &length=write_byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadWriteMultipleRegistersRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=23
|
||||
type ReadWriteRegistersResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint8;
|
||||
registerValues: uint16[registerCount] &length = byteCount;
|
||||
} &length = len,
|
||||
&let {
|
||||
registerCount = byteCount / 2;
|
||||
deliver: bool =$context.flow.deliver_ReadWriteRegRes(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||
type ReadWriteMultipleRegistersResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint8;
|
||||
registers: uint16[] &length=byte_count;
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadWriteMultipleRegistersResponse(header, this);
|
||||
};
|
||||
|
||||
# REQUEST FC=24
|
||||
type ReadFIFOQueueRequest(header: ModbusTCP_TransportHeader) = record {
|
||||
start_address: uint16;
|
||||
} &let{
|
||||
deliver: bool = $context.flow.deliver_ReadFIFOQueueRequest(header, this);
|
||||
};
|
||||
|
||||
# RESPONSE FC=24
|
||||
type ReadFIFOQueueResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||
byteCount: uint16 &check(byteCount <= 64);
|
||||
wordCount: uint16 &check(wordCount <= 31);
|
||||
registerData: uint16[wordCount] &length = byteCount;
|
||||
} &length = len,
|
||||
&let{
|
||||
deliver: bool =$context.flow.deliver_ReadFIFORes(this, header.tid, header.pid, header.uid, header.fc);
|
||||
type ReadFIFOQueueResponse(header: ModbusTCP_TransportHeader) = record {
|
||||
byte_count: uint16 &check(byte_count <= 62);
|
||||
fifo_count: uint16 &check(word_count <= 31);
|
||||
register_data: uint16[fifo_count];
|
||||
} &let {
|
||||
deliver: bool = $context.flow.deliver_ReadFIFOQueueResponse(header, this);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,23 @@
|
|||
# Useful references: http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
|
||||
# http://www.simplymodbus.ca/faq.htm
|
||||
|
||||
%include binpac.pac
|
||||
%include bro.pac
|
||||
|
||||
analyzer ModbusTCP withcontext {
|
||||
connection: ModbusTCP_Conn;
|
||||
flow: ModbusTCP_Flow;
|
||||
};
|
||||
|
||||
connection ModbusTCP_Conn(bro_analyzer: BroAnalyzer) {
|
||||
upflow = ModbusTCP_Flow(true);
|
||||
downflow = ModbusTCP_Flow(false);
|
||||
};
|
||||
|
||||
%include modbus-protocol.pac
|
||||
|
||||
flow ModbusTCP_Flow(is_orig: bool) {
|
||||
flowunit = ModbusTCP_PDU(is_orig) withcontext (connection, this);
|
||||
}
|
||||
|
||||
%include modbus-analyzer.pac
|
||||
|
|
|
@ -156,6 +156,13 @@ type readdir_reply_t: record;
|
|||
|
||||
type fsstat_t: record;
|
||||
|
||||
|
||||
module GLOBAL;
|
||||
|
||||
type ModbusHeaders: record;
|
||||
type ModbusCoils: vector;
|
||||
type ModbusRegisters: vector;
|
||||
|
||||
module Log;
|
||||
|
||||
enum Writer %{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue