ntp: convert reference_id to buffer and add keyword

Store the NTP reference ID as raw network-order bytes so it can be
exposed as a sticky buffer and matched with payload keywords. The
reference ID is often a 4 character string, or an IP address and not
just an integer identifier.

Updates the log reference ID to be a string of colon separated hex
digits as this matches what tshark does.

Ticket: #8488
(cherry picked from commit 713e4eb900)
pull/15411/head
Jason Ish 3 months ago committed by Victor Julien
parent 2a9a57378c
commit 587e4871b8

@ -36,6 +36,23 @@ Signature Example:
alert ntp any any -> any any (msg:"NTP client mode"; :example-rule-options:`ntp.mode:client;` sid:1; rev:1;)
ntp.reference_id
****************
``ntp.reference_id`` is a sticky buffer exposing the 4-byte NTP
reference ID.
Examples::
ntp.reference_id; content:"RATE";
ntp.reference_id; content:"|0a 00 00 01|";
Signature Example:
.. container:: example-rule
alert ntp any any -> any any (msg:"NTP reference ID RATE"; :example-rule-emphasis:`ntp.reference_id; content:"RATE";` sid:4; rev:1;)
ntp.stratum
***********

@ -4446,8 +4446,8 @@
"description": "The mode of the NTP message"
},
"reference_id": {
"type": "integer",
"description": "Identifies specific server or reference clock"
"type": "string",
"description": "Identifies specific server or reference clock as a colon-separated 4-byte hex string"
},
"stratum": {
"type": "integer",

@ -20,10 +20,14 @@ use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
use crate::detect::uint::{
detect_parse_uint_enum, DetectUintData, SCDetectU8Free, SCDetectU8Match, SCDetectU8Parse,
};
use crate::detect::{
helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer,
};
use std::ffi::CStr;
use std::os::raw::{c_int, c_void};
use suricata_sys::sys::{
DetectEngineCtx, DetectEngineThreadCtx, Flow, SCDetectHelperBufferProgressRegister,
DetectEngineCtx, DetectEngineThreadCtx, Flow, SCDetectBufferSetActiveList,
SCDetectHelperBufferProgressMpmRegister, SCDetectHelperBufferProgressRegister,
SCDetectHelperKeywordRegister, SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList,
SCSigTableAppLiteElmt, SigMatchCtx, Signature,
};
@ -32,6 +36,7 @@ static mut G_NTP_VERSION_KW_ID: u16 = 0;
static mut G_NTP_MODE_KW_ID: u16 = 0;
static mut G_NTP_STRATUM_KW_ID: u16 = 0;
static mut G_NTP_GENERIC_BUFFER_ID: c_int = 0;
static mut G_NTP_REFERENCE_ID_BUFFER_ID: c_int = 0;
#[derive(Clone, Debug, PartialEq, EnumStringU8)]
#[repr(u8)]
@ -164,6 +169,27 @@ unsafe extern "C" fn ntp_detect_stratum_match(
return SCDetectU8Match(tx.stratum, ctx);
}
unsafe extern "C" fn ntp_detect_reference_id_setup(
de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
) -> c_int {
if SCDetectSignatureSetAppProto(s, ALPROTO_NTP) != 0 {
return -1;
}
if SCDetectBufferSetActiveList(de, s, G_NTP_REFERENCE_ID_BUFFER_ID) < 0 {
return -1;
}
return 0;
}
unsafe extern "C" fn ntp_detect_reference_id_get_data(
tx: *const c_void, _flow_flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, NTPTransaction);
*buffer = tx.reference_id.as_ptr();
*buffer_len = tx.reference_id.len() as u32;
true
}
pub(super) unsafe extern "C" fn detect_ntp_register() {
let kw = SCSigTableAppLiteElmt {
name: b"ntp.version\0".as_ptr() as *const libc::c_char,
@ -203,6 +229,22 @@ pub(super) unsafe extern "C" fn detect_ntp_register() {
flags: 0,
};
G_NTP_STRATUM_KW_ID = SCDetectHelperKeywordRegister(&kw);
let kw = SigTableElmtStickyBuffer {
name: String::from("ntp.reference_id"),
desc: String::from("sticky buffer to match on the NTP reference ID"),
url: String::from("/rules/ntp-keywords.html#ntp-reference-id"),
setup: ntp_detect_reference_id_setup,
};
let _g_ntp_reference_id_kw_id = helper_keyword_register_sticky_buffer(&kw);
G_NTP_REFERENCE_ID_BUFFER_ID = SCDetectHelperBufferProgressMpmRegister(
b"ntp.reference_id\0".as_ptr() as *const libc::c_char,
b"NTP reference ID\0".as_ptr() as *const libc::c_char,
ALPROTO_NTP,
STREAM_TOSERVER | STREAM_TOCLIENT,
Some(ntp_detect_reference_id_get_data),
1,
);
}
#[cfg(test)]

@ -23,7 +23,13 @@ fn log(jb: &mut JsonBuilder, tx: &NTPTransaction) -> Result<(), JsonError> {
jb.set_uint("version", tx.version)?;
jb.set_uint("mode", tx.mode)?;
jb.set_uint("stratum", tx.stratum)?;
jb.set_uint("reference_id", tx.reference_id)?;
jb.set_string(
"reference_id",
&format!(
"{:02x}:{:02x}:{:02x}:{:02x}",
tx.reference_id[0], tx.reference_id[1], tx.reference_id[2], tx.reference_id[3]
),
)?;
jb.close()?;
Ok(())
}

@ -60,7 +60,7 @@ pub struct NTPState {
#[derive(Debug, Default)]
pub struct NTPTransaction {
/// The NTP reference ID
pub reference_id: u32,
pub reference_id: [u8; 4],
pub version: u8,
pub mode: u8,
@ -169,7 +169,7 @@ impl NTPState {
impl NTPTransaction {
pub fn new(direction: Direction, id: u64, reference_id: u32) -> NTPTransaction {
NTPTransaction {
reference_id,
reference_id: reference_id.to_be_bytes(),
id,
tx_data: applayer::AppLayerTxData::for_direction(direction),
..Default::default()

Loading…
Cancel
Save