Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/modbus/modbus.rs
Line
Count
Source
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
use crate::applayer::{self, *};
18
use crate::core::{self, AppProto, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_TCP};
19
20
use std::ffi::CString;
21
22
use sawp::error::Error as SawpError;
23
use sawp::error::ErrorKind as SawpErrorKind;
24
use sawp::parser::{Direction, Parse};
25
use sawp::probe::{Probe, Status};
26
use sawp_modbus::{self, AccessType, ErrorFlags, Flags, Message};
27
28
pub const REQUEST_FLOOD: usize = 500; // Default unreplied Modbus requests are considered a flood
29
pub const MODBUS_PARSER: sawp_modbus::Modbus = sawp_modbus::Modbus { probe_strict: true };
30
31
static mut ALPROTO_MODBUS: AppProto = ALPROTO_UNKNOWN;
32
33
#[derive(AppLayerEvent)]
34
enum ModbusEvent {
35
    UnsolicitedResponse,
36
    InvalidFunctionCode,
37
    InvalidLength,
38
    InvalidValue,
39
    InvalidExceptionCode,
40
    ValueMismatch,
41
    Flooded,
42
    InvalidProtocolId,
43
}
44
pub struct ModbusTransaction {
45
    pub id: u64,
46
47
    pub request: Option<Message>,
48
    pub response: Option<Message>,
49
50
    pub tx_data: AppLayerTxData,
51
}
52
53
impl Transaction for ModbusTransaction {
54
125M
    fn id(&self) -> u64 {
55
125M
        self.id
56
125M
    }
57
}
58
59
impl ModbusTransaction {
60
1.77M
    pub fn new(id: u64) -> Self {
61
1.77M
        Self {
62
1.77M
            id,
63
1.77M
            request: None,
64
1.77M
            response: None,
65
1.77M
            tx_data: AppLayerTxData::new(),
66
1.77M
        }
67
1.77M
    }
68
69
3.64M
    fn set_event(&mut self, event: ModbusEvent) {
70
3.64M
        self.tx_data.set_event(event as u8);
71
3.64M
    }
72
73
1.94M
    fn set_events_from_flags(&mut self, flags: &Flags<ErrorFlags>) {
74
1.94M
        if flags.intersects(ErrorFlags::FUNC_CODE) {
75
18.7k
            self.set_event(ModbusEvent::InvalidFunctionCode);
76
1.92M
        }
77
1.94M
        if flags.intersects(ErrorFlags::DATA_VALUE) {
78
22.7k
            self.set_event(ModbusEvent::InvalidValue);
79
1.92M
        }
80
1.94M
        if flags.intersects(ErrorFlags::DATA_LENGTH) {
81
1.83M
            self.set_event(ModbusEvent::InvalidLength);
82
1.83M
        }
83
1.94M
        if flags.intersects(ErrorFlags::EXC_CODE) {
84
21.5k
            self.set_event(ModbusEvent::InvalidExceptionCode);
85
1.92M
        }
86
1.94M
        if flags.intersects(ErrorFlags::PROTO_ID) {
87
302k
            self.set_event(ModbusEvent::InvalidProtocolId);
88
1.64M
        }
89
1.94M
    }
90
}
91
92
#[derive(Default)]
93
pub struct ModbusState {
94
    state_data: AppLayerStateData,
95
    pub transactions: Vec<ModbusTransaction>,
96
    tx_id: u64,
97
    givenup: bool, // Indicates flood
98
}
99
100
impl State<ModbusTransaction> for ModbusState {
101
48.2M
    fn get_transaction_count(&self) -> usize {
102
48.2M
        self.transactions.len()
103
48.2M
    }
104
105
77.2M
    fn get_transaction_by_index(&self, index: usize) -> Option<&ModbusTransaction> {
106
77.2M
        self.transactions.get(index)
107
77.2M
    }
108
}
109
110
impl ModbusState {
111
7.64k
    pub fn new() -> Self {
112
7.64k
        Default::default()
113
7.64k
    }
114
115
18.9k
    pub fn get_tx(&mut self, tx_id: u64) -> Option<&mut ModbusTransaction> {
116
2.21M
        self.transactions.iter_mut().find(|tx| tx.id == tx_id + 1)
117
18.9k
    }
118
119
    /// Searches the requests in order to find one matching the given response. Returns the matching
120
    /// transaction, if it exists
121
1.61M
    pub fn find_request_and_validate(
122
1.61M
        &mut self, resp: &mut Message,
123
1.61M
    ) -> Option<&mut ModbusTransaction> {
124
208M
        for tx in &mut self.transactions {
125
207M
            if let Some(req) = &tx.request {
126
20.5M
                if tx.response.is_none() && resp.matches(req) {
127
204k
                    tx.tx_data.updated_tc = true;
128
204k
                    tx.tx_data.updated_ts = true;
129
204k
                    return Some(tx);
130
20.3M
                }
131
186M
            }
132
        }
133
1.40M
        None
134
1.61M
    }
135
136
    /// Searches the responses in order to find one matching the given request. Returns the matching
137
    /// transaction, if it exists
138
365k
    pub fn find_response_and_validate(
139
365k
        &mut self, req: &mut Message,
140
365k
    ) -> Option<&mut ModbusTransaction> {
141
36.2M
        for tx in &mut self.transactions {
142
35.8M
            if let Some(resp) = &tx.response {
143
502k
                if tx.request.is_none() && req.matches(resp) {
144
2.95k
                    tx.tx_data.updated_tc = true;
145
2.95k
                    tx.tx_data.updated_ts = true;
146
2.95k
                    return Some(tx);
147
499k
                }
148
35.3M
            }
149
        }
150
362k
        None
151
365k
    }
152
153
1.77M
    pub fn new_tx(&mut self) -> Option<ModbusTransaction> {
154
        // Check flood limit
155
1.77M
        if self.givenup {
156
92
            return None;
157
1.77M
        }
158
159
1.77M
        self.tx_id += 1;
160
1.77M
        let mut tx = ModbusTransaction::new(self.tx_id);
161
162
1.77M
        if REQUEST_FLOOD != 0 && self.transactions.len() >= REQUEST_FLOOD {
163
474
            tx.set_event(ModbusEvent::Flooded);
164
474
            self.givenup = true;
165
1.77M
        }
166
167
1.77M
        Some(tx)
168
1.77M
    }
169
170
1.58M
    pub fn free_tx(&mut self, tx_id: u64) {
171
21.1M
        if let Some(index) = self.transactions.iter().position(|tx| tx.id == tx_id + 1) {
172
1.58M
            self.transactions.remove(index);
173
174
            // Check flood limit
175
1.58M
            if self.givenup && REQUEST_FLOOD != 0 && self.transactions.len() < REQUEST_FLOOD {
176
386
                self.givenup = false;
177
1.58M
            }
178
0
        }
179
1.58M
    }
180
181
414k
    pub fn parse(&mut self, input: &[u8], direction: Direction) -> AppLayerResult {
182
414k
        let mut rest = input;
183
2.39M
        while !rest.is_empty() {
184
2.21M
            match MODBUS_PARSER.parse(rest, direction.clone()) {
185
1.97M
                Ok((inner_rest, Some(mut msg))) => {
186
1.97M
                    match direction {
187
                        Direction::ToServer | Direction::Unknown => {
188
365k
                            match self.find_response_and_validate(&mut msg) {
189
2.95k
                                Some(tx) => {
190
2.95k
                                    tx.set_events_from_flags(&msg.error_flags);
191
2.95k
                                    tx.tx_data.updated_tc = true;
192
2.95k
                                    tx.tx_data.updated_ts = true;
193
2.95k
                                    tx.request = Some(msg);
194
2.95k
                                }
195
                                None => {
196
362k
                                    let mut tx = match self.new_tx() {
197
362k
                                        Some(tx) => tx,
198
66
                                        None => return AppLayerResult::err(),
199
                                    };
200
362k
                                    tx.set_events_from_flags(&msg.error_flags);
201
362k
                                    tx.request = Some(msg);
202
362k
                                    self.transactions.push(tx);
203
                                }
204
                            }
205
                        }
206
1.61M
                        Direction::ToClient => match self.find_request_and_validate(&mut msg) {
207
204k
                            Some(tx) => {
208
204k
                                if msg
209
204k
                                    .access_type
210
204k
                                    .intersects(AccessType::READ | AccessType::WRITE)
211
19.3k
                                    && msg.error_flags.intersects(
212
19.3k
                                        ErrorFlags::DATA_LENGTH | ErrorFlags::DATA_VALUE,
213
                                    )
214
17.5k
                                {
215
17.5k
                                    tx.set_event(ModbusEvent::ValueMismatch);
216
186k
                                } else {
217
186k
                                    tx.set_events_from_flags(&msg.error_flags);
218
186k
                                }
219
204k
                                tx.tx_data.updated_tc = true;
220
204k
                                tx.tx_data.updated_ts = true;
221
204k
                                tx.response = Some(msg);
222
                            }
223
                            None => {
224
1.40M
                                let mut tx = match self.new_tx() {
225
1.40M
                                    Some(tx) => tx,
226
26
                                    None => return AppLayerResult::err(),
227
                                };
228
1.40M
                                if msg
229
1.40M
                                    .access_type
230
1.40M
                                    .intersects(AccessType::READ | AccessType::WRITE)
231
19.2k
                                    && msg.error_flags.intersects(
232
19.2k
                                        ErrorFlags::DATA_LENGTH | ErrorFlags::DATA_VALUE,
233
                                    )
234
16.4k
                                {
235
16.4k
                                    tx.set_event(ModbusEvent::ValueMismatch);
236
1.39M
                                } else {
237
1.39M
                                    tx.set_events_from_flags(&msg.error_flags);
238
1.39M
                                }
239
1.40M
                                tx.response = Some(msg);
240
1.40M
                                tx.set_event(ModbusEvent::UnsolicitedResponse);
241
1.40M
                                self.transactions.push(tx);
242
                            }
243
                        },
244
                    }
245
246
1.97M
                    if inner_rest.len() >= rest.len() {
247
0
                        return AppLayerResult::err();
248
1.97M
                    }
249
1.97M
                    rest = inner_rest;
250
                }
251
0
                Ok((inner_rest, None)) => {
252
0
                    return AppLayerResult::incomplete(
253
0
                        (input.len() - inner_rest.len()) as u32,
254
0
                        inner_rest.len() as u32 + 1,
255
                    );
256
                }
257
                Err(SawpError {
258
238k
                    kind: SawpErrorKind::Incomplete(sawp::error::Needed::Size(needed)),
259
                }) => {
260
238k
                    return AppLayerResult::incomplete(
261
238k
                        (input.len() - rest.len()) as u32,
262
238k
                        (rest.len() + needed.get()) as u32,
263
                    );
264
                }
265
                Err(SawpError {
266
                    kind: SawpErrorKind::Incomplete(sawp::error::Needed::Unknown),
267
                }) => {
268
0
                    return AppLayerResult::incomplete(
269
0
                        (input.len() - rest.len()) as u32,
270
0
                        rest.len() as u32 + 1,
271
                    );
272
                }
273
0
                Err(_) => return AppLayerResult::err(),
274
            }
275
        }
276
175k
        AppLayerResult::ok()
277
414k
    }
278
}
279
280
/// Probe input to see if it looks like Modbus.
281
#[no_mangle]
282
54.2k
pub extern "C" fn rs_modbus_probe(
283
54.2k
    _flow: *const core::Flow, _direction: u8, input: *const u8, len: u32, _rdir: *mut u8,
284
54.2k
) -> AppProto {
285
54.2k
    if input.is_null() {
286
14.8k
        return ALPROTO_UNKNOWN;
287
39.4k
    }
288
39.4k
    let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, len as usize) };
