mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/dina/modbus' into topic/robin/modbus-merge
* origin/topic/dina/modbus: put some make-up on Modbus analyser Modbus analyser, added support: FC=20,21 Modbus analyzer,added support: FC=1,2,15,24 Modbus analyzer, current support: FC=3,4,5,6,7,16,22,23 I cleaned up the code a bit, mainly layout style. I did not include the *.bro scripts for now, but a test script ../testing/btest/scripts/base/protocols/modbus/events.bro that prints out the value for each event. Merged the Modbus traces from the ics repository into a single trace as input for the test. They currently trigger 20 of the 34 events. Addresses #870.
This commit is contained in:
commit
cbb31cedc3
17 changed files with 81106 additions and 1 deletions
|
@ -53,6 +53,14 @@ type string_vec: vector of string;
|
||||||
## then remove this alias.
|
## then remove this alias.
|
||||||
type addr_vec: vector of addr;
|
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.
|
## A table of strings indexed by strings.
|
||||||
##
|
##
|
||||||
## .. todo:: We need this type definition only for declaring builtin functions via
|
## .. todo:: We need this type definition only for declaring builtin functions via
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
@load base/protocols/ftp
|
@load base/protocols/ftp
|
||||||
@load base/protocols/http
|
@load base/protocols/http
|
||||||
@load base/protocols/irc
|
@load base/protocols/irc
|
||||||
|
@load base/protocols/modbus
|
||||||
@load base/protocols/smtp
|
@load base/protocols/smtp
|
||||||
@load base/protocols/socks
|
@load base/protocols/socks
|
||||||
@load base/protocols/ssh
|
@load base/protocols/ssh
|
||||||
|
|
1
scripts/base/protocols/modbus/__load__.bro
Normal file
1
scripts/base/protocols/modbus/__load__.bro
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@load ./main
|
12
scripts/base/protocols/modbus/main.bro
Normal file
12
scripts/base/protocols/modbus/main.bro
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
##! Base Modbus analysis script. For now it does not do anything else than
|
||||||
|
##! activating the analyzer for connections on Modbus port 502/tcp.
|
||||||
|
|
||||||
|
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 };
|
|
@ -28,6 +28,7 @@
|
||||||
#include "DCE_RPC.h"
|
#include "DCE_RPC.h"
|
||||||
#include "Gnutella.h"
|
#include "Gnutella.h"
|
||||||
#include "Ident.h"
|
#include "Ident.h"
|
||||||
|
#include "Modbus.h"
|
||||||
#include "NCP.h"
|
#include "NCP.h"
|
||||||
#include "NetbiosSSN.h"
|
#include "NetbiosSSN.h"
|
||||||
#include "SMB.h"
|
#include "SMB.h"
|
||||||
|
@ -129,6 +130,9 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
|
||||||
{ AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC",
|
{ AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC",
|
||||||
Syslog_Analyzer_binpac::InstantiateAnalyzer,
|
Syslog_Analyzer_binpac::InstantiateAnalyzer,
|
||||||
Syslog_Analyzer_binpac::Available, 0, false },
|
Syslog_Analyzer_binpac::Available, 0, false },
|
||||||
|
{ AnalyzerTag::Modbus, "MODBUS",
|
||||||
|
ModbusTCP_Analyzer::InstantiateAnalyzer,
|
||||||
|
ModbusTCP_Analyzer::Available, 0, false },
|
||||||
|
|
||||||
{ AnalyzerTag::AYIYA, "AYIYA",
|
{ AnalyzerTag::AYIYA, "AYIYA",
|
||||||
AYIYA_Analyzer::InstantiateAnalyzer,
|
AYIYA_Analyzer::InstantiateAnalyzer,
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace AnalyzerTag {
|
||||||
// Application-layer analyzers, binpac-generated.
|
// Application-layer analyzers, binpac-generated.
|
||||||
DHCP_BINPAC, DNS_TCP_BINPAC, DNS_UDP_BINPAC,
|
DHCP_BINPAC, DNS_TCP_BINPAC, DNS_UDP_BINPAC,
|
||||||
HTTP_BINPAC, SSL, SYSLOG_BINPAC,
|
HTTP_BINPAC, SSL, SYSLOG_BINPAC,
|
||||||
|
Modbus,
|
||||||
|
|
||||||
// Decapsulation analyzers.
|
// Decapsulation analyzers.
|
||||||
AYIYA,
|
AYIYA,
|
||||||
|
|
|
@ -215,6 +215,8 @@ binpac_target(ssl.pac
|
||||||
ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac)
|
ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac)
|
||||||
binpac_target(syslog.pac
|
binpac_target(syslog.pac
|
||||||
syslog-protocol.pac syslog-analyzer.pac)
|
syslog-protocol.pac syslog-analyzer.pac)
|
||||||
|
binpac_target(modbus.pac
|
||||||
|
modbus-protocol.pac modbus-analyzer.pac)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
## bro target
|
## bro target
|
||||||
|
@ -345,6 +347,7 @@ set(bro_SRCS
|
||||||
Reporter.cc
|
Reporter.cc
|
||||||
Login.cc
|
Login.cc
|
||||||
MIME.cc
|
MIME.cc
|
||||||
|
Modbus.cc
|
||||||
NCP.cc
|
NCP.cc
|
||||||
NFA.cc
|
NFA.cc
|
||||||
NFS.cc
|
NFS.cc
|
||||||
|
|
41
src/Modbus.cc
Normal file
41
src/Modbus.cc
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
#include "Modbus.h"
|
||||||
|
#include "TCP_Reassembler.h"
|
||||||
|
|
||||||
|
ModbusTCP_Analyzer::ModbusTCP_Analyzer(Connection* c)
|
||||||
|
: TCP_ApplicationAnalyzer(AnalyzerTag::Modbus, c)
|
||||||
|
{
|
||||||
|
interp = new binpac::ModbusTCP::ModbusTCP_Conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModbusTCP_Analyzer::~ModbusTCP_Analyzer()
|
||||||
|
{
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusTCP_Analyzer::Done()
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::Done();
|
||||||
|
|
||||||
|
interp->FlowEOF(true);
|
||||||
|
interp->FlowEOF(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusTCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusTCP_Analyzer::Undelivered(int seq, int len, bool orig)
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||||
|
interp->NewGap(orig, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusTCP_Analyzer::EndpointEOF(TCP_Reassembler* endp)
|
||||||
|
{
|
||||||
|
TCP_ApplicationAnalyzer::EndpointEOF(endp);
|
||||||
|
interp->FlowEOF(endp->IsOrig());
|
||||||
|
}
|
||||||
|
|
66
src/Modbus.h
Normal file
66
src/Modbus.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
#ifndef MODBUS_H
|
||||||
|
#define MODBUS_H
|
||||||
|
|
||||||
|
#include "TCP.h"
|
||||||
|
|
||||||
|
#include "modbus_pac.h"
|
||||||
|
|
||||||
|
class ModbusTCP_Analyzer : public TCP_ApplicationAnalyzer {
|
||||||
|
public:
|
||||||
|
ModbusTCP_Analyzer(Connection* conn);
|
||||||
|
virtual ~ModbusTCP_Analyzer();
|
||||||
|
|
||||||
|
virtual void Done();
|
||||||
|
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);
|
||||||
|
|
||||||
|
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||||
|
{ return new ModbusTCP_Analyzer(conn); }
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binpac::ModbusTCP::ModbusTCP_Conn* interp;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
170
src/event.bif
170
src/event.bif
|
@ -6547,6 +6547,176 @@ event netflow_v5_header%(h: nf_v5_header%);
|
||||||
## .. bro:see:: netflow_v5_record
|
## .. bro:see:: netflow_v5_record
|
||||||
event netflow_v5_record%(r: nf_v5_record%);
|
event netflow_v5_record%(r: nf_v5_record%);
|
||||||
|
|
||||||
|
## Event that passes request header only
|
||||||
|
##
|
||||||
|
## 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 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%);
|
||||||
|
|
||||||
## Raised for informational messages reported via Bro's reporter framework. Such
|
## Raised for informational messages reported via Bro's reporter framework. Such
|
||||||
## messages may be generated internally by the event engine and also by other
|
## messages may be generated internally by the event engine and also by other
|
||||||
## scripts calling :bro:id:`Reporter::info`.
|
## scripts calling :bro:id:`Reporter::info`.
|
||||||
|
|
592
src/modbus-analyzer.pac
Normal file
592
src/modbus-analyzer.pac
Normal file
|
@ -0,0 +1,592 @@
|
||||||
|
#
|
||||||
|
# The development of Bro's Modbus analyzer has been made possible thanks to
|
||||||
|
# the support of the Ministry of Security and Justice of the Kingdom of the
|
||||||
|
# Netherlands within the projects of Hermes, Castor and Midas.
|
||||||
|
#
|
||||||
|
# Useful references: http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
|
||||||
|
# http://www.simplymodbus.ca/faq.htm
|
||||||
|
#
|
||||||
|
|
||||||
|
flow ModbusTCP_Flow(is_orig: bool)
|
||||||
|
{
|
||||||
|
flowunit = ModbusTCP_PDU(is_orig) withcontext (connection, this);
|
||||||
|
|
||||||
|
# Parse only headers for request and response.
|
||||||
|
function deliver_message(tid: uint16, pid: uint16, uid: uint8, fc: uint8, flag: int): bool
|
||||||
|
%{
|
||||||
|
if ( flag == 1 )
|
||||||
|
{
|
||||||
|
if ( ::modbus_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( flag == 2 )
|
||||||
|
{
|
||||||
|
if ( ::modbus_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=1
|
||||||
|
function deliver_ReadCoilsReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, bitCount: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_coils_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_coils_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, bitCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=2
|
||||||
|
function deliver_ReadInputDiscReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, bitCount: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_input_discretes_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_input_discretes_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, bitCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=3
|
||||||
|
function deliver_ReadMultiRegReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, wcount: uint16, flag: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_multi_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_multi_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, wcount, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=4
|
||||||
|
function deliver_ReadInputRegReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, wcount: uint16, flag: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_input_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_input_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, wcount, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=5
|
||||||
|
function deliver_WriteCoilReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, onOff: uint8, other: uint8): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_write_coil_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_coil_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, onOff, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=6
|
||||||
|
function deliver_WriteSingleRegReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, len: uint16, ref: uint16, value: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_write_single_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_single_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, len, ref, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=15
|
||||||
|
function deliver_ForceMultiCoilsReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, bitCount: uint16, byteCount: uint16, coils: bytestring): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_force_coils_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_force_coils_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, bitCount, byteCount, new StringVal(coils.length(), (const char*) coils.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=16
|
||||||
|
function deliver_WriteMultiRegReq( writeMulti: WriteMultipleRegistersRequest, tid: uint16, pid: uint16, uid: uint8, fc: uint8, len: uint16): bool
|
||||||
|
%{
|
||||||
|
VectorVal * t = new VectorVal( new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${writeMulti.registers}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*writeMulti->registers())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_write_multi_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_multi_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), t, tid, pid, uid, fc, ${writeMulti.referenceNumber}, ${writeMulti.wordCount}, ${writeMulti.byteCount}, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=20
|
||||||
|
function deliver_ReadReferenceReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, refCount: uint8, reference:Reference[]): bool
|
||||||
|
%{
|
||||||
|
VectorVal *t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${reference}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val((${reference[i].refType}), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* k = new Val((${reference[i].refNumber}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* l = new Val((${reference[i].wordCount}), TYPE_INT);
|
||||||
|
t->Assign(i, l, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_reference_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_reference_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, refCount, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=20 (to read single reference)
|
||||||
|
function deliver_ReadSingleReferenceReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, refType: uint8, refNumber: uint32, wordCount: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_single_reference_request)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_single_reference_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, refType, refNumber, wordCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=20 (to read single reference)
|
||||||
|
function deliver_ReadSingleReferenceRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, byteCount: uint8, refType: uint8, ref:ReferenceResponse): bool
|
||||||
|
%{
|
||||||
|
VectorVal *t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${ref.registerValue}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*ref->registerValue())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_single_reference_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_single_reference_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, byteCount, refType, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=21
|
||||||
|
function deliver_WriteReferenceReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, byteCount: uint8, reference:ReferenceWithData[]): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${reference}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val((${reference[i].refType}), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* k = new Val((${reference[i].refNumber}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* n = new Val((${reference[i].wordCount}), TYPE_INT);
|
||||||
|
t->Assign(i, n, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
for ( unsigned int j = 0; j < (${reference[i].registerValue}->size()); ++j )
|
||||||
|
{
|
||||||
|
k = new Val((${reference[i].registerValue[j]}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_write_reference_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_reference_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, byteCount, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=21 (to write single reference)
|
||||||
|
function deliver_WriteSingleReference(tid: uint16, pid: uint16, uid: uint8, fc: uint8, refType: uint8, refNumber: uint32, wordCount: uint16, ref:ReferenceWithData): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${ref.registerValue}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*ref->registerValue())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_write_single_reference)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_single_reference(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, refType, refNumber, wordCount, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=22
|
||||||
|
function deliver_MaskWriteRegReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, andMask: uint16, orMask: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_mask_write_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_mask_write_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, andMask, orMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=23
|
||||||
|
function deliver_ReadWriteRegReq(doMulti: ReadWriteRegistersRequest, tid: uint16, pid: uint16, uid: uint8, fc: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${doMulti.registerValues})->size(); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*doMulti->registerValues())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_write_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_write_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), t, tid, pid, uid, fc, ${doMulti.referenceNumberRead}, ${doMulti.wordCountRead}, ${doMulti.referenceNumberWrite}, ${doMulti.wordCountWrite}, ${doMulti.byteCount}, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=24
|
||||||
|
function deliver_ReadFIFOReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_FIFO_request )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_FIFO_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=1
|
||||||
|
function deliver_ReadCoilsRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, bcount: uint8, bits: bytestring): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_coils_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_coils_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, bcount, new StringVal(bits.length(), (const char*) bits.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=2
|
||||||
|
function deliver_ReadInputDiscRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, bcount: uint8, bits: bytestring): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_input_discretes_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_input_discretes_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, bcount, new StringVal(bits.length(), (const char*) bits.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=3
|
||||||
|
function deliver_ReadMultiRegRes( doMulti: ReadMultipleRegistersResponse, tid: uint16, pid: uint16, uid: uint8, fc: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${doMulti.registers})->size(); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*doMulti->registers())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_multi_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_multi_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), t, tid, pid, uid, fc, ${doMulti.byteCount}, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=4
|
||||||
|
function deliver_ReadInputRegRes( doMulti: ReadInputRegistersResponse, tid: uint16, pid: uint16, uid: uint8, fc: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${doMulti.registers})->size(); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*doMulti->registers())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_input_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_input_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), t, tid, pid, uid, fc, ${doMulti.byteCount}, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=5
|
||||||
|
function deliver_WriteCoilRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, onOff: uint8, other: uint8): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_write_coil_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_coil_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, onOff, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=6
|
||||||
|
function deliver_WriteSingleRegRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, len: uint16, ref: uint16, value: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_write_single_response)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_single_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, len, ref, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
|
# RESPONSE FC=15
|
||||||
|
function deliver_ForceMultiCoilsRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, bitCount: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_force_coils_response)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_force_coils_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, bitCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=16
|
||||||
|
function deliver_WriteMultiRegRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, wcount: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_write_multi_response)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_multi_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, wcount, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=20
|
||||||
|
function deliver_ReadReferenceRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, byteCount: uint8, reference:ReferenceResponse[]): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${reference}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val((${reference[i].byteCount}), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* k = new Val((${reference[i].refType}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
for ( unsigned int j = 0; j<(${reference[i].registerValue}->size());++j)
|
||||||
|
{
|
||||||
|
k = new Val((${reference[i].registerValue[j]}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_reference_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_reference_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, byteCount, t);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=21
|
||||||
|
function deliver_WriteReferenceRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, byteCount: uint8, reference:ReferenceWithData[]): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${reference}->size()); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val((${reference[i].refType}), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* k = new Val((${reference[i].refNumber}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
Val* n = new Val((${reference[i].wordCount}), TYPE_INT);
|
||||||
|
t->Assign(i, n, 0, OP_ASSIGN);
|
||||||
|
|
||||||
|
for ( unsigned int j = 0; j<(${reference[i].registerValue}->size());++j)
|
||||||
|
{
|
||||||
|
k = new Val((${reference[i].registerValue[j]}), TYPE_INT);
|
||||||
|
t->Assign(i, k, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_write_reference_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_write_reference_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, byteCount, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=22
|
||||||
|
function deliver_MaskWriteRegRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, ref: uint16, andMask: uint16, orMask: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_mask_write_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_mask_write_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, ref, andMask, orMask);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=23
|
||||||
|
function deliver_ReadWriteRegRes(doMulti: ReadWriteRegistersResponse, tid: uint16, pid: uint16, uid: uint8, fc: uint16, len: uint16): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${doMulti.registerValues})->size(); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*doMulti->registerValues())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_write_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_write_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), t, tid, pid, uid, fc, ${doMulti.byteCount}, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=24
|
||||||
|
function deliver_ReadFIFORes( doMulti: ReadFIFOQueueResponse, tid: uint16, pid: uint16, uid: uint8, fc: uint16): bool
|
||||||
|
%{
|
||||||
|
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_INT)));
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < (${doMulti.registerData})->size(); ++i )
|
||||||
|
{
|
||||||
|
Val* r = new Val(((*doMulti->registerData())[i]), TYPE_INT);
|
||||||
|
t->Assign(i, r, 0, OP_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::modbus_read_FIFO_response )
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_FIFO_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), t, tid, pid, uid, fc, ${doMulti.byteCount});
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# EXCEPTION
|
||||||
|
function deliver_Exception(tid: uint16, pid: uint16, uid: uint8, fc: uint8, code: uint8): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_exception)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_exception(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# REQUEST FC=7
|
||||||
|
function deliver_ReadExceptStatReq(tid: uint16, pid: uint16, uid: uint8, fc: uint8, len: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_except_request)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_except_request(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
# RESPONSE FC=7
|
||||||
|
function deliver_ReadExceptStatRes(tid: uint16, pid: uint16, uid: uint8, fc: uint8, status: uint8, len: uint16): bool
|
||||||
|
%{
|
||||||
|
if ( ::modbus_read_except_response)
|
||||||
|
{
|
||||||
|
BifEvent::generate_modbus_read_except_response(connection()->bro_analyzer(),
|
||||||
|
connection()->bro_analyzer()->Conn(),
|
||||||
|
is_orig(), tid, pid, uid, fc, status, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
458
src/modbus-protocol.pac
Normal file
458
src/modbus-protocol.pac
Normal file
|
@ -0,0 +1,458 @@
|
||||||
|
#
|
||||||
|
# The development of Bro's Modbus analyzer has been made possible thanks to
|
||||||
|
# the support of the Ministry of Security and Justice of the Kingdom of the
|
||||||
|
# Netherlands within the projects of Hermes, Castor and Midas.
|
||||||
|
#
|
||||||
|
# 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,
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
|
||||||
|
# Exceptions
|
||||||
|
READ_MULTIPLE_REGISTERS_EXCEPTION = 0x83,
|
||||||
|
WRITE_MULTIPLE_REGISTERS_EXCEPTION = 0x90,
|
||||||
|
READ_COILS_EXCEPTION = 0x81,
|
||||||
|
READ_INPUT_DISCRETES_EXCEPTION = 0x82,
|
||||||
|
READ_INPUT_REGISTERS_EXCEPTION = 0x84,
|
||||||
|
WRITE_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,
|
||||||
|
MASK_WRITE_REGISTER_EXCEPTION = 0x96,
|
||||||
|
READ_WRITE_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_TransportHeader = record {
|
||||||
|
tid: uint16; # Transaction identifier
|
||||||
|
pid: uint16; # Protocol identifier
|
||||||
|
len: uint16; # Length of everyting after this field
|
||||||
|
uid: uint8; # Unit identifier (previously 'slave address')
|
||||||
|
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);
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
|
||||||
|
# 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,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;
|
||||||
|
} &let{
|
||||||
|
registerCount : uint8 = byteCount/2;
|
||||||
|
deliver: bool =$context.flow.deliver_ReadMultiRegRes(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
# RESPONSE FC=16
|
||||||
|
type WriteMultipleRegistersResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
referenceNumber: uint16;
|
||||||
|
wordCount: uint16;
|
||||||
|
} &let {
|
||||||
|
deliver: bool =$context.flow.deliver_WriteMultiRegRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, wordCount, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
# Class 1 responses
|
||||||
|
|
||||||
|
# RESPONSE FC=1
|
||||||
|
type ReadCoilsResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
byteCount: uint8;
|
||||||
|
bits: bytestring &length = byteCount;
|
||||||
|
} &let {
|
||||||
|
deliver: bool =$context.flow.deliver_ReadCoilsRes(header.tid, header.pid, header.uid, header.fc, byteCount, bits);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
# RESPONSE FC=2
|
||||||
|
type ReadInputDiscretesResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
byteCount: uint8;
|
||||||
|
bits: bytestring &length = byteCount;
|
||||||
|
} &let {
|
||||||
|
deliver: bool =$context.flow.deliver_ReadInputDiscRes(header.tid, header.pid, header.uid, header.fc, byteCount, bits);
|
||||||
|
};
|
||||||
|
|
||||||
|
# RESPONSE FC=4
|
||||||
|
type ReadInputRegistersResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
byteCount: uint8;
|
||||||
|
registers: uint16[registerCount] &length = byteCount;
|
||||||
|
} &let {
|
||||||
|
registerCount = byteCount/2;
|
||||||
|
deliver: bool =$context.flow.deliver_ReadInputRegRes(this, header.tid, header.pid, header.uid, header.fc, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
# RESPONSE FC=5
|
||||||
|
type WriteCoilResponse(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_WriteCoilRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, onOff, other);
|
||||||
|
};
|
||||||
|
|
||||||
|
# RESPONSE FC=6
|
||||||
|
type WriteSingleRegisterResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
referenceNumber: uint16;
|
||||||
|
registerValue: uint16;
|
||||||
|
} &let {
|
||||||
|
deliver: bool =$context.flow.deliver_WriteSingleRegRes(header.tid, header.pid, header.uid, header.fc, len, referenceNumber, registerValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ReadExceptionStatusResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
status: uint8;
|
||||||
|
} &let {
|
||||||
|
deliver: bool =$context.flow.deliver_ReadExceptStatRes(header.tid, header.pid, header.uid, header.fc, status, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
# Class 2 responses
|
||||||
|
|
||||||
|
# RESPONSE FC=15
|
||||||
|
type ForceMultipleCoilsResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
referenceNumber: uint16;
|
||||||
|
bitCount: uint16;
|
||||||
|
} &let {
|
||||||
|
deliver: bool =$context.flow.deliver_ForceMultiCoilsRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, bitCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
# RESPONSE FC=22
|
||||||
|
type MaskWriteRegisterResponse(len: uint16, header: ModbusTCP_TransportHeader) = record {
|
||||||
|
referenceNumber: uint16;
|
||||||
|
andMask: uint16;
|
||||||
|
orMask: uint16;
|
||||||
|
} &let{
|
||||||
|
deliver: bool =$context.flow.deliver_MaskWriteRegRes(header.tid, header.pid, header.uid, header.fc, referenceNumber, andMask, orMask);
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
};
|
12
src/modbus.pac
Normal file
12
src/modbus.pac
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#
|
||||||
|
# The development of Bro's Modbus analyzer has been made possible thanks to
|
||||||
|
# the support of the Ministry of Security and Justice of the Kingdom of the
|
||||||
|
# Netherlands within the projects of Hermes, Castor and Midas.
|
||||||
|
#
|
||||||
|
# Useful references: http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
|
||||||
|
# http://www.simplymodbus.ca/faq.htm
|
||||||
|
|
||||||
|
%include bro.pac
|
||||||
|
|
||||||
|
%include modbus-protocol.pac
|
||||||
|
%include modbus-analyzer.pac
|
|
@ -0,0 +1 @@
|
||||||
|
20 of 34 events triggered by trace
|
79557
testing/btest/Baseline/scripts.base.protocols.modbus.events/output
Normal file
79557
testing/btest/Baseline/scripts.base.protocols.modbus.events/output
Normal file
File diff suppressed because it is too large
Load diff
BIN
testing/btest/Traces/modbus.trace
Normal file
BIN
testing/btest/Traces/modbus.trace
Normal file
Binary file not shown.
178
testing/btest/scripts/base/protocols/modbus/events.bro
Normal file
178
testing/btest/scripts/base/protocols/modbus/events.bro
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: bro -r $TRACES/modbus.trace %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
# @TEST-EXEC: cat output | awk '{print $1}' | sort | uniq | wc -l >covered
|
||||||
|
# @TEST-EXEC: cat ${DIST}/src/event.bif | grep "^event modbus_" | wc -l >total
|
||||||
|
# @TEST-EXEC: echo `cat covered` of `cat total` events triggered by trace >coverage
|
||||||
|
# @TEST-EXEC: btest-diff coverage
|
||||||
|
|
||||||
|
event modbus_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count)
|
||||||
|
{
|
||||||
|
print "modbus_request", is_orig, tid, pid, uid, fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count)
|
||||||
|
{
|
||||||
|
print "modbus_response", is_orig, tid, pid, uid, fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_coils_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bcount: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_coils_request", is_orig, tid, pid, uid, fc, ref, bcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_input_discretes_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bcount: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_input_discretes_request", is_orig, tid, pid, uid, fc, ref, bcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_multi_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, wcount: count, len: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_multi_request", is_orig, tid, pid, uid, fc, ref, wcount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_input_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, wcount: count, len: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_input_request", is_orig, tid, pid, uid, fc, ref, wcount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_coil_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, onOff: count, other: count)
|
||||||
|
{
|
||||||
|
print "modbus_write_coil_request", is_orig, tid, pid, uid, fc, ref, onOff, other;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_single_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, len: count, ref: count, value: count)
|
||||||
|
{
|
||||||
|
print "modbus_write_single_request", is_orig, tid, pid, uid, fc, len, ref, value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_force_coils_request", is_orig, tid, pid, uid, fc, ref, bitCount, byteCount, coils;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_write_multi_request", is_orig, t, tid, pid, uid, fc, ref, wCount, bCount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_reference_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, refCount: count, t: int_vec)
|
||||||
|
{
|
||||||
|
print "modbus_read_reference_request", is_orig, tid, pid, uid, fc, refCount, t;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_read_single_reference_request", is_orig, tid, pid, uid, fc, refType, refNumber, wordCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_reference_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, t: int_vec)
|
||||||
|
{
|
||||||
|
print "modbus_write_reference_request", is_orig, tid, pid, uid, fc, byteCount, t;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_write_single_reference", is_orig, tid, pid, uid, fc, refType, refNumber, wordCount, t;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_mask_write_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, andMask: count, orMask: count)
|
||||||
|
{
|
||||||
|
print "modbus_mask_write_request", is_orig, tid, pid, uid, fc, ref, andMask, orMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_read_write_request", is_orig, t, tid, pid, uid, fc, refRead, wcRead, refWrite, wcWrite, bCount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_FIFO_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_FIFO_request", is_orig, tid, pid, uid, fc, ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_except_request(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, len: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_except_request", is_orig, tid, pid, uid, fc, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_coils_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, bcount: count, bits: string)
|
||||||
|
{
|
||||||
|
print "modbus_read_coils_response", is_orig, tid, pid, uid, fc, bcount, bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_input_discretes_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, bcount: count, bits: string)
|
||||||
|
{
|
||||||
|
print "modbus_read_input_discretes_response", is_orig, tid, pid, uid, fc, bcount, bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_read_multi_response", is_orig, t, tid, pid, uid, fc, bCount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_read_input_response", is_orig, t, tid, pid, uid, fc, bCount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_coil_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, onOff: count, other: count)
|
||||||
|
{
|
||||||
|
print "modbus_write_coil_response", is_orig, tid, pid, uid, fc, ref, onOff, other;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_single_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, len: count, ref: count, value: count)
|
||||||
|
{
|
||||||
|
print "modbus_write_single_response", is_orig, tid, pid, uid, fc, len, ref, value;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_force_coils_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, bitCount: count)
|
||||||
|
{
|
||||||
|
print "modbus_force_coils_response", is_orig, tid, pid, uid, fc, ref, bitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_multi_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, wcount: count, len: count)
|
||||||
|
{
|
||||||
|
print "modbus_write_multi_response", is_orig, tid, pid, uid, fc, ref, wcount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_reference_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, t: int_vec)
|
||||||
|
{
|
||||||
|
print "modbus_read_reference_response", is_orig, tid, pid, uid, fc, byteCount, t;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_read_single_reference_response", is_orig, tid, pid, uid, fc, byteCount, refType, t;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_write_reference_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, byteCount: count, t: int_vec)
|
||||||
|
{
|
||||||
|
print "modbus_write_reference_response", is_orig, tid, pid, uid, fc, byteCount, t;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_mask_write_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, ref: count, andMask: count, orMask: count)
|
||||||
|
{
|
||||||
|
print "modbus_mask_write_response", is_orig, tid, pid, uid, fc, ref, andMask, orMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
print "modbus_read_write_response", is_orig, t, tid, pid, uid, fc, bCount, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_FIFO_response(c: connection, is_orig: bool, t: int_vec, tid: count, pid: count, uid: count, fc: count, bcount: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_FIFO_response", is_orig, t, tid, pid, uid, fc, bcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_read_except_response(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, status: count, len: count)
|
||||||
|
{
|
||||||
|
print "modbus_read_except_response", is_orig, tid, pid, uid, fc, status, len;
|
||||||
|
}
|
||||||
|
|
||||||
|
event modbus_exception(c: connection, is_orig: bool, tid: count, pid: count, uid: count, fc: count, code: count)
|
||||||
|
{
|
||||||
|
print "modbus_exception", is_orig, tid, pid, uid, fc, code;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue