From: Philippe Antoine Date: Wed, 26 May 2021 19:45:30 +0000 (+0200) Subject: http2: http.host normalized keyword now works for HTTP2 X-Git-Tag: suricata-6.0.4~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=629a8226a09ec1731fe886dd86dcaa9ea8c282ad;p=thirdparty%2Fsuricata.git http2: http.host normalized keyword now works for HTTP2 (cherry picked from commit 547e9f4ab42fb4a67dc67f85fa58e0c9a7e4c634) --- diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index b374a16999..f17571d551 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -552,6 +552,60 @@ pub unsafe extern "C" fn rs_http2_tx_get_host( return 0; } +fn http2_lower(value: &[u8]) -> Option> { + for i in 0..value.len() { + if value[i].is_ascii_uppercase() { + // we got at least one upper character, need to transform + let mut vec: Vec = Vec::with_capacity(value.len()); + vec.extend_from_slice(value); + for j in i..vec.len() { + vec[j].make_ascii_lowercase(); + } + return Some(vec); + } + } + return None; +} + +// returns a tuple with the value and its size +fn http2_normalize_host(value: &[u8]) -> (Option>, usize) { + match value.iter().position(|&x| x == ':' as u8) { + Some(i) => { + return (http2_lower(&value[..i]), i); + } + None => { + return (http2_lower(value), value.len()); + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn rs_http2_tx_get_host_norm( + tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, +) -> u8 { + if let Ok(value) = http2_frames_get_header_value(&tx.frames_ts, ":authority") { + let r = http2_normalize_host(value); + // r is a tuple with the value and its size + // this is useful when we only take a substring (before the port) + match r.0 { + Some(normval) => { + tx.escaped.push(normval); + let idx = tx.escaped.len() - 1; + let resvalue = &tx.escaped[idx]; + *buffer = resvalue.as_ptr(); //unsafe + *buffer_len = r.1 as u32; + return 1; + } + None => { + *buffer = value.as_ptr(); //unsafe + *buffer_len = r.1 as u32; + return 1; + } + } + } + return 0; +} + #[no_mangle] pub unsafe extern "C" fn rs_http2_tx_get_useragent( tx: &mut HTTP2Transaction, buffer: *mut *const u8, buffer_len: *mut u32, @@ -887,3 +941,41 @@ pub extern "C" fn rs_http2_tx_add_header( http2_tx_set_header(state, slice_name, slice_value) } } + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_http2_normalize_host() { + let buf0 = "aBC.com:1234".as_bytes(); + let r0 = http2_normalize_host(buf0); + match r0.0 { + Some(r) => { + assert_eq!(r, "abc.com".as_bytes().to_vec()); + } + None => { + panic!("Result should not have been None"); + } + } + let buf1 = "oisf.net".as_bytes(); + let r1 = http2_normalize_host(buf1); + match r1.0 { + Some(r) => { + panic!("Result should not have been None, not {:?}", r); + } + None => {} + } + assert_eq!(r1.1, "oisf.net".len()); + let buf2 = "localhost:3000".as_bytes(); + let r2 = http2_normalize_host(buf2); + match r2.0 { + Some(r) => { + panic!("Result should not have been None, not {:?}", r); + } + None => {} + } + assert_eq!(r2.1, "localhost".len()); + } +} diff --git a/src/detect-http-host.c b/src/detect-http-host.c index d470105469..108ca34430 100644 --- a/src/detect-http-host.c +++ b/src/detect-http-host.c @@ -77,6 +77,9 @@ static int DetectHttpHostRawSetupSticky(DetectEngineCtx *de_ctx, Signature *s, c static InspectionBuffer *GetRawData(DetectEngineThreadCtx *det_ctx, const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, const int list_id); +static InspectionBuffer *GetRawData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id); static int g_http_host_buffer_id = 0; /** @@ -110,6 +113,12 @@ void DetectHttpHHRegister(void) PrefilterGenericMpmRegister, GetData, ALPROTO_HTTP, HTP_REQUEST_HEADERS); + DetectAppLayerInspectEngineRegister2("http_host", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + + DetectAppLayerMpmRegister2("http_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, + GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + DetectBufferTypeRegisterValidateCallback("http_host", DetectHttpHostValidateCallback); @@ -142,10 +151,10 @@ void DetectHttpHHRegister(void) HTP_REQUEST_HEADERS); DetectAppLayerInspectEngineRegister2("http_raw_host", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, - HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetData2); + HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRawData2); DetectAppLayerMpmRegister2("http_raw_host", SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, - GetData2, ALPROTO_HTTP2, HTTP2StateDataClient); + GetRawData2, ALPROTO_HTTP2, HTTP2StateDataClient); DetectBufferTypeSetDescriptionByName("http_raw_host", "http raw host header"); @@ -224,7 +233,7 @@ static int DetectHttpHostSetup(DetectEngineCtx *de_ctx, Signature *s, const char if (DetectBufferSetActiveList(s, g_http_host_buffer_id) < 0) return -1; if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0) - return -1; + return -1; return 0; } @@ -258,6 +267,27 @@ static InspectionBuffer *GetData2(DetectEngineThreadCtx *det_ctx, uint32_t b_len = 0; const uint8_t *b = NULL; + if (rs_http2_tx_get_host_norm(txv, &b, &b_len) != 1) + return NULL; + if (b == NULL || b_len == 0) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + + return buffer; +} + +static InspectionBuffer *GetRawData2(DetectEngineThreadCtx *det_ctx, + const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, + const int list_id) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + uint32_t b_len = 0; + const uint8_t *b = NULL; + if (rs_http2_tx_get_host(txv, &b, &b_len) != 1) return NULL; if (b == NULL || b_len == 0)