289
39.4k
    match MODBUS_PARSER.probe(slice, Direction::Unknown) {
290
26.9k
        Status::Recognized => unsafe { ALPROTO_MODBUS },
291
9.98k
        Status::Incomplete => ALPROTO_UNKNOWN,
292
2.48k
        Status::Unrecognized => unsafe { ALPROTO_FAILED },
293
    }
294
54.2k
}
295
296
#[no_mangle]
297
7.64k
pub extern "C" fn rs_modbus_state_new(
298
7.64k
    _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
299
7.64k
) -> *mut std::os::raw::c_void {
300
7.64k
    Box::into_raw(Box::new(ModbusState::new())) as *mut std::os::raw::c_void
301
7.64k
}
302
303
#[no_mangle]
304
7.64k
pub extern "C" fn rs_modbus_state_free(state: *mut std::os::raw::c_void) {
305
7.64k
    let _state: Box<ModbusState> = unsafe { Box::from_raw(state as *mut ModbusState) };
306
7.64k
}
307
308
#[no_mangle]
309
1.58M
pub unsafe extern "C" fn rs_modbus_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
310
1.58M
    let state = cast_pointer!(state, ModbusState);
311
1.58M
    state.free_tx(tx_id);
312
1.58M
}
313
314
#[no_mangle]
315
198k
pub unsafe extern "C" fn rs_modbus_parse_request(
316
198k
    _flow: *const core::Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void,
317
198k
    stream_slice: StreamSlice,
318
198k
    _data: *const std::os::raw::c_void,
319
198k
) -> AppLayerResult {
320
198k
    let buf = stream_slice.as_slice();
321
198k
    if buf.is_empty() {
322
1.46k
        if AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) > 0 {
323
1.46k
            return AppLayerResult::ok();
324
        } else {
325
0
            return AppLayerResult::err();
326
        }
327
196k
    }
328
329
196k
    let state = cast_pointer!(state, ModbusState);
330
196k
    state.parse(buf, Direction::ToServer)
331
198k
}
332
333
#[no_mangle]
334
218k
pub unsafe extern "C" fn rs_modbus_parse_response(
335
218k
    _flow: *const core::Flow, state: *mut std::os::raw::c_void, pstate: *mut std::os::raw::c_void,
336
218k
    stream_slice: StreamSlice,
337
218k
    _data: *const std::os::raw::c_void,
338
218k
) -> AppLayerResult {
339
218k
    let buf = stream_slice.as_slice();
340
218k
    if buf.is_empty() {
341
285
        if AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) > 0 {
342
285
            return AppLayerResult::ok();
343
        } else {
344
0
            return AppLayerResult::err();
345
        }
346
218k
    }
