mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.6 KiB
Rust
149 lines
4.6 KiB
Rust
/* Copyright (C) 2021 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
use super::modbus::ModbusTransaction;
|
|
use crate::jsonbuilder::{JsonBuilder, JsonError};
|
|
|
|
use sawp_modbus::{Data, Message, Read, Write};
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rs_modbus_to_json(tx: &mut ModbusTransaction, js: &mut JsonBuilder) -> bool {
|
|
log(tx, js).is_ok()
|
|
}
|
|
|
|
/// populate a json object with transactional information, for logging
|
|
fn log(tx: &ModbusTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
|
js.open_object("modbus")?;
|
|
js.set_uint("id", tx.id)?;
|
|
|
|
if let Some(req) = &tx.request {
|
|
js.open_object("request")?;
|
|
log_message(req, js)?;
|
|
js.close()?;
|
|
}
|
|
|
|
if let Some(resp) = &tx.response {
|
|
js.open_object("response")?;
|
|
log_message(resp, js)?;
|
|
js.close()?;
|
|
}
|
|
|
|
js.close()?;
|
|
Ok(())
|
|
}
|
|
|
|
fn log_message(msg: &Message, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
|
js.set_uint("transaction_id", msg.transaction_id.into())?;
|
|
js.set_uint("protocol_id", msg.protocol_id.into())?;
|
|
js.set_uint("unit_id", msg.unit_id.into())?;
|
|
js.set_uint("function_raw", msg.function.raw.into())?;
|
|
js.set_string("function_code", &msg.function.code.to_string())?;
|
|
js.set_string("access_type", &msg.access_type.to_string())?;
|
|
js.set_string("category", &msg.category.to_string())?;
|
|
js.set_string("error_flags", &msg.error_flags.to_string())?;
|
|
|
|
match &msg.data {
|
|
Data::Exception(exc) => {
|
|
js.open_object("exception")?;
|
|
js.set_uint("raw", exc.raw.into())?;
|
|
js.set_string("code", &exc.code.to_string())?;
|
|
js.close()?;
|
|
}
|
|
Data::Diagnostic { func, data } => {
|
|
js.open_object("diagnostic")?;
|
|
js.set_uint("raw", func.raw.into())?;
|
|
js.set_string("code", &func.code.to_string())?;
|
|
js.set_string_from_bytes("data", data)?;
|
|
js.close()?;
|
|
}
|
|
Data::MEI { mei_type, data } => {
|
|
js.open_object("mei")?;
|
|
js.set_uint("raw", mei_type.raw.into())?;
|
|
js.set_string("code", &mei_type.code.to_string())?;
|
|
js.set_string_from_bytes("data", data)?;
|
|
js.close()?;
|
|
}
|
|
Data::Read(read) => {
|
|
js.open_object("read")?;
|
|
log_read(read, js)?;
|
|
js.close()?;
|
|
}
|
|
Data::Write(write) => {
|
|
js.open_object("write")?;
|
|
log_write(write, js)?;
|
|
js.close()?;
|
|
}
|
|
Data::ReadWrite { read, write } => {
|
|
js.open_object("read")?;
|
|
log_read(read, js)?;
|
|
js.close()?;
|
|
js.open_object("write")?;
|
|
log_write(write, js)?;
|
|
js.close()?;
|
|
}
|
|
Data::ByteVec(data) => {
|
|
js.set_string_from_bytes("data", data)?;
|
|
}
|
|
Data::Empty => {}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn log_read(read: &Read, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
|
match read {
|
|
Read::Request { address, quantity } => {
|
|
js.set_uint("address", (*address).into())?;
|
|
js.set_uint("quantity", (*quantity).into())?;
|
|
}
|
|
Read::Response(data) => {
|
|
js.set_string_from_bytes("data", data)?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn log_write(write: &Write, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
|
match write {
|
|
Write::MultReq {
|
|
address,
|
|
quantity,
|
|
data,
|
|
} => {
|
|
js.set_uint("address", (*address).into())?;
|
|
js.set_uint("quantity", (*quantity).into())?;
|
|
js.set_string_from_bytes("data", data)?;
|
|
}
|
|
Write::Mask {
|
|
address,
|
|
and_mask,
|
|
or_mask,
|
|
} => {
|
|
js.set_uint("address", (*address).into())?;
|
|
js.set_uint("and_mask", (*and_mask).into())?;
|
|
js.set_uint("or_mask", (*or_mask).into())?;
|
|
}
|
|
Write::Other { address, data } => {
|
|
js.set_uint("address", (*address).into())?;
|
|
js.set_uint("data", (*data).into())?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|