From 6c09772a74b0e1e753e856bd1a642551ab3ecc8f Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Tue, 7 Feb 2023 17:31:22 -0500 Subject: [PATCH] #76 added trusted connection ranges for modem messages --- coordinator/config.lua | 2 ++ coordinator/coordinator.lua | 19 +++++++++++-------- coordinator/startup.lua | 6 ++++-- reactor-plc/config.lua | 2 ++ reactor-plc/plc.lua | 31 +++++++++++++++++-------------- reactor-plc/startup.lua | 5 +++-- rtu/config.lua | 15 +++++++++++---- rtu/rtu.lua | 29 ++++++++++++++++------------- rtu/startup.lua | 6 ++++-- scada-common/comms.lua | 18 ++++++++++++++++++ supervisor/config.lua | 2 ++ supervisor/startup.lua | 5 +++-- supervisor/supervisor.lua | 31 ++++++++++++++++--------------- 13 files changed, 109 insertions(+), 62 deletions(-) diff --git a/coordinator/config.lua b/coordinator/config.lua index 983c7d9..b88593f 100644 --- a/coordinator/config.lua +++ b/coordinator/config.lua @@ -6,6 +6,8 @@ config.SCADA_SV_PORT = 16100 config.SCADA_SV_LISTEN = 16101 -- listen port for SCADA coordinator API access config.SCADA_API_LISTEN = 16200 +-- max trusted modem message distance (0 to disable check) +config.TRUSTED_RANGE = 0 -- expected number of reactor units, used only to require that number of unit monitors config.NUM_UNITS = 4 diff --git a/coordinator/coordinator.lua b/coordinator/coordinator.lua index b13f4a2..7df62d0 100644 --- a/coordinator/coordinator.lua +++ b/coordinator/coordinator.lua @@ -191,13 +191,14 @@ function coordinator.log_comms_connecting(message) end -- coordinator communications ----@param version string ----@param modem table ----@param sv_port integer ----@param sv_listen integer ----@param api_listen integer +---@param version string coordinator version +---@param modem table modem device +---@param sv_port integer port of configured supervisor +---@param sv_listen integer listening port for supervisor replys +---@param api_listen integer listening port for pocket API +---@param range integer trusted device connection range ---@param sv_watchdog watchdog -function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_watchdog) +function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, range, sv_watchdog) local self = { sv_linked = false, sv_seq_num = 0, @@ -209,6 +210,8 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa ---@class coord_comms local public = {} + comms.set_trusted_range(range) + -- PRIVATE FUNCTIONS -- -- configure modem channels @@ -512,8 +515,8 @@ function coordinator.comms(version, modem, sv_port, sv_listen, api_listen, sv_wa ---@class facility_conf local conf = { - num_units = config[1], - defs = {} -- boilers and turbines + num_units = config[1], ---@type integer + defs = {} -- boilers and turbines } if (#config - 1) == (conf.num_units * 2) then diff --git a/coordinator/startup.lua b/coordinator/startup.lua index 74ae70a..e789f38 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -19,7 +19,7 @@ local iocontrol = require("coordinator.iocontrol") local renderer = require("coordinator.renderer") local sounder = require("coordinator.sounder") -local COORDINATOR_VERSION = "beta-v0.9.1" +local COORDINATOR_VERSION = "beta-v0.9.2" local print = util.print local println = util.println @@ -41,6 +41,7 @@ local cfv = util.new_validator() cfv.assert_port(config.SCADA_SV_PORT) cfv.assert_port(config.SCADA_SV_LISTEN) cfv.assert_port(config.SCADA_API_LISTEN) +cfv.assert_type_int(config.TRUSTED_RANGE) cfv.assert_type_int(config.NUM_UNITS) cfv.assert_type_bool(config.RECOLOR) cfv.assert_type_num(config.SOUNDER_VOLUME) @@ -146,7 +147,8 @@ local function main() log.debug("boot> conn watchdog created") -- start comms, open all channels - local coord_comms = coordinator.comms(COORDINATOR_VERSION, modem, config.SCADA_SV_PORT, config.SCADA_SV_LISTEN, config.SCADA_API_LISTEN, conn_watchdog) + local coord_comms = coordinator.comms(COORDINATOR_VERSION, modem, config.SCADA_SV_PORT, config.SCADA_SV_LISTEN, + config.SCADA_API_LISTEN, config.TRUSTED_RANGE, conn_watchdog) log.debug("boot> comms init") log_comms("comms initialized") diff --git a/reactor-plc/config.lua b/reactor-plc/config.lua index 2e0eed3..f1a33a0 100644 --- a/reactor-plc/config.lua +++ b/reactor-plc/config.lua @@ -8,6 +8,8 @@ config.REACTOR_ID = 1 config.SERVER_PORT = 16000 -- port to listen to incoming packets FROM server config.LISTEN_PORT = 14001 +-- max trusted modem message distance (0 to disable check) +config.TRUSTED_RANGE = 0 -- log path config.LOG_PATH = "/log.txt" -- log mode diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua index a23ad3f..71f17e4 100644 --- a/reactor-plc/plc.lua +++ b/reactor-plc/plc.lua @@ -404,15 +404,16 @@ function plc.rps_init(reactor, is_formed) end -- Reactor PLC Communications ----@param id integer ----@param version string ----@param modem table ----@param local_port integer ----@param server_port integer ----@param reactor table ----@param rps rps ----@param conn_watchdog watchdog -function plc.comms(id, version, modem, local_port, server_port, reactor, rps, conn_watchdog) +---@param id integer reactor ID +---@param version string PLC version +---@param modem table modem device +---@param local_port integer local listening port +---@param server_port integer remote server port +---@param range integer trusted device connection range +---@param reactor table reactor device +---@param rps rps RPS reference +---@param conn_watchdog watchdog watchdog reference +function plc.comms(id, version, modem, local_port, server_port, range, reactor, rps, conn_watchdog) local self = { seq_num = 0, r_seq_num = nil, @@ -428,6 +429,13 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co max_burn_rate = nil } + ---@class plc_comms + local public = {} + + comms.set_trusted_range(range) + + -- PRIVATE FUNCTIONS -- + -- configure modem channels local function _conf_channels() self.modem.closeAll() @@ -436,11 +444,6 @@ function plc.comms(id, version, modem, local_port, server_port, reactor, rps, co _conf_channels() - ---@class plc_comms - local public = {} - - -- PRIVATE FUNCTIONS -- - -- send an RPLC packet ---@param msg_type RPLC_TYPES ---@param msg table diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua index 207fec6..b4ffb89 100644 --- a/reactor-plc/startup.lua +++ b/reactor-plc/startup.lua @@ -14,7 +14,7 @@ local config = require("reactor-plc.config") local plc = require("reactor-plc.plc") local threads = require("reactor-plc.threads") -local R_PLC_VERSION = "beta-v0.10.5" +local R_PLC_VERSION = "beta-v0.10.6" local print = util.print local println = util.println @@ -31,6 +31,7 @@ cfv.assert_type_bool(config.NETWORKED) cfv.assert_type_int(config.REACTOR_ID) cfv.assert_port(config.SERVER_PORT) cfv.assert_port(config.LISTEN_PORT) +cfv.assert_type_int(config.TRUSTED_RANGE) cfv.assert_type_str(config.LOG_PATH) cfv.assert_type_int(config.LOG_MODE) assert(cfv.valid(), "bad config file: missing/invalid fields") @@ -162,7 +163,7 @@ local function main() -- start comms smem_sys.plc_comms = plc.comms(config.REACTOR_ID, R_PLC_VERSION, smem_dev.modem, config.LISTEN_PORT, config.SERVER_PORT, - smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog) + config.TRUSTED_RANGE, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog) log.debug("init> comms init") else println("boot> starting in offline mode") diff --git a/rtu/config.lua b/rtu/config.lua index 80f9e9e..50122ea 100644 --- a/rtu/config.lua +++ b/rtu/config.lua @@ -6,13 +6,15 @@ local config = {} config.SERVER_PORT = 16000 -- port to listen to incoming packets FROM server config.LISTEN_PORT = 15001 +-- max trusted modem message distance (0 to disable check) +config.TRUSTED_RANGE = 0 -- log path config.LOG_PATH = "/log.txt" -- log mode -- 0 = APPEND (adds to existing file on start) -- 1 = NEW (replaces existing file on start) config.LOG_MODE = 0 --- RTU peripheral devices (name: side/network device name) +-- RTU peripheral devices (named: side/network device name) config.RTU_DEVICES = { { name = "boilerValve_0", @@ -33,17 +35,22 @@ config.RTU_REDSTONE = { -- { -- port = rsio.IO.WASTE_PO, -- side = "top", - -- bundled_color = colors.blue + -- bundled_color = colors.red -- }, -- { -- port = rsio.IO.WASTE_PU, -- side = "top", - -- bundled_color = colors.cyan + -- bundled_color = colors.orange + -- }, + -- { + -- port = rsio.IO.WASTE_POPL, + -- side = "top", + -- bundled_color = colors.yellow -- }, -- { -- port = rsio.IO.WASTE_AM, -- side = "top", - -- bundled_color = colors.purple + -- bundled_color = colors.lime -- } -- } -- } diff --git a/rtu/rtu.lua b/rtu/rtu.lua index 2831cf4..eb75d1a 100644 --- a/rtu/rtu.lua +++ b/rtu/rtu.lua @@ -160,12 +160,13 @@ function rtu.init_unit() end -- RTU Communications ----@param version string ----@param modem table ----@param local_port integer ----@param server_port integer ----@param conn_watchdog watchdog -function rtu.comms(version, modem, local_port, server_port, conn_watchdog) +---@param version string RTU version +---@param modem table modem device +---@param local_port integer local listening port +---@param server_port integer remote server port +---@param range integer trusted device connection range +---@param conn_watchdog watchdog watchdog reference +function rtu.comms(version, modem, local_port, server_port, range, conn_watchdog) local self = { version = version, seq_num = 0, @@ -177,6 +178,15 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog) conn_watchdog = conn_watchdog } + ---@class rtu_comms + local public = {} + + local insert = table.insert + + comms.set_trusted_range(range) + + -- PRIVATE FUNCTIONS -- + -- configure modem channels local function _conf_channels() self.modem.closeAll() @@ -185,13 +195,6 @@ function rtu.comms(version, modem, local_port, server_port, conn_watchdog) _conf_channels() - ---@class rtu_comms - local public = {} - - local insert = table.insert - - -- PRIVATE FUNCTIONS -- - -- send a scada management packet ---@param msg_type SCADA_MGMT_TYPES ---@param msg table diff --git a/rtu/startup.lua b/rtu/startup.lua index 975784d..392c039 100644 --- a/rtu/startup.lua +++ b/rtu/startup.lua @@ -25,7 +25,7 @@ local sna_rtu = require("rtu.dev.sna_rtu") local sps_rtu = require("rtu.dev.sps_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu") -local RTU_VERSION = "beta-v0.9.13" +local RTU_VERSION = "beta-v0.10.0" local rtu_t = types.rtu_t @@ -42,6 +42,7 @@ local cfv = util.new_validator() cfv.assert_port(config.SERVER_PORT) cfv.assert_port(config.LISTEN_PORT) +cfv.assert_type_int(config.TRUSTED_RANGE) cfv.assert_type_str(config.LOG_PATH) cfv.assert_type_int(config.LOG_MODE) cfv.assert_type_table(config.RTU_DEVICES) @@ -390,7 +391,8 @@ local function main() log.debug("boot> conn watchdog started") -- setup comms - smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_dev.modem, config.LISTEN_PORT, config.SERVER_PORT, smem_sys.conn_watchdog) + smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_dev.modem, config.LISTEN_PORT, config.SERVER_PORT, + config.TRUSTED_RANGE, smem_sys.conn_watchdog) log.debug("boot> comms init") -- init threads diff --git a/scada-common/comms.lua b/scada-common/comms.lua index 1234c31..672d4e2 100644 --- a/scada-common/comms.lua +++ b/scada-common/comms.lua @@ -12,6 +12,8 @@ local rtu_t = types.rtu_t local insert = table.insert +local max_distance = nil + comms.version = "1.3.0" ---@alias PROTOCOLS integer @@ -136,6 +138,17 @@ comms.FAC_COMMANDS = FAC_COMMANDS ---@alias packet scada_packet|modbus_packet|rplc_packet|mgmt_packet|crdn_packet|capi_packet ---@alias frame modbus_frame|rplc_frame|mgmt_frame|crdn_frame|capi_frame +-- configure the maximum allowable message receive distance
+-- packets received with distances greater than this will be silently discarded +---@param distance integer max modem message distance (less than 1 disables the limit) +function comms.set_trusted_range(distance) + if distance < 1 then + max_distance = nil + else + max_distance = distance + end +end + -- generic SCADA packet object function comms.scada_packet() local self = { @@ -181,6 +194,10 @@ function comms.scada_packet() self.raw = self.modem_msg_in.msg + if (type(max_distance) == "number") and (distance > max_distance) then + -- outside of maximum allowable transmission distance + -- log.debug("comms.scada_packet.receive(): discarding packet with distance " .. distance .. " outside of trusted range") + else if type(self.raw) == "table" then if #self.raw >= 3 then self.seq_num = self.raw[1] @@ -196,6 +213,7 @@ function comms.scada_packet() self.valid = type(self.seq_num) == "number" and type(self.protocol) == "number" and type(self.payload) == "table" + end end return self.valid diff --git a/supervisor/config.lua b/supervisor/config.lua index b98ceb2..a7ceb7e 100644 --- a/supervisor/config.lua +++ b/supervisor/config.lua @@ -4,6 +4,8 @@ local config = {} config.SCADA_DEV_LISTEN = 16000 -- listen port for SCADA supervisor access by coordinators config.SCADA_SV_LISTEN = 16100 +-- max trusted modem message distance (0 to disable check) +config.TRUSTED_RANGE = 0 -- expected number of reactors config.NUM_REACTORS = 4 -- expected number of boilers/turbines for each reactor diff --git a/supervisor/startup.lua b/supervisor/startup.lua index 79282c0..bb27074 100644 --- a/supervisor/startup.lua +++ b/supervisor/startup.lua @@ -14,7 +14,7 @@ local svsessions = require("supervisor.session.svsessions") local config = require("supervisor.config") local supervisor = require("supervisor.supervisor") -local SUPERVISOR_VERSION = "beta-v0.9.14" +local SUPERVISOR_VERSION = "beta-v0.10.0" local print = util.print local println = util.println @@ -29,6 +29,7 @@ local cfv = util.new_validator() cfv.assert_port(config.SCADA_DEV_LISTEN) cfv.assert_port(config.SCADA_SV_LISTEN) +cfv.assert_type_int(config.TRUSTED_RANGE) cfv.assert_type_int(config.NUM_REACTORS) cfv.assert_type_table(config.REACTOR_COOLING) cfv.assert_type_str(config.LOG_PATH) @@ -81,7 +82,7 @@ local function main() -- start comms, open all channels local superv_comms = supervisor.comms(SUPERVISOR_VERSION, config.NUM_REACTORS, config.REACTOR_COOLING, modem, - config.SCADA_DEV_LISTEN, config.SCADA_SV_LISTEN) + config.SCADA_DEV_LISTEN, config.SCADA_SV_LISTEN, config.TRUSTED_RANGE) -- base loop clock (6.67Hz, 3 ticks) local MAIN_CLOCK = 0.15 diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua index b86e0e6..12f5291 100644 --- a/supervisor/supervisor.lua +++ b/supervisor/supervisor.lua @@ -9,9 +9,7 @@ local supervisor = {} local PROTOCOLS = comms.PROTOCOLS local DEVICE_TYPES = comms.DEVICE_TYPES local ESTABLISH_ACK = comms.ESTABLISH_ACK -local RPLC_TYPES = comms.RPLC_TYPES local SCADA_MGMT_TYPES = comms.SCADA_MGMT_TYPES -local SCADA_CRDN_TYPES = comms.SCADA_CRDN_TYPES local print = util.print local println = util.println @@ -19,13 +17,14 @@ local print_ts = util.print_ts local println_ts = util.println_ts -- supervisory controller communications ----@param version string ----@param num_reactors integer ----@param cooling_conf table ----@param modem table ----@param dev_listen integer ----@param coord_listen integer -function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen, coord_listen) +---@param version string supervisor version +---@param num_reactors integer number of reactors +---@param cooling_conf table cooling configuration table +---@param modem table modem device +---@param dev_listen integer listening port for PLC/RTU devices +---@param coord_listen integer listening port for coordinator +---@param range integer trusted device connection range +function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen, coord_listen, range) local self = { version = version, num_reactors = num_reactors, @@ -38,6 +37,8 @@ function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen ---@class superv_comms local public = {} + comms.set_trusted_range(range) + -- PRIVATE FUNCTIONS -- -- configure modem channels @@ -205,12 +206,12 @@ function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen if plc_id == false then -- reactor already has a PLC assigned - log.debug(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id)) + log.warning(util.c("PLC_ESTABLISH: assignment collision with reactor ", reactor_id)) _send_dev_establish(next_seq_id, r_port, { ESTABLISH_ACK.COLLISION }) else -- got an ID; assigned to a reactor successfully - println(util.c("reactor ", reactor_id, " PLC (", firmware_v, ") [:", r_port, "] \xbb connected")) - log.debug(util.c("PLC_ESTABLISH: link accepted for PLC (", firmware_v, ") [:", r_port, "] connected with session ID ", plc_id)) + println(util.c("PLC (", firmware_v, ") [:", r_port, "] \xbb reactor ", reactor_id, " connected")) + log.info(util.c("PLC_ESTABLISH: PLC (", firmware_v, ") [:", r_port, "] reactor unit ", reactor_id, " PLC connected with session ID ", plc_id)) _send_dev_establish(next_seq_id, r_port, { ESTABLISH_ACK.ALLOW }) end else @@ -224,7 +225,7 @@ function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen local s_id = svsessions.establish_rtu_session(l_port, r_port, rtu_advert, firmware_v) println(util.c("RTU (", firmware_v, ") [:", r_port, "] \xbb connected")) - log.debug(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [:", r_port, "] connected with session ID ", s_id)) + log.info(util.c("RTU_ESTABLISH: RTU (",firmware_v, ") [:", r_port, "] connected with session ID ", s_id)) _send_dev_establish(next_seq_id, r_port, { ESTABLISH_ACK.ALLOW }) else log.debug("RTU_ESTABLISH: packet length mismatch") @@ -286,8 +287,8 @@ function supervisor.comms(version, num_reactors, cooling_conf, modem, dev_listen table.insert(config, cooling_conf[i].TURBINES) end - println(util.c("coordinator (",firmware_v, ") [:", r_port, "] \xbb connected")) - log.debug(util.c("CRDN_ESTABLISH: coordinator (",firmware_v, ") [:", r_port, "] connected with session ID ", s_id)) + println(util.c("CRD (",firmware_v, ") [:", r_port, "] \xbb connected")) + log.info(util.c("CRDN_ESTABLISH: coordinator (",firmware_v, ") [:", r_port, "] connected with session ID ", s_id)) _send_crdn_establish(next_seq_id, r_port, { ESTABLISH_ACK.ALLOW, config }) else log.debug("CRDN_ESTABLISH: denied new coordinator due to already being connected to another coordinator")