347
348
218k
    let state = cast_pointer!(state, ModbusState);
349
218k
    state.parse(buf, Direction::ToClient)
350
218k
}
351
352
#[no_mangle]
353
1.35M
pub unsafe extern "C" fn rs_modbus_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
354
1.35M
    let state = cast_pointer!(state, ModbusState);
355
1.35M
    state.tx_id
356
1.35M
}
357
358
#[no_mangle]
359
18.9k
pub unsafe extern "C" fn rs_modbus_state_get_tx(
360
18.9k
    state: *mut std::os::raw::c_void, tx_id: u64,
361
18.9k
) -> *mut std::os::raw::c_void {
362
18.9k
    let state = cast_pointer!(state, ModbusState);
363
18.9k
    match state.get_tx(tx_id) {
364
18.7k
        Some(tx) => (tx as *mut ModbusTransaction) as *mut std::os::raw::c_void,
365
212
        None => std::ptr::null_mut(),
366
    }
367
18.9k
}
368
369
#[no_mangle]
370
49.9M
pub unsafe extern "C" fn rs_modbus_tx_get_alstate_progress(
371
49.9M
    tx: *mut std::os::raw::c_void, _direction: u8,
372
49.9M
) -> std::os::raw::c_int {
373
49.9M
    let tx = cast_pointer!(tx, ModbusTransaction);
374
49.9M
    tx.response.is_some() as std::os::raw::c_int
375
49.9M
}
376
377
#[no_mangle]
378
48.2M
pub unsafe extern "C" fn rs_modbus_state_get_tx_data(
379
48.2M
    tx: *mut std::os::raw::c_void,
380
48.2M
) -> *mut AppLayerTxData {
381
48.2M
    let tx = cast_pointer!(tx, ModbusTransaction);
382
48.2M
    &mut tx.tx_data
383
48.2M
}
384
385
export_state_data_get!(rs_modbus_get_state_data, ModbusState);
386
387
#[no_mangle]
388
34
pub unsafe extern "C" fn rs_modbus_register_parser() {
389
34
    let default_port = std::ffi::CString::new("[502]").unwrap();
390
34
    let parser = RustParser {
391
34
        name: b"modbus\0".as_ptr() as *const std::os::raw::c_char,
392
34
        default_port: default_port.as_ptr(),
393
34
        ipproto: IPPROTO_TCP,
394
34
        probe_ts: Some(rs_modbus_probe),
395
34
        probe_tc: Some(rs_modbus_probe),
396
34
        min_depth: 0,
397
34
        max_depth: 16,
398
34
        state_new: rs_modbus_state_new,
399
34
        state_free: rs_modbus_state_free,
400
34
        tx_free: rs_modbus_state_tx_free,
401
34
        parse_ts: rs_modbus_parse_request,
402
34
        parse_tc: rs_modbus_parse_response,
403
34
        get_tx_count: rs_modbus_state_get_tx_count,
404
34
        get_tx: rs_modbus_state_get_tx,
405
34
        tx_comp_st_ts: 1,
406
34
        tx_comp_st_tc: 1,
407
34
        tx_get_progress: rs_modbus_tx_get_alstate_progress,
408
34
        get_eventinfo: Some(ModbusEvent::get_event_info),
409
34
        get_eventinfo_byid: Some(ModbusEvent::get_event_info_by_id),
410
34
        localstorage_new: None,
411
34
        localstorage_free: None,
412
34
        get_tx_files: None,
413
34
        get_tx_iterator: Some(applayer::state_get_tx_iterator::<ModbusState, ModbusTransaction>),
414
34
        get_tx_data: rs_modbus_state_get_tx_data,
415
34
        get_state_data: rs_modbus_get_state_data,
416
34
        apply_tx_config: None,
417
34
        flags: 0,
418
34
        truncate: None,
419
34
        get_frame_id_by_name: None,
420
34
        get_frame_name_by_id: None,
421
34
    };
422
423
34
    let ip_proto_str = CString::new("tcp").unwrap();
424
34
    if AppLayerProtoDetectConfProtoDetectionEnabledDefault(ip_proto_str.as_ptr(), parser.name, false) != 0 {
425
34
        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
426
34
        ALPROTO_MODBUS = alproto;
427
34
        if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
428
34
            let _ = AppLayerRegisterParser(&parser, alproto);
429
34
        }
430
0
    }
