value: Option<Range<u16>>,
}
-/// TODO: remove these after regression testing commit
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_category(modbus: *const DetectModbusRust) -> u8 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.category.map(|val| val.bits()).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_function(modbus: *const DetectModbusRust) -> u8 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.function.map(|val| val as u8).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_subfunction(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.subfunction.unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_has_subfunction(modbus: *const DetectModbusRust) -> bool {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.subfunction.is_some()
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_access_type(modbus: *const DetectModbusRust) -> u8 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.access_type.map(|val| val.bits()).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_unit_id_min(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.unit_id.as_ref().map(|val| val.start).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_unit_id_max(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.unit_id.as_ref().map(|val| val.end).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_address_min(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.address.as_ref().map(|val| val.start).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_address_max(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.address.as_ref().map(|val| val.end).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_data_min(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.value.as_ref().map(|val| val.start).unwrap_or(0)
-}
-
-#[no_mangle]
-pub extern "C" fn rs_modbus_get_data_max(modbus: *const DetectModbusRust) -> u16 {
- let modbus = unsafe { modbus.as_ref() }.unwrap();
- modbus.value.as_ref().map(|val| val.end).unwrap_or(0)
-}
-
impl Default for DetectModbusRust {
fn default() -> Self {
DetectModbusRust {
Ok(modbus)
}
+
+#[cfg(test)]
+mod test {
+ use super::super::modbus::ModbusState;
+ use super::*;
+ use crate::applayer::*;
+ use sawp::parser::Direction;
+
+ #[test]
+ fn test_parse() {
+ assert_eq!(
+ parse_function("function 1"),
+ Ok(DetectModbusRust {
+ function: Some(FunctionCode::RdCoils),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_function("function 8, subfunction 4"),
+ Ok(DetectModbusRust {
+ function: Some(FunctionCode::Diagnostic),
+ subfunction: Some(4),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_function("function reserved"),
+ Ok(DetectModbusRust {
+ category: Some(Flags::from(CodeCategory::RESERVED)),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_function("function !assigned"),
+ Ok(DetectModbusRust {
+ category: Some(!CodeCategory::PUBLIC_ASSIGNED),
+ ..Default::default()
+ })
+ );
+
+ assert_eq!(
+ parse_access("access read"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_access("access read discretes"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::DISCRETES)),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_access("access read, address 1000"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ address: Some(1000..1000),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_access("access write coils, address <500"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::COILS)),
+ address: Some(std::u16::MIN..500),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_access("access write coils, address >500"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::COILS)),
+ address: Some(500..std::u16::MAX),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_access("access write holding, address 100, value <1000"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(100..100),
+ value: Some(std::u16::MIN..1000),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_access("access write holding, address 100, value 500<>1000"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(100..100),
+ value: Some(500..1000),
+ ..Default::default()
+ })
+ );
+
+ assert_eq!(
+ parse_unit_id("unit 10"),
+ Ok(DetectModbusRust {
+ unit_id: Some(10..10),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_unit_id("unit 10, function 8, subfunction 4"),
+ Ok(DetectModbusRust {
+ function: Some(FunctionCode::Diagnostic),
+ subfunction: Some(4),
+ unit_id: Some(10..10),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_unit_id("unit 10, access read, address 1000"),
+ Ok(DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ unit_id: Some(10..10),
+ address: Some(1000..1000),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_unit_id("unit <11"),
+ Ok(DetectModbusRust {
+ unit_id: Some(std::u16::MIN..11),
+ ..Default::default()
+ })
+ );
+ assert_eq!(
+ parse_unit_id("unit 10<>500"),
+ Ok(DetectModbusRust {
+ unit_id: Some(10..500),
+ ..Default::default()
+ })
+ );
+
+ assert_eq!(parse_access("access write holdin"), Err(()));
+ assert_eq!(parse_access("unt 10"), Err(()));
+ assert_eq!(
+ parse_access("access write holding, address 100, value 500<>"),
+ Err(())
+ );
+ }
+
+ #[test]
+ fn test_match() {
+ let mut modbus = ModbusState::new();
+
+ // Read/Write Multiple Registers Request
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x12, 0x34, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x11, // Length
+ 0x0a, // Unit ID
+ 0x17, // Function code
+ 0x00, 0x03, // Read Starting Address
+ 0x00, 0x06, // Quantity to Read
+ 0x00, 0x0E, // Write Starting Address
+ 0x00, 0x03, // Quantity to Write
+ 0x06, // Write Byte count
+ 0x12, 0x34, // Write Registers Value
+ 0x56, 0x78, 0x9A, 0xBC
+ ],
+ Direction::ToServer
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 1);
+ // function 23
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ function: Some(FunctionCode::RdWrMultRegs),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 15, value <4660
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(15..15),
+ value: Some(std::u16::MIN..4660),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 15, value 4661
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(15..15),
+ value: Some(4661..4661),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 16, value 20000<>22136
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(16..16),
+ value: Some(20000..22136),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 16, value 22136<>30000
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(16..16),
+ value: Some(22136..30000),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 15, value >4660
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(15..15),
+ value: Some(4660..std::u16::MAX),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 16, value <22137
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(16..16),
+ value: Some(std::u16::MIN..22137),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 16, value <22137
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(16..16),
+ value: Some(std::u16::MIN..22137),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 17, value 39612
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(17..17),
+ value: Some(39612..39612),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 17, value 30000<>39613
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(17..17),
+ value: Some(30000..39613),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 15, value 4659<>5000
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(15..15),
+ value: Some(4659..5000),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write holding, address 17, value >39611
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE | AccessType::HOLDING)),
+ address: Some(17..17),
+ value: Some(39611..std::u16::MAX),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 12
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(12..12),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 5<>9
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(5..9),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 11<>15
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(11..15),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit >11
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(11..std::u16::MAX),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit <9
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(std::u16::MIN..9),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 5<>15
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(5..15),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit >9
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(9..std::u16::MAX),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit <11
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ unit_id: Some(std::u16::MIN..11),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, function 20
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ function: Some(FunctionCode::RdFileRec),
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 11, function 20
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ function: Some(FunctionCode::RdFileRec),
+ unit_id: Some(11..11),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 11, function 23
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ function: Some(FunctionCode::RdWrMultRegs),
+ unit_id: Some(11..11),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 11, function public
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ category: Some(Flags::from(
+ CodeCategory::PUBLIC_ASSIGNED | CodeCategory::PUBLIC_UNASSIGNED
+ )),
+ unit_id: Some(11..11),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, function user
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ category: Some(Flags::from(CodeCategory::USER_DEFINED)),
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, function 23
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ function: Some(FunctionCode::RdWrMultRegs),
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, function public
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ category: Some(Flags::from(
+ CodeCategory::PUBLIC_ASSIGNED | CodeCategory::PUBLIC_UNASSIGNED
+ )),
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, function !user
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[0],
+ &DetectModbusRust {
+ category: Some(!CodeCategory::USER_DEFINED),
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Force Listen Only Mode
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x0A, 0x00, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x06, // Length
+ 0x00, // Unit ID
+ 0x08, // Function code
+ 0x00, 0x04, // Sub-function code
+ 0x00, 0x00 // Data
+ ],
+ Direction::ToServer
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 2);
+ // function 8, subfunction 4
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[1],
+ &DetectModbusRust {
+ function: Some(FunctionCode::Diagnostic),
+ subfunction: Some(4),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Encapsulated Interface Transport (MEI)
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x10, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x05, // Length
+ 0x00, // Unit ID
+ 0x2B, // Function code
+ 0x0F, // MEI Type
+ 0x00, 0x00 // Data
+ ],
+ Direction::ToServer
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 3);
+ // function reserved
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[2],
+ &DetectModbusRust {
+ category: Some(Flags::from(CodeCategory::RESERVED)),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Unassigned/Unknown function
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x0A, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x02, // Length
+ 0x00, // Unit ID
+ 0x12 // Function code
+ ],
+ Direction::ToServer
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 4);
+ // function !assigned
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[3],
+ &DetectModbusRust {
+ category: Some(!CodeCategory::PUBLIC_ASSIGNED),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Read Coils request
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x00, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x06, // Length
+ 0x0a, // Unit ID
+ 0x01, // Function code
+ 0x78, 0x90, // Starting Address
+ 0x00, 0x13 // Quantity of coils
+ ],
+ Direction::ToServer
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 5);
+ // access read
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read, address 30870
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ address: Some(30870..30870),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, access read, address 30863
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ unit_id: Some(10..10),
+ address: Some(30863..30863),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 11, access read, address 30870
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ unit_id: Some(11..11),
+ address: Some(30870..30870),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 11, access read, address 30863
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ unit_id: Some(11..11),
+ address: Some(30863..30863),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, access write
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE)),
+ unit_id: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // unit 10, access read, address 30870
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[4],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ unit_id: Some(10..10),
+ address: Some(30870..30870),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Read Inputs Register request
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x0A, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x06, // Length
+ 0x00, // Unit ID
+ 0x04, // Function code
+ 0x00, 0x08, // Starting Address
+ 0x00, 0x60 // Quantity of Registers
+ ],
+ Direction::ToServer
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 6);
+ // access read input
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address <9
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(std::u16::MIN..9),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address 5<>9
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(5..9),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address >104
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(104..std::u16::MAX),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address 104<>110
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(104..110),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address 9
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(9..9),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address <10
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(std::u16::MIN..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address 5<>10
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(5..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address >103
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(103..std::u16::MAX),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address 103<>110
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(103..110),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read input, address 104
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[5],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ | AccessType::INPUT)),
+ address: Some(104..104),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Origin: https://github.com/bro/bro/blob/master/testing/btest/Traces/modbus/modbus.trace
+ // Read Coils Response
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x01, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x04, // Length
+ 0x0a, // Unit ID
+ 0x01, // Function code
+ 0x01, // Count
+ 0x00, // Data
+ ],
+ Direction::ToClient
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 7);
+ // function 1
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[6],
+ &DetectModbusRust {
+ function: Some(FunctionCode::RdCoils),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read, address 104
+ // Fails because there was no request, and the address is not retrievable
+ // from the response.
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[6],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ address: Some(104..104),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Origin: https://github.com/bro/bro/blob/master/testing/btest/Traces/modbus/modbus.trace
+ // Write Single Register Response
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x01, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x06, // Length
+ 0x0a, // Unit ID
+ 0x06, // Function code
+ 0x00, 0x05, // Starting address
+ 0x00, 0x0b // Data
+ ],
+ Direction::ToClient
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 8);
+ // function 6
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[7],
+ &DetectModbusRust {
+ function: Some(FunctionCode::WrSingleReg),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access write, address 10
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[7],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::WRITE)),
+ address: Some(10..10),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+
+ // Origin: https://github.com/bro/bro/blob/master/testing/btest/Traces/modbus/modbus.trace
+ // Write Single Register Response
+ assert_eq!(
+ modbus.parse(
+ &[
+ 0x00, 0x00, // Transaction ID
+ 0x00, 0x00, // Protocol ID
+ 0x00, 0x06, // Length
+ 0x0a, // Unit ID
+ 0x08, // Function code
+ 0x00, 0x0a, // Diagnostic code
+ 0x00, 0x00 // Data
+ ],
+ Direction::ToClient
+ ),
+ AppLayerResult::ok()
+ );
+ assert_eq!(modbus.transactions.len(), 9);
+ // function 8
+ assert_eq!(
+ rs_modbus_inspect(
+ &modbus.transactions[8],
+ &DetectModbusRust {
+ function: Some(FunctionCode::Diagnostic),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ // access read
+ assert_ne!(
+ rs_modbus_inspect(
+ &modbus.transactions[8],
+ &DetectModbusRust {
+ access_type: Some(Flags::from(AccessType::READ)),
+ ..Default::default()
+ }
+ ),
+ 1
+ );
+ }
+}
detect-engine.h \
detect-engine-iponly.h \
detect-engine-loader.h \
- detect-engine-modbus.h \
detect-engine-mpm.h \
detect-engine-payload.h \
detect-engine-port.h \
detect-engine-file.c \
detect-engine-iponly.c \
detect-engine-loader.c \
- detect-engine-modbus.c \
detect-engine-mpm.c \
detect-engine-payload.c \
detect-engine-port.c \
#ifndef __APP_LAYER_MODBUS_H__
#define __APP_LAYER_MODBUS_H__
-/* Modbus Function Code Categories. */
-#define MODBUS_CAT_NONE 0x0
-#define MODBUS_CAT_PUBLIC_ASSIGNED (1<<0)
-#define MODBUS_CAT_PUBLIC_UNASSIGNED (1<<1)
-#define MODBUS_CAT_USER_DEFINED (1<<2)
-#define MODBUS_CAT_RESERVED (1<<3)
-#define MODBUS_CAT_ALL 0xFF
-
-/* Modbus Read/Write function and Access Types. */
-#define MODBUS_TYP_NONE 0x0
-#define MODBUS_TYP_ACCESS_MASK 0x03
-#define MODBUS_TYP_READ (1<<0)
-#define MODBUS_TYP_WRITE (1<<1)
-#define MODBUS_TYP_ACCESS_FUNCTION_MASK 0x3C
-#define MODBUS_TYP_BIT_ACCESS_MASK 0x0C
-#define MODBUS_TYP_DISCRETES (1<<2)
-#define MODBUS_TYP_COILS (1<<3)
-#define MODBUS_TYP_WORD_ACCESS_MASK 0x30
-#define MODBUS_TYP_INPUT (1<<4)
-#define MODBUS_TYP_HOLDING (1<<5)
-#define MODBUS_TYP_SINGLE (1<<6)
-#define MODBUS_TYP_MULTIPLE (1<<7)
-#define MODBUS_TYP_WRITE_SINGLE (MODBUS_TYP_WRITE | MODBUS_TYP_SINGLE)
-#define MODBUS_TYP_WRITE_MULTIPLE (MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE)
-#define MODBUS_TYP_READ_WRITE_MULTIPLE (MODBUS_TYP_READ | MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE)
-
void RegisterModbusParsers(void);
#endif /* __APP_LAYER_MODBUS_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2014 ANSSI
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** \file
- *
- * \author David DIALLO <diallo@et.esiea.fr>
- *
- * Based on detect-engine-dns.c
- */
-
-#include "suricata-common.h"
-
-#include "app-layer.h"
-
-#include "detect.h"
-#include "detect-modbus.h"
-
-#include "detect-engine-modbus.h"
-
-#include "flow.h"
-
-#include "util-debug.h"
-
-#ifdef UNITTESTS /* UNITTESTS */
-#include "app-layer-parser.h"
-
-#include "detect-parse.h"
-
-#include "detect-engine.h"
-
-#include "flow-util.h"
-
-#include "stream-tcp.h"
-
-#include "util-unittest.h"
-#include "util-unittest-helper.h"
-
-/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
-/* Example of a request to read discrete outputs 20-38 */
-static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
- /* Protocol ID */ 0x00, 0x00,
- /* Length */ 0x00, 0x06,
- /* Unit ID */ 0x0a,
- /* Function code */ 0x01,
- /* Starting Address */ 0x78, 0x90,
- /* Quantity of coils */ 0x00, 0x13 };
-
-/* Modbus Application Protocol Specification V1.1b3 6.4: Read Input Registers */
-/* Example of a request to read input register 9 */
-static uint8_t readInputsRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A,
- /* Protocol ID */ 0x00, 0x00,
- /* Length */ 0x00, 0x06,
- /* Unit ID */ 0x00,
- /* Function code */ 0x04,
- /* Starting Address */ 0x00, 0x08,
- /* Quantity of Registers */ 0x00, 0x60};
-
-/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */
-/* Example of a request to read six registers starting at register 4, */
-/* and to write three registers starting at register 15 */
-static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34,
- /* Protocol ID */ 0x00, 0x00,
- /* Length */ 0x00, 0x11,
- /* Unit ID */ 0x0a,
- /* Function code */ 0x17,
- /* Read Starting Address */ 0x00, 0x03,
- /* Quantity to Read */ 0x00, 0x06,
- /* Write Starting Address */ 0x00, 0x0E,
- /* Quantity to Write */ 0x00, 0x03,
- /* Write Byte count */ 0x06,
- /* Write Registers Value */ 0x12, 0x34, /* 15 */
- 0x56, 0x78, /* 16 */
- 0x9A, 0xBC};/* 17 */
-
-/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */
-/* Example of a request to to remote device to its Listen Only MOde for Modbus Communications. */
-static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00,
- /* Protocol ID */ 0x00, 0x00,
- /* Length */ 0x00, 0x06,
- /* Unit ID */ 0x00,
- /* Function code */ 0x08,
- /* Sub-function code */ 0x00, 0x04,
- /* Data */ 0x00, 0x00};
-
-/* Modbus Application Protocol Specification V1.1b3 Annex A */
-/* Modbus Reserved Function codes, Subcodes and MEI types */
-static uint8_t encapsulatedInterfaceTransport[] = {
- /* Transaction ID */ 0x00, 0x10,
- /* Protocol ID */ 0x00, 0x00,
- /* Length */ 0x00, 0x05,
- /* Unit ID */ 0x00,
- /* Function code */ 0x2B,
- /* MEI Type */ 0x0F,
- /* Data */ 0x00, 0x00};
-
-static uint8_t unassigned[] = {
- /* Transaction ID */ 0x00, 0x0A,
- /* Protocol ID */ 0x00, 0x00,
- /* Length */ 0x00, 0x02,
- /* Unit ID */ 0x00,
- /* Function code */ 0x3F
-};
-
-/** \test Test code function. */
-static int DetectEngineInspectModbusTest01(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code function\"; "
- "modbus: function 23; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER,
- readWriteMultipleRegistersReq,
- sizeof(readWriteMultipleRegistersReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test code function and code subfunction. */
-static int DetectEngineInspectModbusTest02(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus function and subfunction\"; "
- "modbus: function 8, subfunction 4; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, forceListenOnlyMode,
- sizeof(forceListenOnlyMode));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test function category. */
-static int DetectEngineInspectModbusTest03(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus category function\"; "
- "modbus: function reserved; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER,
- encapsulatedInterfaceTransport,
- sizeof(encapsulatedInterfaceTransport));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test negative function category. */
-static int DetectEngineInspectModbusTest04(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus category function\"; "
- "modbus: function !assigned; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, unassigned,
- sizeof(unassigned));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test access type. */
-static int DetectEngineInspectModbusTest05(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access type\"; "
- "modbus: access read; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, readCoilsReq,
- sizeof(readCoilsReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test access function. */
-static int DetectEngineInspectModbusTest06(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access type\"; "
- "modbus: access read input; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, readInputsRegistersReq,
- sizeof(readInputsRegistersReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test read access at an address. */
-static int DetectEngineInspectModbusTest07(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus address access\"; "
- "modbus: access read, address 30870; sid:1;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, readCoilsReq,
- sizeof(readCoilsReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test read access at a range of address. */
-static int DetectEngineInspectModbusTest08(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- /* readInputsRegistersReq, Starting Address = 0x08, Quantity of Registers = 0x60 */
- /* Read access address from 9 to 104 */
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address <9; sid:1;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address 9; sid:2;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address 5<>9; sid:3;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address <10; sid:4;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address 5<>10; sid:5;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address >103; sid:6;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address 103<>110; sid:7;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address 104; sid:8;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address >104; sid:9;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus access\"; "
- "modbus: access read input, "
- "address 104<>110; sid:10;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, readInputsRegistersReq,
- sizeof(readInputsRegistersReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF(PacketAlertCheck(p, 1));
- FAIL_IF(PacketAlertCheck(p, 3));
- FAIL_IF(PacketAlertCheck(p, 9));
- FAIL_IF(PacketAlertCheck(p, 10));
-
- FAIL_IF_NOT(PacketAlertCheck(p, 2));
- FAIL_IF_NOT(PacketAlertCheck(p, 4));
- FAIL_IF_NOT(PacketAlertCheck(p, 5));
- FAIL_IF_NOT(PacketAlertCheck(p, 6));
- FAIL_IF_NOT(PacketAlertCheck(p, 7));
- FAIL_IF_NOT(PacketAlertCheck(p, 8));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test write access at a address in a range of value. */
-static int DetectEngineInspectModbusTest09(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
- /* Write access register address 15 = 0x1234 (4660) */
- /* Write access register address 16 = 0x5678 (22136) */
- /* Write access register address 17 = 0x9ABC (39612) */
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 15, value <4660; sid:1;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 16, value <22137; sid:2;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 17, value 39612; sid:3;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 15, value 4661; sid:4;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 16, value 20000<>22136; sid:5;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 17, value 30000<>39613; sid:6;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 15, value 4659<>5000; sid:7;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 16, value 22136<>30000; sid:8;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 17, value >39611; sid:9;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus write access\"; "
- "modbus: access write holding, "
- "address 15, value >4660; sid:10;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER,
- readWriteMultipleRegistersReq,
- sizeof(readWriteMultipleRegistersReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF(PacketAlertCheck(p, 1));
- FAIL_IF(PacketAlertCheck(p, 4));
- FAIL_IF(PacketAlertCheck(p, 5));
- FAIL_IF(PacketAlertCheck(p, 8));
- FAIL_IF(PacketAlertCheck(p, 10));
-
- FAIL_IF_NOT(PacketAlertCheck(p, 2));
- FAIL_IF_NOT(PacketAlertCheck(p, 3));
- FAIL_IF_NOT(PacketAlertCheck(p, 6));
- FAIL_IF_NOT(PacketAlertCheck(p, 7));
- FAIL_IF_NOT(PacketAlertCheck(p, 9));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test Test code unit_id. */
-static int DetectEngineInspectModbusTest10(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readWriteMultipleRegistersReq,
- sizeof(readWriteMultipleRegistersReq),
- IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
- /* Unit ID = 0x0a (10) */
- /* Function code = 0x17 (23) */
- /* Write access register address 15 = 0x1234 (4660) */
- /* Write access register address 16 = 0x5678 (22136) */
- /* Write access register address 17 = 0x9ABC (39612) */
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 10; sid:1;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 12; sid:2;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 5<>15; sid:3;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 5<>9; sid:4;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 11<>15; sid:5;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit >9; sid:6;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit >11; sid:7;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit <11; sid:8;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit <9; sid:9;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER,
- readWriteMultipleRegistersReq,
- sizeof(readWriteMultipleRegistersReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF(PacketAlertCheck(p, 2));
- FAIL_IF(PacketAlertCheck(p, 4));
- FAIL_IF(PacketAlertCheck(p, 5));
- FAIL_IF(PacketAlertCheck(p, 7));
- FAIL_IF(PacketAlertCheck(p, 9));
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
- FAIL_IF_NOT(PacketAlertCheck(p, 3));
- FAIL_IF_NOT(PacketAlertCheck(p, 6));
- FAIL_IF_NOT(PacketAlertCheck(p, 8));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test Test code unit_id and code function. */
-static int DetectEngineInspectModbusTest11(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readWriteMultipleRegistersReq,
- sizeof(readWriteMultipleRegistersReq),
- IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
- /* Unit ID = 0x0a (10) */
- /* Function code = 0x17 (23) */
- /* Write access register address 15 = 0x1234 (4660) */
- /* Write access register address 16 = 0x5678 (22136) */
- /* Write access register address 17 = 0x9ABC (39612) */
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 10, function 20; sid:1;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 10, function 23; sid:2;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 11, function 20; sid:3;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 11, function 23; sid:4;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 10, function public; sid:5;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 11, function public; sid:6;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 10, function user; sid:7;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus code unit_id\"; "
- "modbus: unit 10, function !user; sid:8;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER,
- readWriteMultipleRegistersReq,
- sizeof(readWriteMultipleRegistersReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF(PacketAlertCheck(p, 1));
- FAIL_IF(PacketAlertCheck(p, 3));
- FAIL_IF(PacketAlertCheck(p, 4));
- FAIL_IF(PacketAlertCheck(p, 6));
- FAIL_IF(PacketAlertCheck(p, 7));
-
- FAIL_IF_NOT(PacketAlertCheck(p, 2));
- FAIL_IF_NOT(PacketAlertCheck(p, 5));
- FAIL_IF_NOT(PacketAlertCheck(p, 8));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-
-/** \test unit_id and read access at an address. */
-static int DetectEngineInspectModbusTest12(void)
-{
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- DetectEngineThreadCtx *det_ctx = NULL;
- DetectEngineCtx *de_ctx = NULL;
- Flow f;
- Packet *p = NULL;
- Signature *s = NULL;
- TcpSession ssn;
- ThreadVars tv;
-
- FAIL_IF_NULL(alp_tctx);
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof(TcpSession));
-
- p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
-
- FLOW_INITIALIZE(&f);
- f.alproto = ALPROTO_MODBUS;
- f.protoctx = (void *)&ssn;
- f.proto = IPPROTO_TCP;
- f.flags |= FLOW_IPV4;
-
- p->flow = &f;
- p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
- p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-
- StreamTcpInitConfig(true);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- /* readCoilsReq, Read coils Starting Address = 0x7890 (30864), Quantity of coils = 0x13 (19) */
- /* Unit ID = 0x0a (10) */
- /* Function code = 0x01 (01) */
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus address access\"; "
- "modbus: unit 10, access read, address 30870; sid:1;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus address access\"; "
- "modbus: unit 10, access read, address 30863; sid:2;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus address access\"; "
- "modbus: unit 11, access read, address 30870; sid:3;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus address access\"; "
- "modbus: unit 11, access read, address 30863; sid:4;)");
-
- s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus address access\"; "
- "modbus: unit 10, access write; sid:5;)");
- FAIL_IF_NULL(s);
-
- SigGroupBuild(de_ctx);
- DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
-
- FLOWLOCK_WRLOCK(&f);
- int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
- STREAM_TOSERVER, readCoilsReq,
- sizeof(readCoilsReq));
- FAIL_IF_NOT(r == 0);
- FLOWLOCK_UNLOCK(&f);
-
- FAIL_IF_NULL(f.alstate);
-
- /* do detect */
- SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-
- FAIL_IF(PacketAlertCheck(p, 2));
- FAIL_IF(PacketAlertCheck(p, 3));
- FAIL_IF(PacketAlertCheck(p, 4));
- FAIL_IF(PacketAlertCheck(p, 5));
-
- FAIL_IF_NOT(PacketAlertCheck(p, 1));
-
- AppLayerParserThreadCtxFree(alp_tctx);
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- SigGroupCleanup(de_ctx);
- DetectEngineCtxFree(de_ctx);
-
- StreamTcpFreeConfig(true);
- FLOW_DESTROY(&f);
- UTHFreePacket(p);
- PASS;
-}
-#endif /* UNITTESTS */
-
-void DetectEngineInspectModbusRegisterTests(void)
-{
-#ifdef UNITTESTS
- UtRegisterTest("DetectEngineInspectModbusTest01 - Code function",
- DetectEngineInspectModbusTest01);
- UtRegisterTest("DetectEngineInspectModbusTest02 - code function and code subfunction",
- DetectEngineInspectModbusTest02);
- UtRegisterTest("DetectEngineInspectModbusTest03 - Function category",
- DetectEngineInspectModbusTest03);
- UtRegisterTest("DetectEngineInspectModbusTest04 - Negative function category",
- DetectEngineInspectModbusTest04);
- UtRegisterTest("DetectEngineInspectModbusTest05 - Access type",
- DetectEngineInspectModbusTest05);
- UtRegisterTest("DetectEngineInspectModbusTest06 - Access function",
- DetectEngineInspectModbusTest06);
- UtRegisterTest("DetectEngineInspectModbusTest07 - Read access at an address",
- DetectEngineInspectModbusTest07);
- UtRegisterTest("DetectEngineInspectModbusTest08 - Read access at a range of address",
- DetectEngineInspectModbusTest08);
- UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value",
- DetectEngineInspectModbusTest09);
- UtRegisterTest("DetectEngineInspectModbusTest10 - Code unit_id",
- DetectEngineInspectModbusTest10);
- UtRegisterTest("DetectEngineInspectModbusTest11 - Code unit_id and code function",
- DetectEngineInspectModbusTest11);
- UtRegisterTest("DetectEngineInspectModbusTest12 - Code unit_id and acces function",
- DetectEngineInspectModbusTest12);
-#endif /* UNITTESTS */
- return;
-}
+++ /dev/null
-/*
- * Copyright (C) 2014 ANSSI
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** \file
- *
- * \author David DIALLO <diallo@et.esiea.fr>
- */
-
-#ifndef __DETECT_ENGINE_MODBUS_H__
-#define __DETECT_ENGINE_MODBUS_H__
-
-int DetectEngineInspectModbus(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *,
- const struct DetectEngineAppInspectionEngine_ *engine, const Signature *, Flow *, uint8_t,
- void *, void *, uint64_t);
-
-void DetectEngineInspectModbusRegisterTests(void);
-#endif /* __DETECT_ENGINE_MODBUS_H__ */
#include "util-debug.h"
#include "util-byte.h"
-#include "app-layer-modbus.h"
-
#include "stream-tcp.h"
#include "rust.h"
}
#ifdef UNITTESTS /* UNITTESTS */
-#include "util-unittest.h"
-
-/** Convert rust structure to C for regression tests.
- *
- * Note: Newly allocated `DetectModbus` structure must be freed.
- *
- * TODO: remove this after regression testing commit.
- */
-static DetectModbusValue *DetectModbusValueRustToC(uint16_t min, uint16_t max)
-{
- DetectModbusValue *value = SCMalloc(sizeof(*value));
- FAIL_IF_NULL(value);
-
- value->min = min;
- value->max = max;
-
- if (min == max) {
- value->mode = DETECT_MODBUS_EQ;
- } else if (min == 0) {
- value->mode = DETECT_MODBUS_LT;
- } else if (max == UINT16_MAX) {
- value->mode = DETECT_MODBUS_GT;
- } else {
- value->mode = DETECT_MODBUS_RA;
- }
-
- return value;
-}
-
-static DetectModbus *DetectModbusRustToC(DetectModbusRust *ctx)
-{
- DetectModbus *modbus = SCMalloc(sizeof(*modbus));
- FAIL_IF_NULL(modbus);
-
- modbus->category = rs_modbus_get_category(ctx);
- modbus->function = rs_modbus_get_function(ctx);
- modbus->subfunction = rs_modbus_get_subfunction(ctx);
- modbus->has_subfunction = rs_modbus_get_has_subfunction(ctx);
- modbus->type = rs_modbus_get_access_type(ctx);
-
- modbus->unit_id = DetectModbusValueRustToC(
- rs_modbus_get_unit_id_min(ctx), rs_modbus_get_unit_id_max(ctx));
-
- modbus->address = DetectModbusValueRustToC(
- rs_modbus_get_address_min(ctx), rs_modbus_get_address_max(ctx));
-
- modbus->data =
- DetectModbusValueRustToC(rs_modbus_get_data_min(ctx), rs_modbus_get_data_max(ctx));
-
- return modbus;
-}
-
-static void DetectModbusCFree(DetectModbus *modbus)
-{
- if (modbus) {
- if (modbus->unit_id)
- SCFree(modbus->unit_id);
-
- if (modbus->address)
- SCFree(modbus->address);
-
- if (modbus->data)
- SCFree(modbus->data);
-
- SCFree(modbus);
- }
-}
-
-/** \test Signature containing a function. */
-static int DetectModbusTest01(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus function\"; "
- "modbus: function 1; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+#include "app-layer-parser.h"
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+#include "flow-util.h"
- FAIL_IF_NOT(modbus->function == 1);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
-/** \test Signature containing a function and a subfunction. */
-static int DetectModbusTest02(void)
+/**
+ * Sample data for tests derived from
+ * https://github.com/bro/bro/blob/master/testing/btest/Traces/modbus/modbus.trace
+ */
+static uint8_t writeSingleCoil[] = {
+ /* Transaction ID */ 0x00, 0x01,
+ /* Protocol ID */ 0x00, 0x00,
+ /* Length */ 0x00, 0x06,
+ /* Unit ID */ 0x0a,
+ /* Function code */ 0x05,
+ /* Read Starting Address */ 0x00, 0x02,
+ /* Data */ 0x00, 0x00
+};
+
+static uint8_t restartCommOption[] = {
+ /* Transaction ID */ 0x00, 0x00,
+ /* Protocol ID */ 0x00, 0x00,
+ /* Length */ 0x00, 0x06,
+ /* Unit ID */ 0x0a,
+ /* Function code */ 0x08,
+ /* Diagnostic Code */ 0x00, 0x01,
+ /* Data */ 0x00, 0x00
+};
+
+/** \test Signature containing an access type. */
+static int DetectModbusTestAccess(void)
{
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ DetectEngineThreadCtx *det_ctx = NULL;
DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
+ Flow f;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
- de_ctx->flags |= DE_QUIET;
+ FAIL_IF_NULL(alp_tctx);
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus function and subfunction\"; "
- "modbus: function 8, subfunction 4; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&f, 0, sizeof(Flow));
+ memset(&ssn, 0, sizeof(TcpSession));
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ p = UTHBuildPacket(restartCommOption, sizeof(restartCommOption), IPPROTO_TCP);
- FAIL_IF_NOT(modbus->function == 8);
- FAIL_IF_NOT(modbus->subfunction == 4);
+ FLOW_INITIALIZE(&f);
+ f.alproto = ALPROTO_MODBUS;
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ f.flags |= FLOW_IPV4;
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
+ p->flow = &f;
+ p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+ p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
-/** \test Signature containing a function category. */
-static int DetectModbusTest03(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
+ StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
+ s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code function\"; "
+ "modbus: access write; sid:1;)");
+ FAIL_IF_NULL(s);
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.function\"; "
- "modbus: function reserved; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ FLOWLOCK_WRLOCK(&f);
+ int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
+ writeSingleCoil, sizeof(writeSingleCoil));
+ FAIL_IF_NOT(r == 0);
+ FLOWLOCK_UNLOCK(&f);
- FAIL_IF_NOT(modbus->category == MODBUS_CAT_RESERVED);
+ FAIL_IF_NULL(f.alstate);
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
-/** \test Signature containing a negative function category. */
-static int DetectModbusTest04(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus function\"; "
- "modbus: function !assigned; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF(modbus->category & MODBUS_CAT_PUBLIC_ASSIGNED);
- FAIL_IF_NOT(modbus->category & MODBUS_CAT_PUBLIC_UNASSIGNED);
- FAIL_IF_NOT(modbus->category & MODBUS_CAT_USER_DEFINED);
- FAIL_IF_NOT(modbus->category & MODBUS_CAT_RESERVED);
-
- DetectModbusCFree(modbus);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
- PASS;
-}
-/** \test Signature containing a access type. */
-static int DetectModbusTest05(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: access read; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF_NOT(modbus->type == MODBUS_TYP_READ);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePacket(p);
PASS;
}
-/** \test Signature containing a access function. */
-static int DetectModbusTest06(void)
+/** \test Signature containing a function. */
+static int DetectModbusTestFunction(void)
{
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ DetectEngineThreadCtx *det_ctx = NULL;
DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
-
- uint8_t type = (MODBUS_TYP_READ | MODBUS_TYP_DISCRETES);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: access read discretes; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF_NOT(modbus->type == type);
+ Flow f;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
-
-/** \test Signature containing a read access at an address. */
-static int DetectModbusTest07(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode mode = DETECT_MODBUS_EQ;
-
- uint8_t type = MODBUS_TYP_READ;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: access read, address 1000; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF_NOT(modbus->type == type);
- FAIL_IF_NOT((*modbus->address).mode == mode);
- FAIL_IF_NOT((*modbus->address).min == 1000);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
-
-/** \test Signature containing a write access at a range of address. */
-static int DetectModbusTest08(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode mode = DETECT_MODBUS_GT;
-
- uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_COILS);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: access write coils, address >500; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF_NOT(modbus->type == type);
- FAIL_IF_NOT((*modbus->address).mode == mode);
- FAIL_IF_NOT((*modbus->address).min == 500);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
-
-/** \test Signature containing a write access at a address a range of value. */
-static int DetectModbusTest09(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode addressMode = DETECT_MODBUS_EQ;
- DetectModbusMode valueMode = DETECT_MODBUS_RA;
-
- uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_HOLDING);
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: access write holding, address 100, value 500<>1000; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ FAIL_IF_NULL(alp_tctx);
- FAIL_IF_NOT(modbus->type == type);
- FAIL_IF_NOT((*modbus->address).mode == addressMode);
- FAIL_IF_NOT((*modbus->address).min == 100);
- FAIL_IF_NOT((*modbus->data).mode == valueMode);
- FAIL_IF_NOT((*modbus->data).min == 500);
- FAIL_IF_NOT((*modbus->data).max == 1000);
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&f, 0, sizeof(Flow));
+ memset(&ssn, 0, sizeof(TcpSession));
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
-
-/** \test Signature containing a unit_id. */
-static int DetectModbusTest10(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode mode = DETECT_MODBUS_EQ;
+ p = UTHBuildPacket(writeSingleCoil, sizeof(writeSingleCoil), IPPROTO_TCP);
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus unit_id\"; "
- "modbus: unit 10; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ FLOW_INITIALIZE(&f);
+ f.alproto = ALPROTO_MODBUS;
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ f.flags |= FLOW_IPV4;
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ p->flow = &f;
+ p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+ p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
- FAIL_IF_NOT((*modbus->unit_id).min == 10);
- FAIL_IF_NOT((*modbus->unit_id).mode == mode);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
-
-/** \test Signature containing a unit_id, a function and a subfunction. */
-static int DetectModbusTest11(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode mode = DETECT_MODBUS_EQ;
+ StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
+ s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code function\"; "
+ "modbus: function 8; sid:1;)");
+ FAIL_IF_NULL(s);
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus function and subfunction\"; "
- "modbus: unit 10, function 8, subfunction 4; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF_NOT((*modbus->unit_id).min == 10);
- FAIL_IF_NOT((*modbus->unit_id).mode == mode);
- FAIL_IF_NOT(modbus->function == 8);
- FAIL_IF_NOT(modbus->subfunction == 4);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
- PASS;
-}
-
-/** \test Signature containing an unit_id and a read access at an address. */
-static int DetectModbusTest12(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode mode = DETECT_MODBUS_EQ;
-
- uint8_t type = MODBUS_TYP_READ;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
- de_ctx->flags |= DE_QUIET;
+ FLOWLOCK_WRLOCK(&f);
+ int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
+ restartCommOption, sizeof(restartCommOption));
+ FAIL_IF_NOT(r == 0);
+ FLOWLOCK_UNLOCK(&f);
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: unit 10, access read, address 1000; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ FAIL_IF_NULL(f.alstate);
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- FAIL_IF_NOT((*modbus->unit_id).min == 10);
- FAIL_IF_NOT((*modbus->unit_id).mode == mode);
- FAIL_IF_NOT(modbus->type == type);
- FAIL_IF_NOT((*modbus->address).mode == mode);
- FAIL_IF_NOT((*modbus->address).min == 1000);
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- DetectModbusCFree(modbus);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
- PASS;
-}
-/** \test Signature containing a range of unit_id. */
-static int DetectModbusTest13(void)
-{
- DetectEngineCtx *de_ctx = NULL;
- DetectModbus *modbus = NULL;
- DetectModbusMode mode = DETECT_MODBUS_RA;
-
- de_ctx = DetectEngineCtxInit();
- FAIL_IF_NULL(de_ctx);
-
- de_ctx->flags |= DE_QUIET;
-
- de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
- "(msg:\"Testing modbus.access\"; "
- "modbus: unit 10<>500; sid:1;)");
- FAIL_IF_NULL(de_ctx->sig_list);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
- FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- modbus = DetectModbusRustToC(
- (DetectModbusRust *)de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
-
- FAIL_IF_NOT((*modbus->unit_id).min == 10);
- FAIL_IF_NOT((*modbus->unit_id).max == 500);
- FAIL_IF_NOT((*modbus->unit_id).mode == mode);
-
- DetectModbusCFree(modbus);
- SigGroupCleanup(de_ctx);
- SigCleanSignatures(de_ctx);
- DetectEngineCtxFree(de_ctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePacket(p);
PASS;
}
*/
void DetectModbusRegisterTests(void)
{
- UtRegisterTest("DetectModbusTest01 - Testing function",
- DetectModbusTest01);
- UtRegisterTest("DetectModbusTest02 - Testing function and subfunction",
- DetectModbusTest02);
- UtRegisterTest("DetectModbusTest03 - Testing category function",
- DetectModbusTest03);
- UtRegisterTest("DetectModbusTest04 - Testing category function in negative",
- DetectModbusTest04);
- UtRegisterTest("DetectModbusTest05 - Testing access type",
- DetectModbusTest05);
- UtRegisterTest("DetectModbusTest06 - Testing access function",
- DetectModbusTest06);
- UtRegisterTest("DetectModbusTest07 - Testing access at address",
- DetectModbusTest07);
- UtRegisterTest("DetectModbusTest08 - Testing a range of address",
- DetectModbusTest08);
- UtRegisterTest("DetectModbusTest09 - Testing write a range of value",
- DetectModbusTest09);
- UtRegisterTest("DetectModbusTest10 - Testing unit_id",
- DetectModbusTest10);
- UtRegisterTest("DetectModbusTest11 - Testing unit_id, function and subfunction",
- DetectModbusTest11);
- UtRegisterTest("DetectModbusTest12 - Testing unit_id and access at address",
- DetectModbusTest12);
- UtRegisterTest("DetectModbusTest13 - Testing a range of unit_id",
- DetectModbusTest13);
+ UtRegisterTest("DetectModbusTestAccess", DetectModbusTestAccess);
+ UtRegisterTest("DetectModbusTestFunction", DetectModbusTestFunction);
}
#endif /* UNITTESTS */
#ifndef __DETECT_MODBUS_H__
#define __DETECT_MODBUS_H__
-#include "app-layer-modbus.h"
-
-typedef enum {
- DETECT_MODBUS_EQ = 0, /** < EQual operator */
- DETECT_MODBUS_LT, /** < "Less Than" operator */
- DETECT_MODBUS_GT, /** < "Greater Than" operator */
- DETECT_MODBUS_RA, /** < RAnge operator */
-} DetectModbusMode;
-
-typedef struct DetectModbusValue_ {
- uint16_t min; /** < Modbus minimum [range] or equal value to match */
- uint16_t max; /** < Modbus maximum value [range] to match */
- DetectModbusMode mode; /** < Modbus operator used in the address/data signature */
-} DetectModbusValue;
-
-typedef struct DetectModbus_ {
- uint8_t category; /** < Modbus function code category to match */
- uint8_t function; /** < Modbus function code to match */
- uint16_t subfunction; /** < Modbus subfunction to match */
- bool has_subfunction; /** < Modbus subfunction indicator */
- uint8_t type; /** < Modbus access type to match */
- DetectModbusValue *unit_id; /** < Modbus unit id to match */
- DetectModbusValue *address; /** < Modbus address to match */
- DetectModbusValue *data; /** < Modbus data to match */
-} DetectModbus;
-
/* prototypes */
void DetectModbusRegister(void);
#include "detect-engine-dcepayload.h"
#include "detect-engine-state.h"
#include "detect-engine-tag.h"
-#include "detect-engine-modbus.h"
#include "detect-fast-pattern.h"
#include "flow.h"
#include "flow-timeout.h"
#endif
DeStateRegisterTests();
MemcmpRegisterTests();
- DetectEngineInspectModbusRegisterTests();
DetectEngineRegisterTests();
SCLogRegisterTests();
MagicRegisterTests();