Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/rust/src/modbus/log.rs
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2021 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
use super::modbus::ModbusTransaction;
19
use crate::jsonbuilder::{JsonBuilder, JsonError};
20
21
use sawp_modbus::{Data, Message, Read, Write};
22
23
#[no_mangle]
24
10.8k
pub extern "C" fn rs_modbus_to_json(tx: &mut ModbusTransaction, js: &mut JsonBuilder) -> bool {
25
10.8k
    log(tx, js).is_ok()
26
10.8k
}
27
28
/// populate a json object with transactional information, for logging
29
10.8k
fn log(tx: &ModbusTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
30
10.8k
    js.open_object("modbus")?;
31
10.8k
    js.set_uint("id", tx.id)?;
32
33
10.8k
    if let Some(req) = &tx.request {
34
6.73k
        js.open_object("request")?;
35
6.73k
        log_message(req, js)?;
36
6.73k
        js.close()?;
37
4.14k
    }
38
39
10.8k
    if let Some(resp) = &tx.response {
40
5.24k
        js.open_object("response")?;
41
5.24k
        log_message(resp, js)?;
42
5.24k
        js.close()?;
43
5.64k
    }
44
45
10.8k
    js.close()?;
46
10.8k
    Ok(())
47
10.8k
}
48
49
11.9k
fn log_message(msg: &Message, js: &mut JsonBuilder) -> Result<(), JsonError> {
50
11.9k
    js.set_uint("transaction_id", msg.transaction_id.into())?;
51
11.9k
    js.set_uint("protocol_id", msg.protocol_id.into())?;
52
11.9k
    js.set_uint("unit_id", msg.unit_id.into())?;
53
11.9k
    js.set_uint("function_raw", msg.function.raw.into())?;
54
11.9k
    js.set_string("function_code", &msg.function.code.to_string())?;
55
11.9k
    js.set_string("access_type", &msg.access_type.to_string())?;
56
11.9k
    js.set_string("category", &msg.category.to_string())?;
57
11.9k
    js.set_string("error_flags", &msg.error_flags.to_string())?;
58
59
11.9k
    match &msg.data {
60
148
        Data::Exception(exc) => {
61
148
            js.open_object("exception")?;
62
148
            js.set_uint("raw", exc.raw.into())?;
63
148
            js.set_string("code", &exc.code.to_string())?;
64
148
            js.close()?;
65
        }
66
31
        Data::Diagnostic { func, data } => {
67
31
            js.open_object("diagnostic")?;
68
31
            js.set_uint("raw", func.raw.into())?;
69
31
            js.set_string("code", &func.code.to_string())?;
70
31
            js.set_string_from_bytes("data", data)?;
71
31
            js.close()?;
72
        }
73
22
        Data::MEI { mei_type, data } => {
74
22
            js.open_object("mei")?;
75
22
            js.set_uint("raw", mei_type.raw.into())?;
76
22
            js.set_string("code", &mei_type.code.to_string())?;
77
22
            js.set_string_from_bytes("data", data)?;
78
22
            js.close()?;
79
        }
80
551
        Data::Read(read) => {
81
551
            js.open_object("read")?;
82
551
            log_read(read, js)?;
83
551
            js.close()?;
84
        }
85
846
        Data::Write(write) => {
86
846
            js.open_object("write")?;
87
846
            log_write(write, js)?;
88
846
            js.close()?;
89
        }
90
0
        Data::ReadWrite { read, write } => {
91
0
            js.open_object("read")?;
92
0
            log_read(read, js)?;
93
0
            js.close()?;
94
0
            js.open_object("write")?;
95
0
            log_write(write, js)?;
96
0
            js.close()?;
97
        }
98
1.28k
        Data::ByteVec(data) => {
99
1.28k
            js.set_string_from_bytes("data", data)?;
100
        }
101
9.09k
        Data::Empty => {}
102
    }
103
104
11.9k
    Ok(())
105
11.9k
}
106
107
551
fn log_read(read: &Read, js: &mut JsonBuilder) -> Result<(), JsonError> {
108
551
    match read {
109
272
        Read::Request { address, quantity } => {
110
272
            js.set_uint("address", (*address).into())?;
111
272
            js.set_uint("quantity", (*quantity).into())?;
112
        }
113
279
        Read::Response(data) => {
114
279
            js.set_string_from_bytes("data", data)?;
115
        }
116
    }
117
118
551
    Ok(())
119
551
}
120
121
846
fn log_write(write: &Write, js: &mut JsonBuilder) -> Result<(), JsonError> {
122
846
    match write {
123
        Write::MultReq {
124
361
            address,
125
361
            quantity,
126
361
            data,
127
361
        } => {
128
361
            js.set_uint("address", (*address).into())?;
129
361
            js.set_uint("quantity", (*quantity).into())?;
130
361
            js.set_string_from_bytes("data", data)?;
131
        }
132
        Write::Mask {
133
63
            address,
134
63
            and_mask,
135
63
            or_mask,
136
63
        } => {
137
63
            js.set_uint("address", (*address).into())?;
138
63
            js.set_uint("and_mask", (*and_mask).into())?;
139
63
            js.set_uint("or_mask", (*or_mask).into())?;
140
        }
141
422
        Write::Other { address, data } => {
142
422
            js.set_uint("address", (*address).into())?;
143
422
            js.set_uint("data", (*data).into())?;
144
        }
145
    }
146
147
846
    Ok(())
148
846
}