431
34
}
432
433
// This struct and accessor functions are used for app-layer-modbus.c tests.
434
pub mod test {
435
    use super::ModbusState;
436
    use sawp_modbus::{Data, Message, Read, Write};
437
    use std::ffi::c_void;
438
    #[repr(C)]
439
    pub struct ModbusMessage(*const c_void);
440
441
    #[no_mangle]
442
0
    pub unsafe extern "C" fn rs_modbus_message_get_function(msg: *const ModbusMessage) -> u8 {
443
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
444
0
        let msg = msg.as_ref().unwrap();
445
0
        msg.function.raw
446
0
    }
447
448
    #[no_mangle]
449
0
    pub unsafe extern "C" fn rs_modbus_message_get_subfunction(msg: *const ModbusMessage) -> u16 {
450
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
451
0
        let msg = msg.as_ref().unwrap();
452
0
        if let Data::Diagnostic { func, data: _ } = &msg.data {
453
0
            func.raw
454
        } else {
455
0
            panic!("wrong modbus message data type");
456
        }
457
0
    }
458
459
    #[no_mangle]
460
0
    pub unsafe extern "C" fn rs_modbus_message_get_read_request_address(
461
0
        msg: *const ModbusMessage,
462
0
    ) -> u16 {
463
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
464
0
        let msg = msg.as_ref().unwrap();
465
        if let Data::Read(Read::Request {
466
0
            address,
467
            quantity: _,
468
0
        }) = &msg.data
469
        {
470
0
            *address
471
        } else {
472
0
            panic!("wrong modbus message data type");
473
        }
474
0
    }
475
476
    #[no_mangle]
477
0
    pub unsafe extern "C" fn rs_modbus_message_get_read_request_quantity(
478
0
        msg: *const ModbusMessage,
479
0
    ) -> u16 {
480
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
481
0
        let msg = msg.as_ref().unwrap();
482
        if let Data::Read(Read::Request {
483
            address: _,
484
0
            quantity,
485
0
        }) = &msg.data
486
        {
487
0
            *quantity
488
        } else {
489
0
            panic!("wrong modbus message data type");
490
        }
491
0
    }
492
493
    #[no_mangle]
494
0
    pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_read_address(
495
0
        msg: *const ModbusMessage,
496
0
    ) -> u16 {
497
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
498
0
        let msg = msg.as_ref().unwrap();
499
        if let Data::ReadWrite {
500
            read:
501
                Read::Request {
502
0
                    address,
503
                    quantity: _,
504
                },
505
            write: _,
506
0
        } = &msg.data
507
        {
508
0
            *address
509
        } else {
510
0
            panic!("wrong modbus message data type");
511
        }
512
0
    }
513
514
    #[no_mangle]
515
0
    pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_read_quantity(
516
0
        msg: *const ModbusMessage,
517
0
    ) -> u16 {
518
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
519
0
        let msg = msg.as_ref().unwrap();
520
        if let Data::ReadWrite {
521
            read:
522
                Read::Request {
523
                    address: _,
524
0
                    quantity,
525
                },
526
            write: _,
527
0
        } = &msg.data
528
        {
529
0
            *quantity
530
        } else {
531
0
            panic!("wrong modbus message data type");
532
        }
533
0
    }
534
535
    #[no_mangle]
536
0
    pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_write_address(
537
0
        msg: *const ModbusMessage,
538
0
    ) -> u16 {
539
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
540
0
        let msg = msg.as_ref().unwrap();
541
        if let Data::ReadWrite {
542
            read: _,
543
            write:
544
                Write::MultReq {
545
0
                    address,
546
                    quantity: _,
547
                    data: _,
548
                },
549
0
        } = &msg.data
550
        {
551
0
            *address
552
        } else {
553
0
            panic!("wrong modbus message data type");
554
        }
555
0
    }
556
557
    #[no_mangle]
558
0
    pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_write_quantity(
559
0
        msg: *const ModbusMessage,
560
0
    ) -> u16 {
561
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
562
0
        let msg = msg.as_ref().unwrap();
563
        if let Data::ReadWrite {
564
            read: _,
565
            write:
566
                Write::MultReq {
567
                    address: _,
568
0
                    quantity,
569
                    data: _,
570
                },
571
0
        } = &msg.data
572
        {
573
0
            *quantity
574
        } else {
575
0
            panic!("wrong modbus message data type");
576
        }
577
0
    }
578
579
    #[no_mangle]
580
0
    pub unsafe extern "C" fn rs_modbus_message_get_rw_multreq_write_data(
581
0
        msg: *const ModbusMessage, data_len: *mut usize,
582
0
    ) -> *const u8 {
583
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
584
0
        let msg = msg.as_ref().unwrap();
585
        if let Data::ReadWrite {
586
            read: _,
587
            write:
588
                Write::MultReq {
589
                    address: _,
590
                    quantity: _,
591
0
                    data,
592
                },
593
0
        } = &msg.data
594
        {
595
0
            *data_len = data.len();
596
0
            data.as_slice().as_ptr()
597
        } else {
598
0
            panic!("wrong modbus message data type");
599
        }
600
0
    }
601
602
    #[no_mangle]
603
0
    pub unsafe extern "C" fn rs_modbus_message_get_write_multreq_address(
604
0
        msg: *const ModbusMessage,
605
0
    ) -> u16 {
606
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
607
0
        let msg = msg.as_ref().unwrap();
608
        if let Data::Write(Write::MultReq {
609
0
            address,
610
            quantity: _,
611
            data: _,
612
0
        }) = &msg.data
613
        {
614
0
            *address
615
        } else {
616
0
            panic!("wrong modbus message data type");
617
        }
618
0
    }
619
620
    #[no_mangle]
621
0
    pub unsafe extern "C" fn rs_modbus_message_get_write_multreq_quantity(
622
0
        msg: *const ModbusMessage,
623
0
    ) -> u16 {
624
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
625
0
        let msg = msg.as_ref().unwrap();
626
        if let Data::Write(Write::MultReq {
627
            address: _,
628
0
            quantity,
629
            data: _,
630
0
        }) = &msg.data
631
        {
632
0
            *quantity
633
        } else {
634
0
            panic!("wrong modbus message data type");
635
        }
636
0
    }
637
638
    #[no_mangle]
639
0
    pub unsafe extern "C" fn rs_modbus_message_get_write_multreq_data(
640
0
        msg: *const ModbusMessage, data_len: *mut usize,
641
0
    ) -> *const u8 {
642
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
643
0
        let msg = msg.as_ref().unwrap();
644
        if let Data::Write(Write::MultReq {
645
            address: _,
646
            quantity: _,
647
0
            data,
648
0
        }) = &msg.data
649
        {
650
0
            *data_len = data.len();
651
0
            data.as_slice().as_ptr()
652
        } else {
653
0
            panic!("wrong modbus message data type");
654
        }
655
0
    }
656
657
    #[no_mangle]
658
0
    pub unsafe extern "C" fn rs_modbus_message_get_and_mask(msg: *const ModbusMessage) -> u16 {
659
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
660
0
        let msg = msg.as_ref().unwrap();
661
        if let Data::Write(Write::Mask {
662
            address: _,
663
0
            and_mask,
664
            or_mask: _,
665
0
        }) = &msg.data
666
        {
667
0
            *and_mask
668
        } else {
669
0
            panic!("wrong modbus message data type");
670
        }
671
0
    }
672
673
    #[no_mangle]
674
0
    pub unsafe extern "C" fn rs_modbus_message_get_or_mask(msg: *const ModbusMessage) -> u16 {
675
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
676
0
        let msg = msg.as_ref().unwrap();
677
        if let Data::Write(Write::Mask {
678
            address: _,
679
            and_mask: _,
680
0
            or_mask,
681
0
        }) = &msg.data
682
        {
683
0
            *or_mask
684
        } else {
685
0
            panic!("wrong modbus message data type");
686
        }
687
0
    }
688
689
    #[no_mangle]
690
0
    pub unsafe extern "C" fn rs_modbus_message_get_write_address(msg: *const ModbusMessage) -> u16 {
691
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
692
0
        let msg = msg.as_ref().unwrap();
693
0
        if let Data::Write(Write::Other { address, data: _ }) = &msg.data {
694
0
            *address
695
        } else {
696
0
            panic!("wrong modbus message data type");
697
        }
698
0
    }
699
700
    #[no_mangle]
701
0
    pub unsafe extern "C" fn rs_modbus_message_get_write_data(msg: *const ModbusMessage) -> u16 {
702
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
703
0
        let msg = msg.as_ref().unwrap();
704
0
        if let Data::Write(Write::Other { address: _, data }) = &msg.data {
705
0
            *data
706
        } else {
707
0
            panic!("wrong modbus message data type");
708
        }
709
0
    }
710
711
    #[no_mangle]
712
0
    pub unsafe extern "C" fn rs_modbus_message_get_bytevec_data(
713
0
        msg: *const ModbusMessage, data_len: *mut usize,
714
0
    ) -> *const u8 {
715
0
        let msg = msg.as_ref().unwrap().0 as *const Message;
716
0
        let msg = msg.as_ref().unwrap();
717
0
        if let Data::ByteVec(data) = &msg.data {
718
0
            *data_len = data.len();
719
0
            data.as_slice().as_ptr()
720
        } else {
721
0
            panic!("wrong modbus message data type");
722
        }
723
0
    }
724
725
    #[no_mangle]
726
0
    pub unsafe extern "C" fn rs_modbus_state_get_tx_request(
727
0
        state: *mut std::os::raw::c_void, tx_id: u64,
728
0
    ) -> ModbusMessage {
729
0
        let state = cast_pointer!(state, ModbusState);
730
0
        if let Some(tx) = state.get_tx(tx_id) {
731
0
            if let Some(request) = &tx.request {
732
0
                ModbusMessage((request as *const Message) as *const c_void)
733
            } else {
734
0
                ModbusMessage(std::ptr::null())
735
            }
736
        } else {
737
0
            ModbusMessage(std::ptr::null())
738
        }
739
0
    }
740
741
    #[no_mangle]
742
0
    pub unsafe extern "C" fn rs_modbus_state_get_tx_response(
743
0
        state: *mut std::os::raw::c_void, tx_id: u64,
744
0
    ) -> ModbusMessage {
745
0
        let state = cast_pointer!(state, ModbusState);
746
0
        if let Some(tx) = state.get_tx(tx_id) {
747
0
            if let Some(response) = &tx.response {
748
0
                ModbusMessage((response as *const Message) as *const c_void)
749
            } else {
750
0
                ModbusMessage(std::ptr::null())
751
            }
752
        } else {
753
0
            ModbusMessage(std::ptr::null())
754
        }
755
0
    }
756
}
757
758
#[cfg(test)]
759
mod tests {
760
    use super::*;
761
    use sawp_modbus::{
762
        Data, Diagnostic, DiagnosticSubfunction, Exception, ExceptionCode, FunctionCode, Read,
763
        Write,
764
    };
765
766
    const INVALID_FUNC_CODE: &[u8] = &[
767
        0x00, 0x00, // Transaction ID
768
        0x00, 0x00, // Protocol ID
769
        0x00, 0x02, // Length
770
        0x00, // Unit ID
771
        0x00, // Function code
772
    ];
773
774
    const RD_COILS_REQ: &[u8] = &[
775
        0x00, 0x00, // Transaction ID
776
        0x00, 0x00, // Protocol ID
777
        0x00, 0x06, // Length
778
        0x00, // Unit ID
779
        0x01, // Function code
780
        0x78, 0x90, // Starting Address
781
        0x00, 0x13, // Quantity of coils
782
    ];
783
784
    const RD_COILS_RESP: &[u8] = &[
785
        0x00, 0x00, // Transaction ID
786
        0x00, 0x00, // Protocol ID
787
        0x00, 0x06, // Length
788
        0x00, // Unit ID
789
        0x01, // Function code
790
        0x03, // Byte count
791
        0xCD, 0x6B, 0x05, // Coil Status
792
    ];
793
794
    const RD_COILS_ERR_RESP: &[u8] = &[
795
        0x00, 0x00, // Transaction ID
796
        0x00, 0x00, // Protocol ID
797
        0x00, 0x03, // Length
798
        0x00, // Unit ID
799
        0x81, // Function code
800
        0xFF, // Exception code
801
    ];
802
803
    const WR_SINGLE_REG_REQ: &[u8] = &[
804
        0x00, 0x0A, // Transaction ID
805
        0x00, 0x00, // Protocol ID
806
        0x00, 0x06, // Length
807
        0x00, // Unit ID
808
        0x06, // Function code
809
        0x00, 0x01, // Register Address
810
        0x00, 0x03, // Register Value
811
    ];
812
813
    const INVALID_WR_SINGLE_REG_REQ: &[u8] = &[
814
        0x00, 0x0A, // Transaction ID
815
        0x00, 0x00, // Protocol ID
816
        0x00, 0x04, // Length
817
        0x00, // Unit ID
818
        0x06, // Function code
819
        0x00, 0x01, // Register Address
820
    ];
821
822
    const WR_SINGLE_REG_RESP: &[u8] = &[
823
        0x00, 0x0A, // Transaction ID
824
        0x00, 0x00, // Protocol ID
825
        0x00, 0x06, // Length
826
        0x00, // Unit ID
827
        0x06, // Function code
828
        0x00, 0x01, // Register Address
829
        0x00, 0x03, // Register Value
830
    ];
831
832
    const WR_MULT_REG_REQ: &[u8] = &[
833
        0x00, 0x0A, // Transaction ID
834
        0x00, 0x00, // Protocol ID
835
        0x00, 0x0B, // Length
836
        0x00, // Unit ID
837
        0x10, // Function code
838
        0x00, 0x01, // Starting Address
839
        0x00, 0x02, // Quantity of Registers
840
        0x04, // Byte count
841
        0x00, 0x0A, // Registers Value
842
        0x01, 0x02,
843
    ];
844
845
    const INVALID_PDU_WR_MULT_REG_REQ: &[u8] = &[
846
        0x00, 0x0A, // Transaction ID
847
        0x00, 0x00, // Protocol ID
848
        0x00, 0x02, // Length
849
        0x00, // Unit ID
850
        0x10, // Function code
851
    ];
852
853
    const WR_MULT_REG_RESP: &[u8] = &[
854
        0x00, 0x0A, // Transaction ID
855
        0x00, 0x00, // Protocol ID
856
        0x00, 0x06, // Length
857
        0x00, // Unit ID
858
        0x10, // Function code
859
        0x00, 0x01, // Starting Address
860
        0x00, 0x02, // Quantity of Registers
861
    ];
862
863
    const MASK_WR_REG_REQ: &[u8] = &[
864
        0x00, 0x0A, // Transaction ID
865
        0x00, 0x00, // Protocol ID
866
        0x00, 0x08, // Length
867
        0x00, // Unit ID
868
        0x16, // Function code
869
        0x00, 0x04, // Reference Address
870
        0x00, 0xF2, // And_Mask
871
        0x00, 0x25, // Or_Mask
872
    ];
873
874
    const INVALID_MASK_WR_REG_REQ: &[u8] = &[
875
        0x00, 0x0A, // Transaction ID
876
        0x00, 0x00, // Protocol ID
877
        0x00, 0x06, // Length
878
        0x00, // Unit ID
879
        0x16, // Function code
880
        0x00, 0x04, // Reference Address
881
        0x00, 0xF2, // And_Mask
882
    ];
883
884
    const MASK_WR_REG_RESP: &[u8] = &[
885
        0x00, 0x0A, // Transaction ID
886
        0x00, 0x00, // Protocol ID
887
        0x00, 0x08, // Length
888
        0x00, // Unit ID
889
        0x16, // Function code
890
        0x00, 0x04, // Reference Address
891
        0x00, 0xF2, // And_Mask
892
        0x00, 0x25, // Or_Mask
893
    ];
894
895
    const RD_WR_MULT_REG_REQ: &[u8] = &[
896
        0x12, 0x34, // Transaction ID
897
        0x00, 0x00, // Protocol ID
898
        0x00, 0x11, // Length
899
        0x00, // Unit ID
900
        0x17, // Function code
901
        0x00, 0x03, // Read Starting Address
902
        0x00, 0x06, // Quantity to Read
903
        0x00, 0x0E, // Write Starting Address
904
        0x00, 0x03, // Quantity to Write
905
        0x06, // Write Byte count
906
        0x12, 0x34, // Write Registers Value
907
        0x56, 0x78, 0x9A, 0xBC,
908
    ];
909
910
    // Mismatch value in Byte count 0x0B instead of 0x0C
911
    const RD_WR_MULT_REG_RESP: &[u8] = &[
912
        0x12, 0x34, // Transaction ID
913
        0x00, 0x00, // Protocol ID
914
        0x00, 0x0E, // Length
915
        0x00, // Unit ID
916
        0x17, // Function code
917
        0x0B, // Byte count
918
        0x00, 0xFE, // Read Registers Value
919
        0x0A, 0xCD, 0x00, 0x01, 0x00, 0x03, 0x00, 0x0D, 0x00,
920
    ];
921
922
    const FORCE_LISTEN_ONLY_MODE: &[u8] = &[
923
        0x0A, 0x00, // Transaction ID
924
        0x00, 0x00, // Protocol ID
925
        0x00, 0x06, // Length
926
        0x00, // Unit ID
927
        0x08, // Function code
928
        0x00, 0x04, // Sub-function code
929
        0x00, 0x00, // Data
930
    ];
931
932
    const INVALID_PROTO_REQ: &[u8] = &[
933
        0x00, 0x00, // Transaction ID
934
        0x00, 0x01, // Protocol ID
935
        0x00, 0x06, // Length
936
        0x00, // Unit ID
937
        0x01, // Function code
938
        0x78, 0x90, // Starting Address
939
        0x00, 0x13, // Quantity of coils
940
    ];
941
942
    const INVALID_LEN_WR_MULT_REG_REQ: &[u8] = &[
943
        0x00, 0x0A, // Transaction ID
944
        0x00, 0x00, // Protocol ID
945
        0x00, 0x09, // Length
946
        0x00, // Unit ID
947
        0x10, // Function code
948
        0x00, 0x01, // Starting Address
949
        0x00, 0x02, // Quantity of Registers
950
        0x04, // Byte count
951
        0x00, 0x0A, // Registers Value
952
        0x01, 0x02,
953
    ];
954
955
    const EXCEEDED_LEN_WR_MULT_REG_REQ: &[u8] = &[
956
        0x00, 0x0A, // Transaction ID
957
        0x00, 0x00, // Protocol ID
958
        0xff, 0xfa, // Length
959
        0x00, // Unit ID
960
        0x10, // Function code
961
        0x00, 0x01, // Starting Address
962
        0x7f, 0xf9, // Quantity of Registers
963
        0xff, // Byte count
964
    ];
965
966
    #[test]
967
    fn read_coils() {
968
        let mut state = ModbusState::new();
969
        assert_eq!(
970
            AppLayerResult::ok(),
971
            state.parse(RD_COILS_REQ, Direction::ToServer)
972
        );
973
        assert_eq!(state.transactions.len(), 1);
974
975
        let tx = &state.transactions[0];
976
        let msg = tx.request.as_ref().unwrap();
977
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
978
        assert_eq!(
979
            msg.data,
980
            Data::Read(Read::Request {
981
                address: 0x7890,
982
                quantity: 0x0013
983
            })
984
        );
985
986
        assert_eq!(
987
            AppLayerResult::ok(),
988
            state.parse(RD_COILS_RESP, Direction::ToClient)
989
        );
990
        assert_eq!(state.transactions.len(), 1);
991
992
        let tx = &state.transactions[0];
993
        let msg = tx.response.as_ref().unwrap();
994
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
995
        assert_eq!(msg.data, Data::Read(Read::Response(vec![0xCD, 0x6B, 0x05])));
996
    }
997
998
    #[test]
999
    fn write_multiple_registers() {
1000
        let mut state = ModbusState::new();
1001
        assert_eq!(
1002
            AppLayerResult::ok(),
1003
            state.parse(WR_MULT_REG_REQ, Direction::ToServer)
1004
        );
1005
        assert_eq!(state.transactions.len(), 1);
1006
1007
        let tx = &state.transactions[0];
1008
        let msg = tx.request.as_ref().unwrap();
1009
        assert_eq!(msg.function.code, FunctionCode::WrMultRegs);
1010
        assert_eq!(
1011
            msg.data,
1012
            Data::Write(Write::MultReq {
1013
                address: 0x0001,
1014
                quantity: 0x0002,
1015
                data: vec![0x00, 0x0a, 0x01, 0x02],
1016
            })
1017
        );
1018
1019
        assert_eq!(
1020
            AppLayerResult::ok(),
1021
            state.parse(WR_MULT_REG_RESP, Direction::ToClient)
1022
        );
1023
        assert_eq!(state.transactions.len(), 1);
1024
1025
        let tx = &state.transactions[0];
1026
        let msg = tx.response.as_ref().unwrap();
1027
        assert_eq!(msg.function.code, FunctionCode::WrMultRegs);
1028
        assert_eq!(
1029
            msg.data,
1030
            Data::Write(Write::Other {
1031
                address: 0x0001,
1032
                data: 0x0002
1033
            })
1034
        );
1035
    }
1036
1037
    #[test]
1038
    fn read_write_multiple_registers() {
1039
        let mut state = ModbusState::new();
1040
        assert_eq!(
1041
            AppLayerResult::ok(),
1042
            state.parse(RD_WR_MULT_REG_REQ, Direction::ToServer)
1043
        );
1044
        assert_eq!(state.transactions.len(), 1);
1045
1046
        let tx = &state.transactions[0];
1047
        let msg = tx.request.as_ref().unwrap();
1048
        assert_eq!(msg.function.code, FunctionCode::RdWrMultRegs);
1049
        assert_eq!(
1050
            msg.data,
1051
            Data::ReadWrite {
1052
                read: Read::Request {
1053
                    address: 0x0003,
1054
                    quantity: 0x0006,
1055
                },
1056
                write: Write::MultReq {
1057
                    address: 0x000e,
1058
                    quantity: 0x0003,
1059
                    data: vec![0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]
1060
                }
1061
            }
1062
        );
1063
1064
        assert_eq!(
1065
            AppLayerResult::ok(),
1066
            state.parse(RD_WR_MULT_REG_RESP, Direction::ToClient)
1067
        );
1068
        assert_eq!(state.transactions.len(), 1);
1069
1070
        let tx = &state.transactions[0];
1071
        let msg = tx.response.as_ref().unwrap();
1072
        assert_eq!(msg.function.code, FunctionCode::RdWrMultRegs);
1073
        assert_eq!(
1074
            msg.data,
1075
            Data::Read(Read::Response(vec![
1076
                0x00, 0xFE, 0x0A, 0xCD, 0x00, 0x01, 0x00, 0x03, 0x00, 0x0D, 0x00,
1077
            ]))
1078
        );
1079
    }
1080
1081
    #[test]
1082
    fn force_listen_only_mode() {
1083
        let mut state = ModbusState::new();
1084
        assert_eq!(
1085
            AppLayerResult::ok(),
1086
            state.parse(FORCE_LISTEN_ONLY_MODE, Direction::ToServer)
1087
        );
1088
        assert_eq!(state.transactions.len(), 1);
1089
1090
        let tx = &state.transactions[0];
1091
        let msg = tx.request.as_ref().unwrap();
1092
        assert_eq!(msg.function.code, FunctionCode::Diagnostic);
1093
        assert_eq!(
1094
            msg.data,
1095
            Data::Diagnostic {
1096
                func: Diagnostic {
1097
                    raw: 4,
1098
                    code: DiagnosticSubfunction::ForceListenOnlyMode
1099
                },
1100
                data: vec![0x00, 0x00]
1101
            }
1102
        );
1103
    }
1104
1105
    #[test]
1106
    fn invalid_protocol_version() {
1107
        let mut state = ModbusState::new();
1108
        assert_eq!(
1109
            AppLayerResult::ok(),
1110
            state.parse(INVALID_PROTO_REQ, Direction::ToServer)
1111
        );
1112
1113
        assert_eq!(state.transactions.len(), 1);
1114
        let tx = &state.transactions[0];
1115
        let msg = tx.request.as_ref().unwrap();
1116
        assert_eq!(msg.error_flags, ErrorFlags::PROTO_ID);
1117
    }
1118
1119
    #[test]
1120
    fn unsolicited_response() {
1121
        let mut state = ModbusState::new();
1122
        assert_eq!(
1123
            AppLayerResult::ok(),
1124
            state.parse(RD_COILS_RESP, Direction::ToClient)
1125
        );
1126
        assert_eq!(state.transactions.len(), 1);
1127
1128
        let tx = &state.transactions[0];
1129
        let msg = tx.response.as_ref().unwrap();
1130
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
1131
        assert_eq!(msg.data, Data::Read(Read::Response(vec![0xCD, 0x6B, 0x05])));
1132
    }
1133
1134
    #[test]
1135
    fn invalid_length_request() {
1136
        let mut state = ModbusState::new();
1137
        assert_eq!(
1138
            AppLayerResult::incomplete(15, 4),
1139
            state.parse(INVALID_LEN_WR_MULT_REG_REQ, Direction::ToServer)
1140
        );
1141
        assert_eq!(state.transactions.len(), 1);
1142
1143
        let tx = &state.transactions[0];
1144
        let msg = tx.request.as_ref().unwrap();
1145
        assert_eq!(msg.function.code, FunctionCode::WrMultRegs);
1146
        assert_eq!(
1147
            msg.data,
1148
            Data::Write(Write::MultReq {
1149
                address: 0x0001,
1150
                quantity: 0x0002,
1151
                data: vec![0x00, 0x0a]
1152
            })
1153
        );
1154
        assert_eq!(msg.error_flags, ErrorFlags::DATA_LENGTH);
1155
    }
1156
1157
    #[test]
1158
    fn exception_code_invalid() {
1159
        let mut state = ModbusState::new();
1160
        assert_eq!(
1161
            AppLayerResult::ok(),
1162
            state.parse(RD_COILS_REQ, Direction::ToServer)
1163
        );
1164
        assert_eq!(state.transactions.len(), 1);
1165
1166
        let tx = &state.transactions[0];
1167
        let msg = tx.request.as_ref().unwrap();
1168
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
1169
        assert_eq!(
1170
            msg.data,
1171
            Data::Read(Read::Request {
1172
                address: 0x7890,
1173
                quantity: 0x0013
1174
            })
1175
        );
1176
1177
        assert_eq!(
1178
            AppLayerResult::ok(),
1179
            state.parse(RD_COILS_ERR_RESP, Direction::ToClient)
1180
        );
1181
        assert_eq!(state.transactions.len(), 1);
1182
1183
        let tx = &state.transactions[0];
1184
        let msg = tx.response.as_ref().unwrap();
1185
        assert_eq!(
1186
            msg.data,
1187
            Data::Exception(Exception {
1188
                raw: 255,
1189
                code: ExceptionCode::Unknown
1190
            })
1191
        );
1192
        assert_eq!(msg.error_flags, ErrorFlags::EXC_CODE);
1193
    }
1194
1195
    #[test]
1196
    fn fragmentation_1_adu_in_2_tcp_packets() {
1197
        let mut state = ModbusState::new();
1198
        assert_eq!(
1199
            AppLayerResult::incomplete(0, 12),
1200
            state.parse(
1201
                &RD_COILS_REQ[0..(RD_COILS_REQ.len() - 3)],
1202
                Direction::ToServer
1203
            )
1204
        );
1205
        assert_eq!(state.transactions.len(), 0);
1206
        assert_eq!(
1207
            AppLayerResult::ok(),
1208
            state.parse(RD_COILS_REQ, Direction::ToServer)
1209
        );
1210
        assert_eq!(state.transactions.len(), 1);
1211
1212
        let tx = &state.transactions[0];
1213
        assert!(&tx.request.is_some());
1214
        let msg = tx.request.as_ref().unwrap();
1215
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
1216
        assert_eq!(
1217
            msg.data,
1218
            Data::Read(Read::Request {
1219
                address: 0x7890,
1220
                quantity: 0x0013
1221
            })
1222
        );
1223
    }
1224
1225
    #[test]
1226
    fn fragmentation_2_adu_in_1_tcp_packet() {
1227
        let req = [RD_COILS_REQ, WR_MULT_REG_REQ].concat();
1228
        let resp = [RD_COILS_RESP, WR_MULT_REG_RESP].concat();
1229
1230
        let mut state = ModbusState::new();
1231
        assert_eq!(AppLayerResult::ok(), state.parse(&req, Direction::ToServer));
1232
        assert_eq!(state.transactions.len(), 2);
1233
1234
        let tx = &state.transactions[0];
1235
        let msg = tx.request.as_ref().unwrap();
1236
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
1237
        assert_eq!(
1238
            msg.data,
1239
            Data::Read(Read::Request {
1240
                address: 0x7890,
1241
                quantity: 0x0013
1242
            })
1243
        );
1244
1245
        let tx = &state.transactions[1];
1246
        let msg = tx.request.as_ref().unwrap();
1247
        assert_eq!(msg.function.code, FunctionCode::WrMultRegs);
1248
        assert_eq!(
1249
            msg.data,
1250
            Data::Write(Write::MultReq {
1251
                address: 0x0001,
1252
                quantity: 0x0002,
1253
                data: vec![0x00, 0x0a, 0x01, 0x02]
1254
            })
1255
        );
1256
1257
        assert_eq!(
1258
            AppLayerResult::ok(),
1259
            state.parse(&resp, Direction::ToClient)
1260
        );
1261
        assert_eq!(state.transactions.len(), 2);
1262
1263
        let tx = &state.transactions[0];
1264
        let msg = tx.response.as_ref().unwrap();
1265
        assert_eq!(msg.function.code, FunctionCode::RdCoils);
1266
        assert_eq!(msg.data, Data::Read(Read::Response(vec![0xCD, 0x6B, 0x05])));
1267
1268
        let tx = &state.transactions[1];
1269
        let msg = tx.response.as_ref().unwrap();
1270
        assert_eq!(msg.function.code, FunctionCode::WrMultRegs);
1271
        assert_eq!(
1272
            msg.data,
1273
            Data::Write(Write::Other {
1274
                address: 0x0001,
1275
                data: 0x0002
1276
            })
1277
        );
1278
    }
1279
1280
    #[test]
1281
    fn exceeded_length_request() {
1282
        let mut state = ModbusState::new();
1283
        assert_eq!(
1284
            AppLayerResult::ok(),
1285
            state.parse(EXCEEDED_LEN_WR_MULT_REG_REQ, Direction::ToServer)
1286
        );
1287
1288
        assert_eq!(state.transactions.len(), 1);
1289
        let tx = &state.transactions[0];
1290
        let msg = tx.request.as_ref().unwrap();
1291
        assert_eq!(msg.error_flags, ErrorFlags::DATA_LENGTH);
1292
    }
1293
1294
    #[test]
1295
    fn invalid_pdu_len_req() {
1296
        let mut state = ModbusState::new();
1297
        assert_eq!(
1298
            AppLayerResult::ok(),
1299
            state.parse(INVALID_PDU_WR_MULT_REG_REQ, Direction::ToServer)
1300
        );
1301
1302
        assert_eq!(state.transactions.len(), 1);
1303
1304
        let tx = &state.transactions[0];
1305
        let msg = tx.request.as_ref().unwrap();
1306
        assert_eq!(msg.function.code, FunctionCode::WrMultRegs);
1307
        assert_eq!(msg.data, Data::ByteVec(vec![]));
1308
    }
1309
1310
    #[test]
1311
    fn mask_write_register_request() {
1312
        let mut state = ModbusState::new();
1313
        assert_eq!(
1314
            AppLayerResult::ok(),
1315
            state.parse(MASK_WR_REG_REQ, Direction::ToServer)
1316
        );
1317
        assert_eq!(state.transactions.len(), 1);
1318
1319
        let tx = &state.transactions[0];
1320
        let msg = tx.request.as_ref().unwrap();
1321
        assert_eq!(msg.function.code, FunctionCode::MaskWrReg);
1322
        assert_eq!(
1323
            msg.data,
1324
            Data::Write(Write::Mask {
1325
                address: 0x0004,
1326
                and_mask: 0x00f2,
1327
                or_mask: 0x0025
1328
            })
1329
        );
1330
1331
        assert_eq!(
1332
            AppLayerResult::ok(),
1333
            state.parse(MASK_WR_REG_RESP, Direction::ToClient)
1334
        );
1335
        assert_eq!(state.transactions.len(), 1);
1336
1337
        let tx = &state.transactions[0];
1338
        let msg = tx.response.as_ref().unwrap();
1339
        assert_eq!(msg.function.code, FunctionCode::MaskWrReg);
1340
        assert_eq!(
1341
            msg.data,
1342
            Data::Write(Write::Mask {
1343
                address: 0x0004,
1344
                and_mask: 0x00f2,
1345
                or_mask: 0x0025
1346
            })
1347
        );
1348
    }
1349
1350
    #[test]
1351
    fn write_single_register_request() {
1352
        let mut state = ModbusState::new();
1353
        assert_eq!(
1354
            AppLayerResult::ok(),
1355
            state.parse(WR_SINGLE_REG_REQ, Direction::ToServer)
1356
        );
1357
        assert_eq!(state.transactions.len(), 1);
1358
1359
        let tx = &state.transactions[0];
1360
        let msg = tx.request.as_ref().unwrap();
1361
        assert_eq!(msg.function.code, FunctionCode::WrSingleReg);
1362
        assert_eq!(
1363
            msg.data,
1364
            Data::Write(Write::Other {
1365
                address: 0x0001,
1366
                data: 0x0003
1367
            })
1368
        );
1369
1370
        assert_eq!(
1371
            AppLayerResult::ok(),
1372
            state.parse(WR_SINGLE_REG_RESP, Direction::ToClient)
1373
        );
1374
        assert_eq!(state.transactions.len(), 1);
1375
1376
        let tx = &state.transactions[0];
1377
        let msg = tx.response.as_ref().unwrap();
1378
        assert_eq!(msg.function.code, FunctionCode::WrSingleReg);
1379
        assert_eq!(
1380
            msg.data,
1381
            Data::Write(Write::Other {
1382
                address: 0x0001,
1383
                data: 0x0003
1384
            })
1385
        );
1386
    }
1387
1388
    #[test]
1389
    fn invalid_mask_write_register_request() {
1390
        let mut state = ModbusState::new();
1391
        assert_eq!(
1392
            AppLayerResult::ok(),
1393
            state.parse(INVALID_MASK_WR_REG_REQ, Direction::ToServer)
1394
        );
1395
        assert_eq!(state.transactions.len(), 1);
1396
1397
        let tx = &state.transactions[0];
1398
        let msg = tx.request.as_ref().unwrap();
1399
        assert_eq!(msg.function.code, FunctionCode::MaskWrReg);
1400
        assert_eq!(msg.error_flags, ErrorFlags::DATA_LENGTH);
1401
        assert_eq!(msg.data, Data::ByteVec(vec![0x00, 0x04, 0x00, 0xF2]));
1402
1403
        assert_eq!(
1404
            AppLayerResult::ok(),
1405
            state.parse(MASK_WR_REG_RESP, Direction::ToClient)
1406
        );
1407
        assert_eq!(state.transactions.len(), 1);
1408
1409
        let tx = &state.transactions[0];
1410
        let msg = tx.response.as_ref().unwrap();
1411
        assert_eq!(msg.function.code, FunctionCode::MaskWrReg);
1412
        assert_eq!(
1413
            msg.data,
1414
            Data::Write(Write::Mask {
1415
                address: 0x0004,
1416
                and_mask: 0x00f2,
1417
                or_mask: 0x0025
1418
            })
1419
        );
1420
    }
1421
1422
    #[test]
1423
    fn invalid_write_single_register_request() {
1424
        let mut state = ModbusState::new();
1425
        assert_eq!(
1426
            AppLayerResult::ok(),
1427
            state.parse(INVALID_WR_SINGLE_REG_REQ, Direction::ToServer)
1428
        );
1429
        assert_eq!(state.transactions.len(), 1);
1430
1431
        let tx = &state.transactions[0];
1432
        let msg = tx.request.as_ref().unwrap();
1433
        assert_eq!(msg.function.code, FunctionCode::WrSingleReg);
1434
        assert_eq!(msg.error_flags, ErrorFlags::DATA_LENGTH);
1435
        assert_eq!(msg.data, Data::ByteVec(vec![0x00, 0x01]));
1436
1437
        assert_eq!(
1438
            AppLayerResult::ok(),
1439
            state.parse(WR_SINGLE_REG_RESP, Direction::ToClient)
1440
        );
1441
        assert_eq!(state.transactions.len(), 1);
1442
1443
        let tx = &state.transactions[0];
1444
        let msg = tx.response.as_ref().unwrap();
1445
        assert_eq!(msg.function.code, FunctionCode::WrSingleReg);
1446
        assert_eq!(
1447
            msg.data,
1448
            Data::Write(Write::Other {
1449
                address: 0x0001,
1450
                data: 0x0003
1451
            })
1452
        );
1453
    }
1454
1455
    #[test]
1456
    fn invalid_function_code() {
1457
        let mut state = ModbusState::new();
1458
        assert_eq!(
1459
            AppLayerResult::ok(),
1460
            state.parse(INVALID_FUNC_CODE, Direction::ToServer)
1461
        );
1462
        assert_eq!(state.transactions.len(), 1);
1463
1464
        let tx = &state.transactions[0];
1465
        let msg = tx.request.as_ref().unwrap();
1466
        assert_eq!(msg.function.code, FunctionCode::Unknown);
1467
        assert_eq!(msg.data, Data::ByteVec(vec![]));
1468
    }
1469
}