mirror of
https://github.com/zeek/zeek.git
synced 2025-10-11 11:08:20 +00:00
792 lines
28 KiB
JavaScript
792 lines
28 KiB
JavaScript
#
|
|
# The development of Zeek'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
|
|
#
|
|
|
|
%header{
|
|
zeek::VectorValPtr bytestring_to_coils(const bytestring& coils, uint quantity);
|
|
zeek::RecordValPtr HeaderToVal(ModbusTCP_TransportHeader* header);
|
|
zeek::VectorValPtr create_vector_of_count();
|
|
%}
|
|
|
|
%code{
|
|
zeek::VectorValPtr bytestring_to_coils(const bytestring& coils, uint quantity)
|
|
{
|
|
auto modbus_coils = zeek::make_intrusive<zeek::VectorVal>(zeek::BifType::Vector::ModbusCoils);
|
|
|
|
for ( uint i = 0; i < quantity && (i/8) < static_cast<uint>(coils.length()); i++ )
|
|
{
|
|
char currentCoil = (coils[i/8] >> (i % 8)) % 2;
|
|
modbus_coils->Assign(i, zeek::val_mgr->Bool(currentCoil));
|
|
}
|
|
|
|
return modbus_coils;
|
|
}
|
|
|
|
zeek::RecordValPtr HeaderToVal(ModbusTCP_TransportHeader* header)
|
|
{
|
|
auto modbus_header = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::ModbusHeaders);
|
|
modbus_header->Assign(0, header->tid());
|
|
modbus_header->Assign(1, header->pid());
|
|
modbus_header->Assign(2, header->uid());
|
|
modbus_header->Assign(3, header->fc());
|
|
modbus_header->Assign(4, header->len());
|
|
return modbus_header;
|
|
}
|
|
|
|
zeek::VectorValPtr create_vector_of_count()
|
|
{
|
|
auto vt = zeek::make_intrusive<zeek::VectorType>(zeek::base_type(zeek::TYPE_COUNT));
|
|
auto vv = zeek::make_intrusive<zeek::VectorVal>(std::move(vt));
|
|
return vv;
|
|
}
|
|
|
|
%}
|
|
|
|
refine connection ModbusTCP_Conn += {
|
|
%member{
|
|
// Fields used to determine if the protocol has been confirmed or not.
|
|
bool confirmed;
|
|
bool orig_pdu;
|
|
bool resp_pdu;
|
|
%}
|
|
|
|
%init{
|
|
confirmed = false;
|
|
orig_pdu = false;
|
|
resp_pdu = false;
|
|
%}
|
|
|
|
function SetPDU(is_orig: bool): bool
|
|
%{
|
|
if ( is_orig )
|
|
orig_pdu = true;
|
|
else
|
|
resp_pdu = true;
|
|
|
|
return true;
|
|
%}
|
|
|
|
function SetConfirmed(): bool
|
|
%{
|
|
confirmed = true;
|
|
return true;
|
|
%}
|
|
|
|
function IsConfirmed(): bool
|
|
%{
|
|
return confirmed && orig_pdu && resp_pdu;
|
|
%}
|
|
};
|
|
|
|
refine flow ModbusTCP_Flow += {
|
|
|
|
function deliver_message(header: ModbusTCP_TransportHeader): bool
|
|
%{
|
|
if ( ::modbus_message )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_message(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
is_orig());
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
function deliver_ModbusTCP_PDU(message: ModbusTCP_PDU): bool
|
|
%{
|
|
// We will assume that if an entire PDU from both sides
|
|
// is successfully parsed then this is definitely modbus.
|
|
connection()->SetPDU(${message.is_orig});
|
|
|
|
if ( ! connection()->IsConfirmed() )
|
|
{
|
|
connection()->SetConfirmed();
|
|
connection()->zeek_analyzer()->AnalyzerConfirmation();
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# EXCEPTION
|
|
function deliver_Exception(header: ModbusTCP_TransportHeader, message: Exception): bool
|
|
%{
|
|
if ( ::modbus_exception )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_exception(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.code});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=1
|
|
function deliver_ReadCoilsRequest(header: ModbusTCP_TransportHeader, message: ReadCoilsRequest): bool
|
|
%{
|
|
if ( ::modbus_read_coils_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_coils_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address},
|
|
${message.quantity});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=1
|
|
function deliver_ReadCoilsResponse(header: ModbusTCP_TransportHeader, message: ReadCoilsResponse): bool
|
|
%{
|
|
if ( ::modbus_read_coils_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_coils_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
bytestring_to_coils(${message.bits}, ${message.bits}.length()*8));
|
|
}
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=2
|
|
function deliver_ReadDiscreteInputsRequest(header: ModbusTCP_TransportHeader, message: ReadDiscreteInputsRequest): bool
|
|
%{
|
|
if ( ::modbus_read_discrete_inputs_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_discrete_inputs_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address}, ${message.quantity});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=2
|
|
function deliver_ReadDiscreteInputsResponse(header: ModbusTCP_TransportHeader, message: ReadDiscreteInputsResponse): bool
|
|
%{
|
|
if ( ::modbus_read_discrete_inputs_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_discrete_inputs_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
bytestring_to_coils(${message.bits}, ${message.bits}.length()*8));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=3
|
|
function deliver_ReadHoldingRegistersRequest(header: ModbusTCP_TransportHeader, message: ReadHoldingRegistersRequest): bool
|
|
%{
|
|
if ( ::modbus_read_holding_registers_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_holding_registers_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address}, ${message.quantity});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=3
|
|
function deliver_ReadHoldingRegistersResponse(header: ModbusTCP_TransportHeader, message: ReadHoldingRegistersResponse): bool
|
|
%{
|
|
if ( ${message.byte_count} % 2 != 0 )
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
zeek::util::fmt("invalid value for modbus read holding register response byte count %d", ${message.byte_count}));
|
|
return false;
|
|
}
|
|
|
|
if ( ::modbus_read_holding_registers_response )
|
|
{
|
|
auto t = zeek::make_intrusive<zeek::VectorVal>(zeek::BifType::Vector::ModbusRegisters);
|
|
|
|
for ( unsigned int i=0; i < ${message.registers}->size(); ++i )
|
|
{
|
|
auto r = zeek::val_mgr->Count(${message.registers[i]});
|
|
t->Assign(i, r);
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_holding_registers_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
std::move(t));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=4
|
|
function deliver_ReadInputRegistersRequest(header: ModbusTCP_TransportHeader, message: ReadInputRegistersRequest): bool
|
|
%{
|
|
if ( ::modbus_read_input_registers_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_input_registers_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address}, ${message.quantity});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=4
|
|
function deliver_ReadInputRegistersResponse(header: ModbusTCP_TransportHeader, message: ReadInputRegistersResponse): bool
|
|
%{
|
|
if ( ${message.byte_count} % 2 != 0 )
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
zeek::util::fmt("invalid value for modbus read input register response byte count %d", ${message.byte_count}));
|
|
return false;
|
|
}
|
|
|
|
if ( ::modbus_read_input_registers_response )
|
|
{
|
|
auto t = zeek::make_intrusive<zeek::VectorVal>(zeek::BifType::Vector::ModbusRegisters);
|
|
|
|
for ( unsigned int i=0; i < (${message.registers})->size(); ++i )
|
|
{
|
|
auto r = zeek::val_mgr->Count(${message.registers[i]});
|
|
t->Assign(i, r);
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_input_registers_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
std::move(t));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=5
|
|
function deliver_WriteSingleCoilRequest(header: ModbusTCP_TransportHeader, message: WriteSingleCoilRequest): bool
|
|
%{
|
|
if ( ::modbus_write_single_coil_request )
|
|
{
|
|
int val;
|
|
if ( ${message.value} == 0x0000 )
|
|
val = 0;
|
|
else if ( ${message.value} == 0xFF00 )
|
|
val = 1;
|
|
else
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(zeek::util::fmt("invalid value for modbus write single coil request %d",
|
|
${message.value}));
|
|
return false;
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_write_single_coil_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.address},
|
|
val);
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=5
|
|
function deliver_WriteSingleCoilResponse(header: ModbusTCP_TransportHeader, message: WriteSingleCoilResponse): bool
|
|
%{
|
|
if ( ::modbus_write_single_coil_response )
|
|
{
|
|
int val;
|
|
if ( ${message.value} == 0x0000 )
|
|
val = 0;
|
|
else if ( ${message.value} == 0xFF00 )
|
|
val = 1;
|
|
else
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(zeek::util::fmt("invalid value for modbus write single coil response %d",
|
|
${message.value}));
|
|
return false;
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_write_single_coil_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.address},
|
|
val);
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=6
|
|
function deliver_WriteSingleRegisterRequest(header: ModbusTCP_TransportHeader, message: WriteSingleRegisterRequest): bool
|
|
%{
|
|
if ( ::modbus_write_single_register_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_write_single_register_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.address}, ${message.value});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=6
|
|
function deliver_WriteSingleRegisterResponse(header: ModbusTCP_TransportHeader, message: WriteSingleRegisterResponse): bool
|
|
%{
|
|
if ( ::modbus_write_single_register_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_write_single_register_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.address}, ${message.value});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=8
|
|
function deliver_DiagnosticsRequest(header: ModbusTCP_TransportHeader, message: DiagnosticsRequest): bool
|
|
%{
|
|
if ( ::modbus_diagnostics_request )
|
|
{
|
|
auto data = to_stringval(${message.data});
|
|
|
|
// Data should always be a multiple of two bytes. For everything except
|
|
// "Return Query Data (0x00)" it should be two bytes long.
|
|
if ( data->Len() < 2 || data->Len() % 2 != 0 ||
|
|
(${message.subfunction} != DIAGNOSTICS_RETURN_QUERY_DATA && data->Len() != 2) )
|
|
{
|
|
zeek::reporter->Weird("modbus_diag_invalid_request_data",
|
|
zeek::util::fmt("%s", data->CheckString()));
|
|
}
|
|
|
|
switch (${message.subfunction})
|
|
{
|
|
case DIAGNOSTICS_RESTART_COMMUNICATIONS_OPTION:
|
|
// For "Restart Communications Option" it's either 0x0000 or 0xFF00.
|
|
if ( ( data->Bytes()[0] != 0x00 && data->Bytes()[0] != 0xFF ) ||
|
|
data->Bytes()[1] != 0x00 )
|
|
{
|
|
zeek::reporter->Weird("modbus_diag_invalid_request_data",
|
|
zeek::util::fmt("%s", data->CheckString()));
|
|
}
|
|
break;
|
|
case DIAGNOSTICS_RETURN_DIAGNOSTIC_REGISTER:
|
|
case DIAGNOSTICS_FORCE_LISTEN_ONLY_MODE:
|
|
case DIAGNOSTICS_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER:
|
|
case DIAGNOSTICS_RETURN_BUS_MESSAGE_COUNT:
|
|
case DIAGNOSTICS_RETURN_BUS_COMMUNICATION_ERROR_COUNT:
|
|
case DIAGNOSTICS_RETURN_BUS_EXCEPTION_ERROR_COUNT:
|
|
case DIAGNOSTICS_RETURN_SERVER_MESSAGE_COUNT:
|
|
case DIAGNOSTICS_RETURN_SERVER_NO_RESPONSE_COUNT:
|
|
case DIAGNOSTICS_RETURN_SERVER_NAK_COUNT:
|
|
case DIAGNOSTICS_RETURN_SERVER_BUSY_COUNT:
|
|
case DIAGNOSTICS_RETURN_BUS_CHARACTER_OVERRUN_COUNT:
|
|
case DIAGNOSTICS_CLEAR_OVERRUN_COUNTER_AND_FLAG:
|
|
// For all of these subfunctions, the data should be 0x0000.
|
|
if ( data->Bytes()[0] != 0x00 || data->Bytes()[1] != 0x00 )
|
|
{
|
|
zeek::reporter->Weird("modbus_diag_invalid_request_data",
|
|
zeek::util::fmt("%s", data->CheckString()));
|
|
}
|
|
break;
|
|
|
|
case DIAGNOSTICS_CHANGE_ASCII_INPUT_DELIMITER:
|
|
// For "Change ASCII Input Delimiter", it should be an ascii character
|
|
// followed by a zero.
|
|
if ( ! isascii(data->Bytes()[0]) || data->Bytes()[1] != 0x00 )
|
|
{
|
|
zeek::reporter->Weird("modbus_diag_invalid_request_data",
|
|
zeek::util::fmt("%s", data->CheckString()));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
zeek::reporter->Weird("modbus_diag_unknown_request_subfunction",
|
|
zeek::util::fmt("%d", ${message.subfunction}));
|
|
break;
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_diagnostics_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.subfunction}, to_stringval(${message.data}));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=8
|
|
function deliver_DiagnosticsResponse(header: ModbusTCP_TransportHeader, message: DiagnosticsResponse): bool
|
|
%{
|
|
if ( ::modbus_diagnostics_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_diagnostics_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.subfunction}, to_stringval(${message.data}));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=15
|
|
function deliver_WriteMultipleCoilsRequest(header: ModbusTCP_TransportHeader, message: WriteMultipleCoilsRequest): bool
|
|
%{
|
|
if ( ::modbus_write_multiple_coils_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_write_multiple_coils_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address},
|
|
bytestring_to_coils(${message.coils}, ${message.quantity}));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=15
|
|
function deliver_WriteMultipleCoilsResponse(header: ModbusTCP_TransportHeader, message: WriteMultipleCoilsResponse): bool
|
|
%{
|
|
if ( ::modbus_write_multiple_coils_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_write_multiple_coils_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address}, ${message.quantity});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# REQUEST FC=16
|
|
function deliver_WriteMultipleRegistersRequest(header: ModbusTCP_TransportHeader, message: WriteMultipleRegistersRequest): bool
|
|
%{
|
|
if ( ${message.byte_count} % 2 != 0 )
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
zeek::util::fmt("invalid value for modbus write multiple registers request byte count %d", ${message.byte_count}));
|
|
return false;
|
|
}
|
|
|
|
if ( ::modbus_write_multiple_registers_request )
|
|
{
|
|
auto t = zeek::make_intrusive<zeek::VectorVal>(zeek::BifType::Vector::ModbusRegisters);
|
|
|
|
for ( unsigned int i = 0; i < (${message.registers}->size()); ++i )
|
|
{
|
|
auto r = zeek::val_mgr->Count(${message.registers[i]});
|
|
t->Assign(i, r);
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_write_multiple_registers_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address}, std::move(t));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=16
|
|
function deliver_WriteMultipleRegistersResponse(header: ModbusTCP_TransportHeader, message: WriteMultipleRegistersResponse): bool
|
|
%{
|
|
if ( ::modbus_write_multiple_registers_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_write_multiple_registers_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address}, ${message.quantity});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=20
|
|
function deliver_ReadFileRecordRequest(header: ModbusTCP_TransportHeader, message: ReadFileRecordRequest): bool
|
|
%{
|
|
if ( ::modbus_read_file_record_request )
|
|
{
|
|
//TODO: this need to be a vector of some Reference Request record type
|
|
//auto t = create_vector_of_count();
|
|
//for ( unsigned int i = 0; i < (${message.references}->size()); ++i )
|
|
// {
|
|
// auto r = zeek::val_mgr->Count((${message.references[i].ref_type}));
|
|
// t->Assign(i, r);
|
|
//
|
|
// auto k = zeek::val_mgr->Count((${message.references[i].file_num}));
|
|
// t->Assign(i, k);
|
|
//
|
|
// auto l = zeek::val_mgr->Count((${message.references[i].record_num}));
|
|
// t->Assign(i, l);
|
|
// }
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_file_record_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=20
|
|
function deliver_ReadFileRecordResponse(header: ModbusTCP_TransportHeader, message: ReadFileRecordResponse): bool
|
|
%{
|
|
if ( ::modbus_read_file_record_response )
|
|
{
|
|
//auto t = create_vector_of_count();
|
|
//for ( unsigned int i = 0; i < ${message.references}->size(); ++i )
|
|
// {
|
|
// //TODO: work the reference type in here somewhere
|
|
// auto r = zeek::val_mgr->Count(${message.references[i].record_data}));
|
|
// t->Assign(i, r);
|
|
// }
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_file_record_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=21
|
|
function deliver_WriteFileRecordRequest(header: ModbusTCP_TransportHeader, message: WriteFileRecordRequest): bool
|
|
%{
|
|
if ( ::modbus_write_file_record_request )
|
|
{
|
|
//auto t = create_vector_of_count();
|
|
//for ( unsigned int i = 0; i < (${message.references}->size()); ++i )
|
|
// {
|
|
// auto r = zeek::val_mgr->Count((${message.references[i].ref_type}));
|
|
// t->Assign(i, r);
|
|
//
|
|
// auto k = zeek::val_mgr->Count((${message.references[i].file_num}));
|
|
// t->Assign(i, k);
|
|
//
|
|
// auto n = zeek::val_mgr->Count((${message.references[i].record_num}));
|
|
// t->Assign(i, n);
|
|
//
|
|
// for ( unsigned int j = 0; j < (${message.references[i].register_value}->size()); ++j )
|
|
// {
|
|
// k = zeek::val_mgr->Count((${message.references[i].register_value[j]}));
|
|
// t->Assign(i, k);
|
|
// }
|
|
// }
|
|
|
|
zeek::BifEvent::enqueue_modbus_write_file_record_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# RESPONSE FC=21
|
|
function deliver_WriteFileRecordResponse(header: ModbusTCP_TransportHeader, message: WriteFileRecordResponse): bool
|
|
%{
|
|
if ( ::modbus_write_file_record_response )
|
|
{
|
|
//auto t = create_vector_of_count();
|
|
//for ( unsigned int i = 0; i < (${messages.references}->size()); ++i )
|
|
// {
|
|
// auto r = zeek::val_mgr->Count((${message.references[i].ref_type}));
|
|
// t->Assign(i, r);
|
|
//
|
|
// auto f = zeek::val_mgr->Count((${message.references[i].file_num}));
|
|
// t->Assign(i, f);
|
|
//
|
|
// auto rn = zeek::val_mgr->Count((${message.references[i].record_num}));
|
|
// t->Assign(i, rn);
|
|
//
|
|
// for ( unsigned int j = 0; j<(${message.references[i].register_value}->size()); ++j )
|
|
// {
|
|
// auto k = zeek::val_mgr->Count((${message.references[i].register_value[j]}));
|
|
// t->Assign(i, k);
|
|
// }
|
|
|
|
zeek::BifEvent::enqueue_modbus_write_file_record_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=22
|
|
function deliver_MaskWriteRegisterRequest(header: ModbusTCP_TransportHeader, message: MaskWriteRegisterRequest): bool
|
|
%{
|
|
if ( ::modbus_mask_write_register_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_mask_write_register_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.address},
|
|
${message.and_mask}, ${message.or_mask});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=22
|
|
function deliver_MaskWriteRegisterResponse(header: ModbusTCP_TransportHeader, message: MaskWriteRegisterResponse): bool
|
|
%{
|
|
if ( ::modbus_mask_write_register_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_mask_write_register_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.address},
|
|
${message.and_mask}, ${message.or_mask});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=23
|
|
function deliver_ReadWriteMultipleRegistersRequest(header: ModbusTCP_TransportHeader, message: ReadWriteMultipleRegistersRequest): bool
|
|
%{
|
|
if ( ${message.write_byte_count} % 2 != 0 )
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
zeek::util::fmt("invalid value for modbus read write multiple registers request write byte count %d", ${message.write_byte_count}));
|
|
return false;
|
|
}
|
|
|
|
if ( ::modbus_read_write_multiple_registers_request )
|
|
{
|
|
auto t = zeek::make_intrusive<zeek::VectorVal>(zeek::BifType::Vector::ModbusRegisters);
|
|
|
|
for ( unsigned int i = 0; i < ${message.write_register_values}->size(); ++i )
|
|
{
|
|
auto r = zeek::val_mgr->Count(${message.write_register_values[i]});
|
|
t->Assign(i, r);
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_write_multiple_registers_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.read_start_address},
|
|
${message.read_quantity},
|
|
${message.write_start_address},
|
|
std::move(t));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=23
|
|
function deliver_ReadWriteMultipleRegistersResponse(header: ModbusTCP_TransportHeader, message: ReadWriteMultipleRegistersResponse): bool
|
|
%{
|
|
if ( ${message.byte_count} % 2 != 0 )
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
zeek::util::fmt("invalid value for modbus read write multiple registers response byte count %d", ${message.byte_count}));
|
|
return false;
|
|
}
|
|
|
|
if ( ::modbus_read_write_multiple_registers_response )
|
|
{
|
|
auto t = zeek::make_intrusive<zeek::VectorVal>(zeek::BifType::Vector::ModbusRegisters);
|
|
|
|
for ( unsigned int i = 0; i < ${message.registers}->size(); ++i )
|
|
{
|
|
auto r = zeek::val_mgr->Count(${message.registers[i]});
|
|
t->Assign(i, r);
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_write_multiple_registers_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
std::move(t));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=24
|
|
function deliver_ReadFIFOQueueRequest(header: ModbusTCP_TransportHeader, message: ReadFIFOQueueRequest): bool
|
|
%{
|
|
if ( ::modbus_read_fifo_queue_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_read_fifo_queue_request(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
${message.start_address});
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
|
|
# RESPONSE FC=24
|
|
function deliver_ReadFIFOQueueResponse(header: ModbusTCP_TransportHeader, message: ReadFIFOQueueResponse): bool
|
|
%{
|
|
if ( ${message.byte_count} % 2 != 0 )
|
|
{
|
|
connection()->zeek_analyzer()->AnalyzerViolation(
|
|
zeek::util::fmt("invalid value for modbus read FIFO queue response byte count %d", ${message.byte_count}));
|
|
return false;
|
|
}
|
|
|
|
if ( ::modbus_read_fifo_queue_response )
|
|
{
|
|
auto t = create_vector_of_count();
|
|
|
|
for ( unsigned int i = 0; i < (${message.register_data})->size(); ++i )
|
|
{
|
|
auto r = zeek::val_mgr->Count(${message.register_data[i]});
|
|
t->Assign(i, r);
|
|
}
|
|
|
|
zeek::BifEvent::enqueue_modbus_read_fifo_queue_response(connection()->zeek_analyzer(),
|
|
connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header),
|
|
std::move(t));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# REQUEST FC=2B
|
|
function deliver_EncapInterfaceTransportRequest(header: ModbusTCP_TransportHeader, message: EncapInterfaceTransportRequest): bool
|
|
%{
|
|
if ( ::modbus_encap_interface_transport_request )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_encap_interface_transport_request(
|
|
connection()->zeek_analyzer(), connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header), ${message.mei_type}, to_stringval(${message.data}));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
# RESPONSE FC=2B
|
|
function deliver_EncapInterfaceTransportResponse(header: ModbusTCP_TransportHeader, message: EncapInterfaceTransportResponse): bool
|
|
%{
|
|
if ( ::modbus_encap_interface_transport_response )
|
|
{
|
|
zeek::BifEvent::enqueue_modbus_encap_interface_transport_response(
|
|
connection()->zeek_analyzer(), connection()->zeek_analyzer()->Conn(),
|
|
HeaderToVal(header), ${message.mei_type}, to_stringval(${message.data}));
|
|
}
|
|
|
|
return true;
|
|
%}
|
|
|
|
};
|