]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
modbus: tx iterator
authorPhilippe Antoine <contact@catenacyber.fr>
Thu, 7 Oct 2021 12:31:29 +0000 (14:31 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 11 Oct 2021 06:35:40 +0000 (08:35 +0200)
When there are a lot of open transactions, as is possible with
modbus, the default tx_iterator will loop for the whole
transacations vector to find each transaction, that means
quadratic complexity.

Reusing the tx_iterator from the template, and keeping as a state
the last index where to start looking avoids this quadratic
complexity.

rust/src/modbus/modbus.rs

index fa62ae7228f08ae3ea7da9b83be0e6401ba95f0e..35147e563057bc77399627996a76e1345721a7b7 100644 (file)
@@ -14,7 +14,7 @@
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
-use crate::applayer::*;
+use crate::applayer::{self, *};
 use crate::core::{self, AppProto, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_TCP};
 
 use std::ffi::CString;
@@ -123,6 +123,27 @@ impl ModbusState {
         None
     }
 
+    fn tx_iterator(
+        &mut self,
+        min_tx_id: u64,
+        state: &mut u64,
+    ) -> Option<(&ModbusTransaction, u64, bool)> {
+        let mut index = *state as usize;
+        let len = self.transactions.len();
+
+        while index < len {
+            let tx = &self.transactions[index];
+            if tx.id < min_tx_id + 1 {
+                index += 1;
+                continue;
+            }
+            *state = index as u64;
+            return Some((tx, tx.id - 1, (len - index) > 1));
+        }
+
+        return None;
+    }
+
     /// Searches the requests in order to find one matching the given response. Returns the matching
     /// transaction, if it exists
     pub fn find_request_and_validate(
@@ -362,6 +383,32 @@ pub unsafe extern "C" fn rs_modbus_state_get_tx(
     }
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn rs_modbus_state_get_tx_iterator(
+    _ipproto: u8,
+    _alproto: AppProto,
+    state: *mut std::os::raw::c_void,
+    min_tx_id: u64,
+    _max_tx_id: u64,
+    istate: &mut u64,
+) -> applayer::AppLayerGetTxIterTuple {
+    let state = cast_pointer!(state, ModbusState);
+    match state.tx_iterator(min_tx_id, istate) {
+        Some((tx, out_tx_id, has_next)) => {
+            let c_tx = tx as *const _ as *mut _;
+            let ires = applayer::AppLayerGetTxIterTuple::with_values(
+                c_tx,
+                out_tx_id,
+                has_next,
+            );
+            return ires;
+        }
+        None => {
+            return applayer::AppLayerGetTxIterTuple::not_found();
+        }
+    }
+}
+
 #[no_mangle]
 pub unsafe extern "C" fn rs_modbus_tx_get_alstate_progress(
     tx: *mut std::os::raw::c_void, _direction: u8,
@@ -433,7 +480,7 @@ pub unsafe extern "C" fn rs_modbus_register_parser() {
         localstorage_new: None,
         localstorage_free: None,
         get_files: None,
-        get_tx_iterator: None,
+        get_tx_iterator: Some(rs_modbus_state_get_tx_iterator),
         get_de_state: rs_modbus_state_get_tx_detect_state,
         set_de_state: rs_modbus_state_set_tx_detect_state,
         get_tx_data: rs_modbus_state_get_tx_data,