Merge remote-tracking branch 'remotes/origin/topic/seth/modbus-merge'

* remotes/origin/topic/seth/modbus-merge:
  Small modbus documentation update and tiny refactoring.
  Final touches to modbus analyzer for now.
  Major revisions to Modbus analyzer support (not quite done yet).
  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

Closes #915.
This commit is contained in:
Robin Sommer 2012-11-05 15:26:57 -08:00
commit 86ce564107
21 changed files with 81439 additions and 2 deletions

View file

@ -0,0 +1,56 @@
##! Script for tracking known Modbus masters and slaves.
##!
##! .. todo: This script needs a lot of work. What might be more interesting is to track
##! master/slave relationships based on commands sent and successful (non-exception)
##! responses.
module Known;
export {
redef enum Log::ID += { MODBUS_LOG };
type ModbusDeviceType: enum {
MODBUS_MASTER,
MODBUS_SLAVE,
};
type ModbusInfo: record {
## The time the device was discovered.
ts: time &log;
## The IP address of the host.
host: addr &log;
## The type of device being tracked.
device_type: ModbusDeviceType &log;
};
## The Modbus nodes being tracked.
global modbus_nodes: set[addr, ModbusDeviceType] &create_expire=1day &redef;
## Event that can be handled to access the loggable record as it is sent
## on to the logging framework.
global log_known_modbus: event(rec: ModbusInfo);
}
event bro_init() &priority=5
{
Log::create_stream(Known::MODBUS_LOG, [$columns=ModbusInfo, $ev=log_known_modbus]);
}
event modbus_message(c: connection, headers: ModbusHeaders, is_orig: bool)
{
local master = c$id$orig_h;
local slave = c$id$resp_h;
if ( [master, MODBUS_MASTER] !in modbus_nodes )
{
add modbus_nodes[master, MODBUS_MASTER];
Log::write(MODBUS_LOG, [$ts=network_time(), $host=master, $device_type=MODBUS_MASTER]);
}
if ( [slave, MODBUS_SLAVE] !in modbus_nodes )
{
add modbus_nodes[slave, MODBUS_SLAVE];
Log::write(MODBUS_LOG, [$ts=network_time(), $host=slave, $device_type=MODBUS_SLAVE]);
}
}

View file

@ -0,0 +1,101 @@
##! This script tracks the memory map of holding (read/write) registers and logs
##! changes as they are discovered.
##!
##! .. todo: Not all register reads and write functions are being supported yet.
module Modbus;
export {
redef enum Log::ID += { Modbus::REGISTER_CHANGE_LOG };
## The hosts that should have memory mapping enabled.
const track_memmap: Host = ALL_HOSTS &redef;
type MemmapInfo: record {
## Timestamp for the detected register change
ts: time &log;
## Unique ID for the connection
uid: string &log;
## Connection ID.
id: conn_id &log;
## The device memory offset.
register: count &log;
## The old value stored in the register.
old_val: count &log;
## The new value stored in the register.
new_val: count &log;
## The time delta between when the 'old_val' and 'new_val' were seen.
delta: interval &log;
};
type RegisterValue: record {
last_set: time;
value: count;
};
## Indexed on the device register value and yielding the register value.
type Registers: table[count] of RegisterValue;
## The memory map of slaves is tracked with this variable.
global device_registers: table[addr] of Registers;
## This event is generated every time a register is seen to be different than
## it was previously seen to be.
global changed_register: event(c: connection, register: count, old_val: count, new_val: count, delta: interval);
}
redef record Modbus::Info += {
track_address: count &default=0;
};
event bro_init() &priority=5
{
Log::create_stream(Modbus::REGISTER_CHANGE_LOG, [$columns=MemmapInfo]);
}
event modbus_read_holding_registers_request(c: connection, headers: ModbusHeaders, start_address: count, quantity: count)
{
c$modbus$track_address = start_address+1;
}
event modbus_read_holding_registers_response(c: connection, headers: ModbusHeaders, registers: ModbusRegisters)
{
local slave = c$id$resp_h;
if ( ! addr_matches_host(slave, track_memmap ) )
return;
if ( slave !in device_registers )
device_registers[slave] = table();
local slave_regs = device_registers[slave];
for ( i in registers )
{
if ( c$modbus$track_address in slave_regs )
{
if ( slave_regs[c$modbus$track_address]$value != registers[i] )
{
local delta = network_time() - slave_regs[c$modbus$track_address]$last_set;
event Modbus::changed_register(c, c$modbus$track_address,
slave_regs[c$modbus$track_address]$value, registers[i],
delta);
slave_regs[c$modbus$track_address]$last_set = network_time();
slave_regs[c$modbus$track_address]$value = registers[i];
}
}
else
{
local tmp_reg: RegisterValue = [$last_set=network_time(), $value=registers[i]];
slave_regs[c$modbus$track_address] = tmp_reg;
}
++c$modbus$track_address;
}
}
event Modbus::changed_register(c: connection, register: count, old_val: count, new_val: count, delta: interval)
{
local rec: MemmapInfo = [$ts=network_time(), $uid=c$uid, $id=c$id,
$register=register, $old_val=old_val, $new_val=new_val, $delta=delta];
Log::write(REGISTER_CHANGE_LOG, rec);
}