#76 added trusted connection ranges for modem messages

This commit is contained in:
Mikayla Fischler 2023-02-07 17:31:22 -05:00
parent 1d3a1672c8
commit 6c09772a74
13 changed files with 109 additions and 62 deletions

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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
-- }
-- }
-- }

View File

@ -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

View File

@ -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

View File

@ -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 <br/>
-- 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

View File

@ -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

View File

@ -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

View File

@ -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")