From 0d6bb4104d293fa017704e0ce6da55b9190621a9 Mon Sep 17 00:00:00 2001 From: jrx Date: Mon, 25 Nov 2024 10:18:04 +0100 Subject: [PATCH 01/15] no need &ref on Copy types + consts --- src/chunks/firehose/activity.rs | 10 ++--- src/decoders/bool.rs | 8 ++-- src/decoders/decoder.rs | 22 +++++----- src/decoders/location.rs | 58 +++++++++++++-------------- src/message.rs | 71 ++++++++++++++++----------------- 5 files changed, 84 insertions(+), 85 deletions(-) diff --git a/src/chunks/firehose/activity.rs b/src/chunks/firehose/activity.rs index 5295bc9..03f2973 100755 --- a/src/chunks/firehose/activity.rs +++ b/src/chunks/firehose/activity.rs @@ -265,11 +265,11 @@ mod tests { assert_eq!(results.unknown_activity_id_3, 64435); assert_eq!(results.unknown_sentinal_3, 2147483648); assert_eq!(results.unknown_message_string_ref, 0); - assert_eq!(results.firehose_formatters.main_exe, false); - assert_eq!(results.firehose_formatters.absolute, false); - assert_eq!(results.firehose_formatters.shared_cache, false); - assert_eq!(results.firehose_formatters.main_plugin, false); - assert_eq!(results.firehose_formatters.pc_style, false); + assert!(!results.firehose_formatters.main_exe); + assert!(!results.firehose_formatters.absolute); + assert!(!results.firehose_formatters.shared_cache); + assert!(!results.firehose_formatters.main_plugin); + assert!(!results.firehose_formatters.pc_style); assert_eq!(results.firehose_formatters.main_exe_alt_index, 0); assert_eq!(results.firehose_formatters.uuid_relative, ""); assert_eq!(results.unknown_pc_id, 303578944); diff --git a/src/decoders/bool.rs b/src/decoders/bool.rs index d27bb18..1bf6816 100644 --- a/src/decoders/bool.rs +++ b/src/decoders/bool.rs @@ -22,9 +22,9 @@ pub(crate) fn lowercase_bool(bool_data: &str) -> String { } /// Return int value to bool -pub(crate) fn lowercase_int_bool(bool_data: &u8) -> String { - let false_bool = 0; - if bool_data == &false_bool { +pub(crate) fn lowercase_int_bool(bool_data: u8) -> String { + const FALSE_BOOL: u8 = 0; + if bool_data == FALSE_BOOL { return String::from("false"); } String::from("true") @@ -59,7 +59,7 @@ mod tests { #[test] fn test_lowercase_int_bool() { let test_data = 0; - let results = lowercase_int_bool(&test_data); + let results = lowercase_int_bool(test_data); assert_eq!(results, "false"); } } diff --git a/src/decoders/decoder.rs b/src/decoders/decoder.rs index 7004f1e..534d4f1 100644 --- a/src/decoders/decoder.rs +++ b/src/decoders/decoder.rs @@ -30,24 +30,24 @@ use crate::{ pub(crate) fn check_objects( format_string: &str, message_values: &[FirehoseItemInfo], - item_type: &u8, + item_type: u8, item_index: usize, ) -> String { let mut message_value = String::new(); let mut index = item_index; - let precision_item = 0x12; + const PRECISION_ITEM: u8 = 0x12; // Increment index get the actual firehose item data - if item_type == &precision_item { + if item_type == PRECISION_ITEM { index += 1; if index > message_values.len() { return format!("Index out of bounds for FirehoseItemInfo Vec. Got adjusted index {}, Vec size is {}. This should not have happened", index, message_values.len()); } } - let masked_hash_type = 0xf2; + const MASKED_HASH_TYPE: u8 = 0xf2; // Check if the log value is hashed or marked private - if (format_string.contains("mask.hash") && message_values[index].item_type == masked_hash_type) + if (format_string.contains("mask.hash") && message_values[index].item_type == MASKED_HASH_TYPE) || message_values[index].message_strings == "" { return message_values[index].message_strings.to_owned(); @@ -143,7 +143,7 @@ mod tests { let test_type = 0; let test_index = 0; - let results = check_objects(test_format, &vec![test_item_info], &test_type, test_index); + let results = check_objects(test_format, &[test_item_info], test_type, test_index); assert_eq!(results, "true") } @@ -158,7 +158,7 @@ mod tests { let test_type = 0; let test_index = 0; - let results = check_objects(test_format, &vec![test_item_info], &test_type, test_index); + let results = check_objects(test_format, &[test_item_info], test_type, test_index); assert_eq!(results, "YES") } @@ -173,7 +173,7 @@ mod tests { let test_type = 50; // 0x32 let test_index = 0; - let results = check_objects(test_format, &vec![test_item_info], &test_type, test_index); + let results = check_objects(test_format, &[test_item_info], test_type, test_index); assert_eq!(results, "user: -2@/Local/Default"); } @@ -188,7 +188,7 @@ mod tests { let test_type = 50; // 0x32 let test_index = 0; - let results = check_objects(test_format, &vec![test_item_info], &test_type, test_index); + let results = check_objects(test_format, &[test_item_info], test_type, test_index); assert_eq!(results, "85957E1D36C44ED286A80657BCDDE293") } @@ -203,7 +203,7 @@ mod tests { let test_type = 50; // 0x32 let test_index = 0; - let results = check_objects(test_format, &vec![test_item_info], &test_type, test_index); + let results = check_objects(test_format, &[test_item_info], test_type, test_index); assert_eq!(results, "") } @@ -218,7 +218,7 @@ mod tests { let test_type = 242; // 0x32 let test_index = 0; - let results = check_objects(test_format, &vec![test_item_info], &test_type, test_index); + let results = check_objects(test_format, &[test_item_info], test_type, test_index); assert_eq!(results, "hash") } } diff --git a/src/decoders/location.rs b/src/decoders/location.rs index c7b5b0e..96084d7 100644 --- a/src/decoders/location.rs +++ b/src/decoders/location.rs @@ -423,32 +423,32 @@ fn location_tracker_object(tracker: &LocationTrackerState) -> String { }}", tracker.distance_filter, tracker.desired_accuracy, - lowercase_int_bool(&tracker.updating_location), - lowercase_int_bool(&tracker.requesting_location), - lowercase_int_bool(&tracker.requesting_ranging), - lowercase_int_bool(&tracker.updating_ranging), - lowercase_int_bool(&tracker.updating_heading), + lowercase_int_bool(tracker.updating_location), + lowercase_int_bool(tracker.requesting_location), + lowercase_int_bool(tracker.requesting_ranging), + lowercase_int_bool(tracker.updating_ranging), + lowercase_int_bool(tracker.updating_heading), tracker.heading_filter, - lowercase_int_bool(&tracker.allows_location_prompts), - lowercase_int_bool(&tracker.allows_altered_locations), - lowercase_int_bool(&tracker.dynamic_accuracy), - lowercase_int_bool(&tracker.previous_authorization_status_valid), + lowercase_int_bool(tracker.allows_location_prompts), + lowercase_int_bool(tracker.allows_altered_locations), + lowercase_int_bool(tracker.dynamic_accuracy), + lowercase_int_bool(tracker.previous_authorization_status_valid), tracker.previous_authorization_status, - lowercase_int_bool(&tracker.limits_precision), + lowercase_int_bool(tracker.limits_precision), tracker.activity_type, tracker.pauses_location_updates, - lowercase_int_bool(&tracker.paused), - lowercase_int_bool(&tracker.allows_background_updates), - lowercase_int_bool(&tracker.shows_background_location), - lowercase_int_bool(&tracker.allows_map_correction), - lowercase_int_bool(&tracker.batching_location), - lowercase_int_bool(&tracker.updating_vehicle_speed), - lowercase_int_bool(&tracker.updating_vehicle_heading), - lowercase_int_bool(&tracker.match_info), - lowercase_int_bool(&tracker.ground_altitude), - lowercase_int_bool(&tracker.fusion_info), - lowercase_int_bool(&tracker.courtesy_prompt), - lowercase_int_bool(&tracker.is_authorized_for_widgets), + lowercase_int_bool(tracker.paused), + lowercase_int_bool(tracker.allows_background_updates), + lowercase_int_bool(tracker.shows_background_location), + lowercase_int_bool(tracker.allows_map_correction), + lowercase_int_bool(tracker.batching_location), + lowercase_int_bool(tracker.updating_vehicle_speed), + lowercase_int_bool(tracker.updating_vehicle_heading), + lowercase_int_bool(tracker.match_info), + lowercase_int_bool(tracker.ground_altitude), + lowercase_int_bool(tracker.fusion_info), + lowercase_int_bool(tracker.courtesy_prompt), + lowercase_int_bool(tracker.is_authorized_for_widgets), ) } @@ -546,15 +546,15 @@ pub(crate) fn get_daemon_status_tracker(data: &[u8]) -> nom::IResult<&[u8], Stri r#"{{"thermalLevel": {}, "reachability: "{}", "airplaneMode": {}, "batteryData":{{"wasConnected": {}, "charged": {}, "level": {}, "connected": {}, "chargerType": "{}"}}, "restrictedMode": {}, "batterySaverModeEnabled": {}, "push_service":{}}}"#, thermal_level, reachability_str, - lowercase_int_bool(&airplane), - lowercase_int_bool(&was_connected), - lowercase_int_bool(&charged), + lowercase_int_bool(airplane), + lowercase_int_bool(was_connected), + lowercase_int_bool(charged), level, - lowercase_int_bool(&connected), + lowercase_int_bool(connected), charger_type_str, - lowercase_int_bool(&restricted), - lowercase_int_bool(&battery_saver), - lowercase_int_bool(&push_service) + lowercase_int_bool(restricted), + lowercase_int_bool(battery_saver), + lowercase_int_bool(push_service) ); Ok((location_data, message)) diff --git a/src/message.rs b/src/message.rs index 314d485..612f2db 100755 --- a/src/message.rs +++ b/src/message.rs @@ -164,7 +164,7 @@ pub fn format_firehose_log_message( let results = parse_type_formatter( formatter_string, item_message, - &item_message[item_index].item_type, + item_message[item_index].item_type, item_index, ); match results { @@ -204,7 +204,7 @@ pub fn format_firehose_log_message( let results = parse_formatter( formatter_string, item_message, - &item_message[item_index].item_type, + item_message[item_index].item_type, item_index, ); match results { @@ -214,9 +214,9 @@ pub fn format_firehose_log_message( } } - let precision_items = [0x10, 0x12]; // dynamic precision item types? - // If the item message was a precision type increment to actual value - if precision_items.contains(&item_message[item_index].item_type) { + const PRECISION_ITEMS: [u8; 2] = [0x10, 0x12]; // dynamic precision item types? + // If the item message was a precision type increment to actual value + if PRECISION_ITEMS.contains(&item_message[item_index].item_type) { item_index += 1; } @@ -267,14 +267,14 @@ pub fn format_firehose_log_message( fn parse_formatter<'a>( formatter: &'a str, message_value: &'a [FirehoseItemInfo], - item_type: &'a u8, + item_type: u8, item_index: usize, ) -> nom::IResult<&'a str, String> { let mut index = item_index; - let precision_items = [0x10, 0x12]; + const PRECISION_ITEMS: [u8; 2] = [0x10, 0x12]; let mut precision_value = 0; - if precision_items.contains(item_type) { + if PRECISION_ITEMS.contains(&item_type) { precision_value = message_value[index].item_size as usize; index += 1; @@ -342,8 +342,8 @@ fn parse_formatter<'a>( if formatter_message.starts_with('*') { // Also seen number type value 0 used for dynamic width/precision value - let dynamic_precision_value = 0x0; - if item_type == &dynamic_precision_value && message_value[index].item_size == 0 { + const DYNAMIC_PRECISION_VALUE: u8 = 0x0; + if item_type == DYNAMIC_PRECISION_VALUE && message_value[index].item_size == 0 { precision_value = message_value[index].item_size as usize; index += 1; if index >= message_value.len() { @@ -470,7 +470,7 @@ fn parse_formatter<'a>( fn parse_type_formatter<'a>( formatter: &'a str, message_value: &'a [FirehoseItemInfo], - item_type: &'a u8, + item_type: u8, item_index: usize, ) -> nom::IResult<&'a str, String> { let (format, format_type) = take_until("}")(formatter)?; @@ -1103,12 +1103,11 @@ mod tests { #[test] fn test_format_firehose_log_message() { let test_data = String::from("opendirectoryd (build %{public}s) launched..."); - let mut item_message: Vec = Vec::new(); - item_message.push(FirehoseItemInfo { + let item_message = vec![FirehoseItemInfo { message_strings: String::from("796.100"), item_type: 34, item_size: 0, - }); + }]; let message_re = Regex::new(r"(%(?:(?:\{[^}]+}?)(?:[-+0#]{0,5})(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:h|hh|l|ll|w|I|z|t|q|I32|I64)?[cmCdiouxXeEfgGaAnpsSZP@%}]|(?:[-+0 #]{0,5})(?:\d+|\*)?(?:\.(?:\d+|\*))?(?:h|hh|l||q|t|ll|w|I|z|I32|I64)?[cmCdiouxXeEfgGaAnpsSZP@%]))").unwrap(); let log_string = format_firehose_log_message(test_data, &item_message, &message_re); @@ -1131,7 +1130,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1141,7 +1140,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1151,7 +1150,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1162,7 +1161,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1172,7 +1171,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1183,7 +1182,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1194,7 +1193,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_float, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1204,7 +1203,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_float, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1214,7 +1213,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_float, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1225,7 +1224,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_float, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1236,7 +1235,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_int, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1247,7 +1246,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_float, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1258,7 +1257,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_float, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1269,7 +1268,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_string, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1280,7 +1279,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_string, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1298,7 +1297,7 @@ mod tests { let (_, formatted_results) = parse_formatter( test_string, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1321,7 +1320,7 @@ mod tests { let (_, formatted_results) = parse_type_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1341,7 +1340,7 @@ mod tests { let (_, formatted_results) = parse_type_formatter( test_format, &test_message, - &test_message[0].item_type, + test_message[0].item_type, item_index, ) .unwrap(); @@ -1405,7 +1404,7 @@ mod tests { test_format, test_width, test_precision, - &test_type, + test_type, plus_minus, hashtag, ); @@ -1424,7 +1423,7 @@ mod tests { test_format, test_width, test_precision, - &test_type, + test_type, plus_minus, hashtag, ); @@ -1439,7 +1438,7 @@ mod tests { let plus_minus = false; let hashtag = false; let formatted_results = - format_left(test_format, test_precision, &test_type, plus_minus, hashtag); + format_left(test_format, test_precision, test_type, plus_minus, hashtag); assert_eq!(formatted_results, "2"); } @@ -1451,7 +1450,7 @@ mod tests { let plus_minus = false; let hashtag = false; let formatted_results = - format_right(test_format, test_precision, &test_type, plus_minus, hashtag); + format_right(test_format, test_precision, test_type, plus_minus, hashtag); assert_eq!(formatted_results, "2"); } From 7f36025c145a1d7270011011ae4f4ee03a0671a6 Mon Sep 17 00:00:00 2001 From: jrx Date: Mon, 25 Nov 2024 13:19:08 +0100 Subject: [PATCH 02/15] use super --- src/decoders/bool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoders/bool.rs b/src/decoders/bool.rs index 1bf6816..ca24012 100644 --- a/src/decoders/bool.rs +++ b/src/decoders/bool.rs @@ -32,7 +32,7 @@ pub(crate) fn lowercase_int_bool(bool_data: u8) -> String { #[cfg(test)] mod tests { - use crate::decoders::bool::{lowercase_bool, lowercase_int_bool, uppercase_bool}; + use super::*; #[test] fn test_uppercase_bool() { From 52d910742b784f7eed07492fe8fc10c6058ab336 Mon Sep 17 00:00:00 2001 From: jrx Date: Mon, 25 Nov 2024 13:19:55 +0100 Subject: [PATCH 03/15] there is really a lot I don't understand in the `dns.rs` file --- src/decoders/dns.rs | 186 ++++++++++++++++++++++++++++++++------------ 1 file changed, 136 insertions(+), 50 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index e18ce0d..22c0216 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -13,6 +13,8 @@ use nom::{ bits, bytes::complete::take, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, + sequence::tuple, + IResult, }; use std::{ mem::size_of, @@ -48,12 +50,12 @@ pub(crate) fn parse_dns_header(data: &str) -> String { /// Get the DNS header data fn get_dns_header(data: &[u8]) -> nom::IResult<&[u8], String> { - let (dns_data, id_data) = take(size_of::())(data)?; - let (dns_data, flag_data) = take(size_of::())(dns_data)?; - - let (_, id) = be_u16(id_data)?; + let (dns_data, id) = be_u16(data)?; + // todo: why limiting here the parse to 2 bytes ? while get_dns_flags is made to parse 13 ? + let (dns_data, flag_data) = take(size_of::())(dns_data)?; let message_result = get_dns_flags(flag_data); + let message = match message_result { Ok(result) => result.1, Err(err) => { @@ -65,9 +67,10 @@ fn get_dns_header(data: &[u8]) -> nom::IResult<&[u8], String> { } }; + // todo: why parsing here the counts ? while the first 2 bytes are already parsed as dns flags ? let message_result = parse_counts(dns_data); let count_message = match message_result { - Ok((_, result)) => result, + Ok((_, result)) => result.to_string(), Err(err) => { error!( "[macos-unifiedlogs] Failed to parse DNS header counts. Error: {:?}", @@ -87,8 +90,76 @@ fn get_dns_header(data: &[u8]) -> nom::IResult<&[u8], String> { Ok((dns_data, header_message)) } +/// Parse the DNS bit flags +fn get_dns_flags_could_be(data: &[u8]) -> IResult<&[u8], String> { + dbg!(data); + let ( + input, + ( + query_flag, + opcode, + authoritative_flag, + truncation_flag, + recursion_desired, + recursion_available, + mut response_code, + ), + ) = tuple((be_u8, be_u32, be_u8, be_u8, be_u8, be_u8, be_u32))(data)?; + + const RESERVED_MASK: u32 = 0b00011111111111111111111111111111111; + response_code &= RESERVED_MASK; + + let opcode_message = match opcode { + 0 => "QUERY", + 1 => "IQUERY", + 2 => "STATUS", + 3 => "RESERVED", + 4 => "NOTIFY", + 5 => "UPDATE", + _ => "UNKNOWN OPCODE", + }; + + let response_message = match response_code { + 0 => "No Error", + 1 => "Format Error", + 2 => "Server Failure", + 3 => "NX Domain", + 4 => "Not Implemented", + 5 => "Refused", + 6 => "YX Domain", + 7 => "YX RR Set", + 8 => "NX RR Set", + 9 => "Not Auth", + 10 => "Not Zone", + _ => "Unknown Response Code", + }; + + let message = format!( + "Opcode: {}, +Query Type: {}, +Authoritative Answer Flag: {}, +Truncation Flag: {}, +Recursion Desired: {}, +Recursion Available: {}, +Response Code: {}", + opcode_message, + query_flag, + authoritative_flag, + truncation_flag, + recursion_desired, + recursion_available, + response_message + ); + + Ok(dbg!((input, message))) +} + /// Parse the DNS bit flags fn get_dns_flags(data: &[u8]) -> nom::IResult<(&[u8], usize), String> { + // todo: it's really weird that we can parse something like 13 bytes here + // wihout error even if the input is only 2 bytes long + // see data passed in unit tests to `parse_idflags` for instance + // Have to work with bits instead of bytes for the DNS flags let ((flag_data, offset), query_flag): ((&[u8], usize), u8) = bits::complete::take(size_of::())((data, 0))?; @@ -531,11 +602,9 @@ pub(crate) fn dns_idflags(data: &str) -> String { /// Parse just the DNS flags associated with the DNS header fn parse_idflags(data: &[u8]) -> nom::IResult<&[u8], String> { - let (dns_data, id_data) = take(size_of::())(data)?; + let (dns_data, id) = be_u16(data)?; let flag_results = get_dns_flags(dns_data); - let (_, id) = be_u16(id_data)?; - let message = match flag_results { Ok((_, result)) => result, Err(err) => { @@ -544,6 +613,8 @@ fn parse_idflags(data: &[u8]) -> nom::IResult<&[u8], String> { } }; + // todo: should be the `get_dns_flags` parser that output what can be used as `flags` + // the responsibility for the `dns_data` format knowledge should not be shared into multiple functions let (_, flags) = be_u16(dns_data)?; Ok(( dns_data, @@ -553,6 +624,9 @@ fn parse_idflags(data: &[u8]) -> nom::IResult<&[u8], String> { /// Get just the DNS count data associated with the DNS header pub(crate) fn dns_counts(data: &str) -> String { + // todo: not sure error handling should be handled as strings + // todo: this function + let flags_results = data.parse::(); let flags: u64 = match flags_results { Ok(results) => results, @@ -580,7 +654,7 @@ pub(crate) fn dns_counts(data: &str) -> String { let message_result = parse_counts(&bytes); match message_result { - Ok((_, result)) => result, + Ok((_, result)) => result.to_string(), Err(err) => { error!("[macos-unifiedlogs] Failed to get counts: {:?}", err); data.to_string() @@ -588,26 +662,38 @@ pub(crate) fn dns_counts(data: &str) -> String { } } -/// parse just the DNS count data associated with the DNS header -fn parse_counts(data: &[u8]) -> nom::IResult<&[u8], String> { - let (dns_data, question_data) = take(size_of::())(data)?; - let (dns_data, answer_data) = take(size_of::())(dns_data)?; - let (dns_data, authority_data) = take(size_of::())(dns_data)?; - let (dns_data, additional_data) = take(size_of::())(dns_data)?; +#[derive(Debug, PartialEq)] +struct DnsCounts { + question: u16, + answer: u16, + authority: u16, + additional: u16, +} - let (_, question) = be_u16(question_data)?; - let (_, answer) = be_u16(answer_data)?; - let (_, authority) = be_u16(authority_data)?; - let (_, additional) = be_u16(additional_data)?; +impl std::fmt::Display for DnsCounts { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Question Count: {}, Answer Record Count: {}, Authority Record Count: {}, Additional Record Count: {}", + self.question, self.answer, self.authority, self.additional + ) + } +} - let header_message = format!( - "Question Count: {}, Answer Record Count: {}, Authority Record Count: {}, Additional Record Count: {}", - question, - answer, - authority, - additional); +/// parse just the DNS count data associated with the DNS header +fn parse_counts(data: &[u8]) -> nom::IResult<&[u8], DnsCounts> { + let (input, (question, answer, authority, additional)) = + tuple((be_u16, be_u16, be_u16, be_u16))(data)?; - Ok((dns_data, header_message)) + Ok(( + input, + DnsCounts { + question, + answer, + authority, + additional, + }, + )) } /// Translate DNS yes/no log values @@ -643,16 +729,8 @@ pub(crate) fn dns_getaddrinfo_opts(data: &str) -> String { #[cfg(test)] mod tests { - use crate::{ - decoders::dns::{ - dns_acceptable, dns_addrmv, dns_counts, dns_getaddrinfo_opts, dns_idflags, dns_ip_addr, - dns_protocol, dns_reason, dns_records, dns_yes_no, get_dns_flags, get_dns_header, - get_dns_mac_addr, get_domain_name, get_service_binding, parse_counts, parse_dns_header, - parse_dns_ip_addr, parse_idflags, parse_mac_addr, parse_svcb, parse_svcb_alpn, - parse_svcb_ip, - }, - util::decode_standard, - }; + use super::*; + use crate::util::decode_standard; #[test] fn test_parse_dns_header() { @@ -678,7 +756,7 @@ mod tests { #[test] fn test_get_domain_name() { let test_data = "AzE0NAMxMDEDMTY4AzE5Mgdpbi1hZGRyBGFycGEA"; - let result = get_domain_name(&test_data); + let result = get_domain_name(test_data); assert_eq!(result, ".144.101.168.192.in-addr.arpa"); } @@ -686,7 +764,7 @@ mod tests { fn test_get_service_binding() { let test_data = "AAEAAAEAAwJoMgAEAAhoEJRAaBCVQAAGACAmBkcAAAAAAAAAAABoEJRAJgZHAAAAAAAAAAAAaBCVQA=="; - let result = get_service_binding(&test_data); + let result = get_service_binding(test_data); assert_eq!(result, "rdata: 1 . alpn=h2, ipv4 hint:104.16.148.64,104.16.149.64, ipv6 hint:2606:4700::6810:9440,2606:4700::6810:9540,"); } @@ -723,7 +801,7 @@ mod tests { fn test_get_dns_mac_addr() { let test_data = "AAAAAAAA"; - let result = get_dns_mac_addr(&test_data); + let result = get_dns_mac_addr(test_data); assert_eq!(result, "00:00:00:00:00:00"); } @@ -739,7 +817,7 @@ mod tests { fn test_dns_ip_addr() { let test_data = "BAAAAMCoZZAAAAAAAAAAAAAAAAA="; - let result = dns_ip_addr(&test_data); + let result = dns_ip_addr(test_data); assert_eq!(result, "192.168.101.144"); } @@ -757,7 +835,7 @@ mod tests { fn test_dns_addrmv() { let test_data = "1"; - let result = dns_addrmv(&test_data); + let result = dns_addrmv(test_data); assert_eq!(result, "add"); } @@ -765,7 +843,7 @@ mod tests { fn test_dns_records() { let test_data = "65"; - let result = dns_records(&test_data); + let result = dns_records(test_data); assert_eq!(result, "HTTPS"); } @@ -773,7 +851,7 @@ mod tests { fn test_dns_reason() { let test_data = "1"; - let result = dns_reason(&test_data); + let result = dns_reason(test_data); assert_eq!(result, "no-data"); } @@ -781,7 +859,7 @@ mod tests { fn test_dns_protocol() { let test_data = "1"; - let result = dns_protocol(&test_data); + let result = dns_protocol(test_data); assert_eq!(result, "UDP"); } @@ -789,7 +867,7 @@ mod tests { fn test_dns_idflags() { let test_data = "2126119168"; - let result = dns_idflags(&test_data); + let result = dns_idflags(test_data); assert_eq!(result, "id: 0x7EBA, flags: 0x100 Opcode: QUERY, \n Query Type: 0,\n Authoritative Answer Flag: 0, \n Truncation Flag: 0, \n Recursion Desired: 1, \n Recursion Available: 0, \n Response Code: No Error"); } @@ -805,7 +883,7 @@ mod tests { fn test_dns_counts() { let test_data = "281474976710656"; - let result = dns_counts(&test_data); + let result = dns_counts(test_data); assert_eq!(result, "Question Count: 1, Answer Record Count: 0, Authority Record Count: 0, Additional Record Count: 0"); } @@ -814,14 +892,22 @@ mod tests { let test_data = vec![0, 1, 0, 0, 0, 0, 0, 0]; let (_, result) = parse_counts(&test_data).unwrap(); - assert_eq!(result, "Question Count: 1, Answer Record Count: 0, Authority Record Count: 0, Additional Record Count: 0"); + assert_eq!( + result, + DnsCounts { + question: 1, + answer: 0, + authority: 0, + additional: 0 + } + ); } #[test] fn test_dns_yes_no() { let test_data = "0"; - let result = dns_yes_no(&test_data); + let result = dns_yes_no(test_data); assert_eq!(result, "no"); } @@ -829,7 +915,7 @@ mod tests { fn test_dns_acceptable() { let test_data = "0"; - let result = dns_acceptable(&test_data); + let result = dns_acceptable(test_data); assert_eq!(result, "unacceptable"); } @@ -837,7 +923,7 @@ mod tests { fn test_dns_getaddrinfo_opts() { let test_data = "8"; - let result = dns_getaddrinfo_opts(&test_data); + let result = dns_getaddrinfo_opts(test_data); assert_eq!(result, "0x8 {use-failover}"); } } From 6736c451069bb9a0d7e47603099ff78fc30ca58b Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 11:33:57 +0100 Subject: [PATCH 04/15] super if/else expression direct assigment --- src/decoders/decoder.rs | 77 +++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/decoders/decoder.rs b/src/decoders/decoder.rs index 534d4f1..6e85df5 100644 --- a/src/decoders/decoder.rs +++ b/src/decoders/decoder.rs @@ -33,7 +33,6 @@ pub(crate) fn check_objects( item_type: u8, item_index: usize, ) -> String { - let mut message_value = String::new(); let mut index = item_index; const PRECISION_ITEM: u8 = 0x12; @@ -54,76 +53,78 @@ pub(crate) fn check_objects( } // Check if log value contains one the supported decoders - if format_string.contains("BOOL") { - message_value = uppercase_bool(&message_values[index].message_strings); + let message_value = if format_string.contains("BOOL") { + uppercase_bool(&message_values[index].message_strings) } else if format_string.contains("bool") { - message_value = lowercase_bool(&message_values[index].message_strings); + lowercase_bool(&message_values[index].message_strings) } else if format_string.contains("uuid_t") { - message_value = parse_uuid(&message_values[index].message_strings); + parse_uuid(&message_values[index].message_strings) } else if format_string.contains("darwin.errno") { - message_value = errno_codes(&message_values[index].message_strings); + errno_codes(&message_values[index].message_strings) } else if format_string.contains("darwin.mode") { - message_value = permission(&message_values[index].message_strings); + permission(&message_values[index].message_strings) } else if format_string.contains("odtypes:ODError") { - message_value = errors(&message_values[index].message_strings); + errors(&message_values[index].message_strings) } else if format_string.contains("odtypes:mbridtype") { - message_value = member_id_type(&message_values[index].message_strings); + member_id_type(&message_values[index].message_strings) } else if format_string.contains("odtypes:mbr_details") { - message_value = member_details(&message_values[index].message_strings); + member_details(&message_values[index].message_strings) } else if format_string.contains("odtypes:nt_sid_t") { - message_value = sid_details(&message_values[index].message_strings); + sid_details(&message_values[index].message_strings) } else if format_string.contains("location:CLClientAuthorizationStatus") { - message_value = client_authorization_status(&message_values[index].message_strings) + client_authorization_status(&message_values[index].message_strings) } else if format_string.contains("location:CLDaemonStatus_Type::Reachability") { - message_value = daemon_status_type(&message_values[index].message_strings); + daemon_status_type(&message_values[index].message_strings) } else if format_string.contains("location:CLSubHarvesterIdentifier") { - message_value = subharvester_identifier(&message_values[index].message_strings); + subharvester_identifier(&message_values[index].message_strings) } else if format_string.contains("location:SqliteResult") { - message_value = sqlite(&message_values[index].message_strings); + sqlite(&message_values[index].message_strings) } else if format_string.contains("location:_CLClientManagerStateTrackerState") { - message_value = client_manager_state_tracker_state(&message_values[index].message_strings); + client_manager_state_tracker_state(&message_values[index].message_strings) } else if format_string.contains("location:_CLLocationManagerStateTrackerState") { - message_value = - location_manager_state_tracker_state(&message_values[index].message_strings); + location_manager_state_tracker_state(&message_values[index].message_strings) } else if format_string.contains("network:in6_addr") { - message_value = ipv_six(&message_values[index].message_strings); + ipv_six(&message_values[index].message_strings) } else if format_string.contains("network:in_addr") { - message_value = ipv_four(&message_values[index].message_strings); + ipv_four(&message_values[index].message_strings) } else if format_string.contains("network:sockaddr") { - message_value = sockaddr(&message_values[index].message_strings); + sockaddr(&message_values[index].message_strings) } else if format_string.contains("time_t") { - message_value = parse_time(&message_values[index].message_strings); + parse_time(&message_values[index].message_strings) } else if format_string.contains("mdns:dnshdr") { - message_value = parse_dns_header(&message_values[index].message_strings); + parse_dns_header(&message_values[index].message_strings) } else if format_string.contains("mdns:rd.svcb") { - message_value = get_service_binding(&message_values[index].message_strings); + get_service_binding(&message_values[index].message_strings) } else if format_string.contains("location:IOMessage") { - message_value = io_message(&message_values[index].message_strings); + io_message(&message_values[index].message_strings) } else if format_string.contains("mdnsresponder:domain_name") { - message_value = get_domain_name(&message_values[index].message_strings); + get_domain_name(&message_values[index].message_strings) } else if format_string.contains("mdnsresponder:mac_addr") { - message_value = get_dns_mac_addr(&message_values[index].message_strings); + get_dns_mac_addr(&message_values[index].message_strings) } else if format_string.contains("mdnsresponder:ip_addr") { - message_value = dns_ip_addr(&message_values[index].message_strings); + dns_ip_addr(&message_values[index].message_strings) } else if format_string.contains("mdns:addrmv") { - message_value = dns_addrmv(&message_values[index].message_strings); + dns_addrmv(&message_values[index].message_strings) } else if format_string.contains("mdns:rrtype") { - message_value = dns_records(&message_values[index].message_strings); + dns_records(&message_values[index].message_strings) } else if format_string.contains("mdns:nreason") { - message_value = dns_reason(&message_values[index].message_strings); + dns_reason(&message_values[index].message_strings) } else if format_string.contains("mdns:protocol") { - message_value = dns_protocol(&message_values[index].message_strings); + dns_protocol(&message_values[index].message_strings) } else if format_string.contains("mdns:dns.idflags") { - message_value = dns_idflags(&message_values[index].message_strings); + dns_idflags(&message_values[index].message_strings) } else if format_string.contains("mdns:dns.counts") { - message_value = dns_counts(&message_values[index].message_strings); + dns_counts(&message_values[index].message_strings) } else if format_string.contains("mdns:yesno") { - message_value = dns_yes_no(&message_values[index].message_strings); + dns_yes_no(&message_values[index].message_strings) } else if format_string.contains("mdns:acceptable") { - message_value = dns_acceptable(&message_values[index].message_strings); + dns_acceptable(&message_values[index].message_strings) } else if format_string.contains("mdns:gaiopts") { - message_value = dns_getaddrinfo_opts(&message_values[index].message_strings); - } + dns_getaddrinfo_opts(&message_values[index].message_strings) + } else { + String::new() + }; + message_value } From d1064e47e4d6e3ee8ba40fb3876623bc4d8702d4 Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 12:34:15 +0100 Subject: [PATCH 05/15] get_dns_flags using consts for bits sizes --- src/decoders/dns.rs | 207 ++++++++++++++++++++++++-------------------- 1 file changed, 111 insertions(+), 96 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index 22c0216..a195415 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -10,7 +10,6 @@ use crate::util::{decode_standard, extract_string, extract_string_size}; use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ - bits, bytes::complete::take, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, @@ -49,11 +48,10 @@ pub(crate) fn parse_dns_header(data: &str) -> String { } /// Get the DNS header data -fn get_dns_header(data: &[u8]) -> nom::IResult<&[u8], String> { - let (dns_data, id) = be_u16(data)?; +fn get_dns_header(input: &[u8]) -> nom::IResult<&[u8], String> { + let (input, id) = be_u16(input)?; + let (input, flag_data) = take(size_of::())(input)?; - // todo: why limiting here the parse to 2 bytes ? while get_dns_flags is made to parse 13 ? - let (dns_data, flag_data) = take(size_of::())(dns_data)?; let message_result = get_dns_flags(flag_data); let message = match message_result { @@ -68,7 +66,7 @@ fn get_dns_header(data: &[u8]) -> nom::IResult<&[u8], String> { }; // todo: why parsing here the counts ? while the first 2 bytes are already parsed as dns flags ? - let message_result = parse_counts(dns_data); + let message_result = parse_counts(input); let count_message = match message_result { Ok((_, result)) => result.to_string(), Err(err) => { @@ -87,99 +85,116 @@ fn get_dns_header(data: &[u8]) -> nom::IResult<&[u8], String> { id, flags, message, count_message ); - Ok((dns_data, header_message)) + Ok((input, header_message)) } -/// Parse the DNS bit flags -fn get_dns_flags_could_be(data: &[u8]) -> IResult<&[u8], String> { - dbg!(data); - let ( - input, - ( - query_flag, - opcode, - authoritative_flag, - truncation_flag, - recursion_desired, - recursion_available, - mut response_code, - ), - ) = tuple((be_u8, be_u32, be_u8, be_u8, be_u8, be_u8, be_u32))(data)?; - - const RESERVED_MASK: u32 = 0b00011111111111111111111111111111111; - response_code &= RESERVED_MASK; - - let opcode_message = match opcode { - 0 => "QUERY", - 1 => "IQUERY", - 2 => "STATUS", - 3 => "RESERVED", - 4 => "NOTIFY", - 5 => "UPDATE", - _ => "UNKNOWN OPCODE", - }; - - let response_message = match response_code { - 0 => "No Error", - 1 => "Format Error", - 2 => "Server Failure", - 3 => "NX Domain", - 4 => "Not Implemented", - 5 => "Refused", - 6 => "YX Domain", - 7 => "YX RR Set", - 8 => "NX RR Set", - 9 => "Not Auth", - 10 => "Not Zone", - _ => "Unknown Response Code", - }; - - let message = format!( - "Opcode: {}, -Query Type: {}, -Authoritative Answer Flag: {}, -Truncation Flag: {}, -Recursion Desired: {}, -Recursion Available: {}, -Response Code: {}", - opcode_message, - query_flag, - authoritative_flag, - truncation_flag, - recursion_desired, - recursion_available, - response_message - ); - - Ok(dbg!((input, message))) -} +// /// Parse the DNS bit flags +// fn get_dns_flags_could_be(input: &[u8]) -> nom::IResult<(&[u8], usize), String> { +// // Have to work with bits instead of bytes for the DNS flags +// let ((input, offset), query_flag): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, 0))?; +// let ((input, offset), opcode): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, offset))?; +// let ((input, offset), authoritative_flag): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, offset))?; +// let ((input, offset), truncation_flag): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, offset))?; + +// let ((input, offset), recursion_desired): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, offset))?; +// let ((input, offset), recursion_available): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, offset))?; + +// const RESERVED_SIZE: usize = 3; +// let ((input, offset), _reserved): ((&[u8], usize), u8) = +// bits::complete::take(RESERVED_SIZE)((input, offset))?; +// let ((flag_data, _), response_code): ((&[u8], usize), u8) = +// bits::complete::take(size_of::())((input, offset))?; + +// // let ( +// // input, +// // ( +// // query_flag, +// // opcode, +// // authoritative_flag, +// // truncation_flag, +// // recursion_desired, +// // recursion_available, +// // mut response_code, +// // ), +// // ) = tuple((be_u8, be_u32, be_u8, be_u8, be_u8, be_u8, be_u32))(input)?; + +// // const RESERVED_MASK: u32 = 0b00011111111111111111111111111111111; +// // response_code &= RESERVED_MASK; + +// let opcode_message = match opcode { +// 0 => "QUERY", +// 1 => "IQUERY", +// 2 => "STATUS", +// 3 => "RESERVED", +// 4 => "NOTIFY", +// 5 => "UPDATE", +// _ => "UNKNOWN OPCODE", +// }; + +// let response_message = match response_code { +// 0 => "No Error", +// 1 => "Format Error", +// 2 => "Server Failure", +// 3 => "NX Domain", +// 4 => "Not Implemented", +// 5 => "Refused", +// 6 => "YX Domain", +// 7 => "YX RR Set", +// 8 => "NX RR Set", +// 9 => "Not Auth", +// 10 => "Not Zone", +// _ => "Unknown Response Code", +// }; + +// let message = format!( +// "Opcode: {}, +// Query Type: {}, +// Authoritative Answer Flag: {}, +// Truncation Flag: {}, +// Recursion Desired: {}, +// Recursion Available: {}, +// Response Code: {}", +// opcode_message, +// query_flag, +// authoritative_flag, +// truncation_flag, +// recursion_desired, +// recursion_available, +// response_message +// ); + +// Ok(dbg!(((input, 0), message))) +// } /// Parse the DNS bit flags -fn get_dns_flags(data: &[u8]) -> nom::IResult<(&[u8], usize), String> { - // todo: it's really weird that we can parse something like 13 bytes here - // wihout error even if the input is only 2 bytes long - // see data passed in unit tests to `parse_idflags` for instance - +fn get_dns_flags(input: &[u8]) -> IResult<(&[u8], usize), String> { + // https://en.wikipedia.org/wiki/Domain_Name_System#DNS_message_format + const QR: usize = 1; + const OPCODE: usize = 4; + const AA: usize = 1; + const TC: usize = 1; + const RD: usize = 1; + const RA: usize = 1; + const Z: usize = 3; + const RCODE: usize = 4; + + type RET<'a> = ((&'a [u8], usize), u8); + use nom::bits::complete::take as bits; // Have to work with bits instead of bytes for the DNS flags - let ((flag_data, offset), query_flag): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((data, 0))?; - let ((flag_data, offset), opcode): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((flag_data, offset))?; - let ((flag_data, offset), authoritative_flag): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((flag_data, offset))?; - let ((flag_data, offset), truncation_flag): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((flag_data, offset))?; - - let ((flag_data, offset), recursion_desired): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((flag_data, offset))?; - let ((flag_data, offset), recursion_available): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((flag_data, offset))?; - - let reserved_size: usize = 3; - let ((flag_data, offset), _reserved): ((&[u8], usize), u8) = - bits::complete::take(reserved_size)((flag_data, offset))?; - let ((flag_data, _), response_code): ((&[u8], usize), u8) = - bits::complete::take(size_of::())((flag_data, offset))?; + let ((input, offset), query): RET<'_> = bits(QR)((input, 0))?; + let ((input, offset), opcode): RET<'_> = bits(OPCODE)((input, offset))?; + let ((input, offset), authoritative_flag): RET<'_> = bits(AA)((input, offset))?; + let ((input, offset), truncation_flag): RET<'_> = bits(TC)((input, offset))?; + let ((input, offset), recursion_desired): RET<'_> = bits(RD)((input, offset))?; + let ((input, offset), recursion_available): RET<'_> = bits(RA)((input, offset))?; + let ((input, offset), _reserved): RET<'_> = bits(Z)((input, offset))?; + let ((input, _), response_code): RET<'_> = bits(RCODE)((input, offset))?; let opcode_message = match opcode { 0 => "QUERY", @@ -215,7 +230,7 @@ fn get_dns_flags(data: &[u8]) -> nom::IResult<(&[u8], usize), String> { Recursion Available: {}, Response Code: {}", opcode_message, - query_flag, + query, authoritative_flag, truncation_flag, recursion_desired, @@ -223,7 +238,7 @@ fn get_dns_flags(data: &[u8]) -> nom::IResult<(&[u8], usize), String> { response_message ); - Ok(((flag_data, 0), message)) + Ok(((input, 0), message)) } /// Base64 decode the domain name. This is normally masked, but may be shown if private data is enabled From e0788266d36db01b8ad8a62e0988a3ade06fa414 Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 12:37:18 +0100 Subject: [PATCH 06/15] clean --- src/decoders/dns.rs | 85 +-------------------------------------------- 1 file changed, 1 insertion(+), 84 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index a195415..51549bc 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -48,7 +48,7 @@ pub(crate) fn parse_dns_header(data: &str) -> String { } /// Get the DNS header data -fn get_dns_header(input: &[u8]) -> nom::IResult<&[u8], String> { +fn get_dns_header(input: &[u8]) -> IResult<&[u8], String> { let (input, id) = be_u16(input)?; let (input, flag_data) = take(size_of::())(input)?; @@ -88,89 +88,6 @@ fn get_dns_header(input: &[u8]) -> nom::IResult<&[u8], String> { Ok((input, header_message)) } -// /// Parse the DNS bit flags -// fn get_dns_flags_could_be(input: &[u8]) -> nom::IResult<(&[u8], usize), String> { -// // Have to work with bits instead of bytes for the DNS flags -// let ((input, offset), query_flag): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, 0))?; -// let ((input, offset), opcode): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, offset))?; -// let ((input, offset), authoritative_flag): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, offset))?; -// let ((input, offset), truncation_flag): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, offset))?; - -// let ((input, offset), recursion_desired): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, offset))?; -// let ((input, offset), recursion_available): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, offset))?; - -// const RESERVED_SIZE: usize = 3; -// let ((input, offset), _reserved): ((&[u8], usize), u8) = -// bits::complete::take(RESERVED_SIZE)((input, offset))?; -// let ((flag_data, _), response_code): ((&[u8], usize), u8) = -// bits::complete::take(size_of::())((input, offset))?; - -// // let ( -// // input, -// // ( -// // query_flag, -// // opcode, -// // authoritative_flag, -// // truncation_flag, -// // recursion_desired, -// // recursion_available, -// // mut response_code, -// // ), -// // ) = tuple((be_u8, be_u32, be_u8, be_u8, be_u8, be_u8, be_u32))(input)?; - -// // const RESERVED_MASK: u32 = 0b00011111111111111111111111111111111; -// // response_code &= RESERVED_MASK; - -// let opcode_message = match opcode { -// 0 => "QUERY", -// 1 => "IQUERY", -// 2 => "STATUS", -// 3 => "RESERVED", -// 4 => "NOTIFY", -// 5 => "UPDATE", -// _ => "UNKNOWN OPCODE", -// }; - -// let response_message = match response_code { -// 0 => "No Error", -// 1 => "Format Error", -// 2 => "Server Failure", -// 3 => "NX Domain", -// 4 => "Not Implemented", -// 5 => "Refused", -// 6 => "YX Domain", -// 7 => "YX RR Set", -// 8 => "NX RR Set", -// 9 => "Not Auth", -// 10 => "Not Zone", -// _ => "Unknown Response Code", -// }; - -// let message = format!( -// "Opcode: {}, -// Query Type: {}, -// Authoritative Answer Flag: {}, -// Truncation Flag: {}, -// Recursion Desired: {}, -// Recursion Available: {}, -// Response Code: {}", -// opcode_message, -// query_flag, -// authoritative_flag, -// truncation_flag, -// recursion_desired, -// recursion_available, -// response_message -// ); - -// Ok(dbg!(((input, 0), message))) -// } /// Parse the DNS bit flags fn get_dns_flags(input: &[u8]) -> IResult<(&[u8], usize), String> { From 878e9232e2f0259837f57fe105ba16827855806c Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 22:42:43 +0100 Subject: [PATCH 07/15] WIP --- src/decoders/decoder.rs | 83 ++++++----- src/decoders/dns.rs | 298 +++++++++++++++++----------------------- src/decoders/mod.rs | 36 +++++ src/error.rs | 14 +- src/util.rs | 8 +- 5 files changed, 224 insertions(+), 215 deletions(-) diff --git a/src/decoders/decoder.rs b/src/decoders/decoder.rs index 6e85df5..46a5f2c 100644 --- a/src/decoders/decoder.rs +++ b/src/decoders/decoder.rs @@ -23,6 +23,7 @@ use crate::{ opendirectory::{errors, member_details, member_id_type, sid_details}, time::parse_time, uuid::parse_uuid, + DecoderError, }, }; @@ -53,79 +54,93 @@ pub(crate) fn check_objects( } // Check if log value contains one the supported decoders - let message_value = if format_string.contains("BOOL") { - uppercase_bool(&message_values[index].message_strings) + let message_value: Result> = if format_string.contains("BOOL") { + Ok(uppercase_bool(&message_values[index].message_strings)) } else if format_string.contains("bool") { - lowercase_bool(&message_values[index].message_strings) + Ok(lowercase_bool(&message_values[index].message_strings)) } else if format_string.contains("uuid_t") { - parse_uuid(&message_values[index].message_strings) + Ok(parse_uuid(&message_values[index].message_strings)) } else if format_string.contains("darwin.errno") { - errno_codes(&message_values[index].message_strings) + Ok(errno_codes(&message_values[index].message_strings)) } else if format_string.contains("darwin.mode") { - permission(&message_values[index].message_strings) + Ok(permission(&message_values[index].message_strings)) } else if format_string.contains("odtypes:ODError") { - errors(&message_values[index].message_strings) + Ok(errors(&message_values[index].message_strings)) } else if format_string.contains("odtypes:mbridtype") { - member_id_type(&message_values[index].message_strings) + Ok(member_id_type(&message_values[index].message_strings)) } else if format_string.contains("odtypes:mbr_details") { - member_details(&message_values[index].message_strings) + Ok(member_details(&message_values[index].message_strings)) } else if format_string.contains("odtypes:nt_sid_t") { - sid_details(&message_values[index].message_strings) + Ok(sid_details(&message_values[index].message_strings)) } else if format_string.contains("location:CLClientAuthorizationStatus") { - client_authorization_status(&message_values[index].message_strings) + Ok(client_authorization_status( + &message_values[index].message_strings, + )) } else if format_string.contains("location:CLDaemonStatus_Type::Reachability") { - daemon_status_type(&message_values[index].message_strings) + Ok(daemon_status_type(&message_values[index].message_strings)) } else if format_string.contains("location:CLSubHarvesterIdentifier") { - subharvester_identifier(&message_values[index].message_strings) + Ok(subharvester_identifier( + &message_values[index].message_strings, + )) } else if format_string.contains("location:SqliteResult") { - sqlite(&message_values[index].message_strings) + Ok(sqlite(&message_values[index].message_strings)) } else if format_string.contains("location:_CLClientManagerStateTrackerState") { - client_manager_state_tracker_state(&message_values[index].message_strings) + Ok(client_manager_state_tracker_state( + &message_values[index].message_strings, + )) } else if format_string.contains("location:_CLLocationManagerStateTrackerState") { - location_manager_state_tracker_state(&message_values[index].message_strings) + Ok(location_manager_state_tracker_state( + &message_values[index].message_strings, + )) } else if format_string.contains("network:in6_addr") { - ipv_six(&message_values[index].message_strings) + Ok(ipv_six(&message_values[index].message_strings)) } else if format_string.contains("network:in_addr") { - ipv_four(&message_values[index].message_strings) + Ok(ipv_four(&message_values[index].message_strings)) } else if format_string.contains("network:sockaddr") { - sockaddr(&message_values[index].message_strings) + Ok(sockaddr(&message_values[index].message_strings)) } else if format_string.contains("time_t") { - parse_time(&message_values[index].message_strings) + Ok(parse_time(&message_values[index].message_strings)) } else if format_string.contains("mdns:dnshdr") { parse_dns_header(&message_values[index].message_strings) } else if format_string.contains("mdns:rd.svcb") { get_service_binding(&message_values[index].message_strings) } else if format_string.contains("location:IOMessage") { - io_message(&message_values[index].message_strings) + Ok(io_message(&message_values[index].message_strings)) } else if format_string.contains("mdnsresponder:domain_name") { get_domain_name(&message_values[index].message_strings) } else if format_string.contains("mdnsresponder:mac_addr") { - get_dns_mac_addr(&message_values[index].message_strings) + Ok(get_dns_mac_addr(&message_values[index].message_strings)) } else if format_string.contains("mdnsresponder:ip_addr") { - dns_ip_addr(&message_values[index].message_strings) + Ok(dns_ip_addr(&message_values[index].message_strings)) } else if format_string.contains("mdns:addrmv") { - dns_addrmv(&message_values[index].message_strings) + Ok(dns_addrmv(&message_values[index].message_strings)) } else if format_string.contains("mdns:rrtype") { - dns_records(&message_values[index].message_strings) + Ok(dns_records(&message_values[index].message_strings)) } else if format_string.contains("mdns:nreason") { - dns_reason(&message_values[index].message_strings) + Ok(dns_reason(&message_values[index].message_strings)) } else if format_string.contains("mdns:protocol") { - dns_protocol(&message_values[index].message_strings) + Ok(dns_protocol(&message_values[index].message_strings)) } else if format_string.contains("mdns:dns.idflags") { - dns_idflags(&message_values[index].message_strings) + Ok(dns_idflags(&message_values[index].message_strings)) } else if format_string.contains("mdns:dns.counts") { - dns_counts(&message_values[index].message_strings) + Ok(dns_counts(&message_values[index].message_strings)) } else if format_string.contains("mdns:yesno") { - dns_yes_no(&message_values[index].message_strings) + Ok(dns_yes_no(&message_values[index].message_strings)) } else if format_string.contains("mdns:acceptable") { - dns_acceptable(&message_values[index].message_strings) + Ok(dns_acceptable(&message_values[index].message_strings)) } else if format_string.contains("mdns:gaiopts") { - dns_getaddrinfo_opts(&message_values[index].message_strings) + Ok(dns_getaddrinfo_opts(&message_values[index].message_strings)) } else { - String::new() + Ok(String::new()) }; - message_value + match message_value { + Ok(value) => value, + Err(e) => { + log::error!("[macos-unifiedlogs] Failed to parse DNS header counts. Error: {e:?}"); + e.to_string() + } + } } #[cfg(test)] diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index 51549bc..e32d18d 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -5,15 +5,15 @@ // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and limitations under the License. -use super::network::{get_ip_four, get_ip_six}; +use super::{ + network::{get_ip_four, get_ip_six}, + DecoderError, +}; use crate::util::{decode_standard, extract_string, extract_string_size}; use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ - bytes::complete::take, - number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, - sequence::tuple, - IResult, + bytes::complete::take, combinator::iterator, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, IResult }; use std::{ mem::size_of, @@ -21,65 +21,49 @@ use std::{ }; /// Parse the DNS header -pub(crate) fn parse_dns_header(data: &str) -> String { - let decoded_data_result = decode_standard(data); - let decoded_data = match decoded_data_result { - Ok(result) => result, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to base64 decode dns header data {}, error: {:?}", - data, err - ); - return String::from("Failed to base64 decode DNS header details"); - } - }; +pub(crate) fn parse_dns_header(data: &str) -> Result> { + let decoded_data = decode_standard(data).map_err(|_| DecoderError::Parse { + input: data.as_bytes(), + parser_name: "dns header", + message: "Failed to base64 decode DNS header details", + })?; + + let (_, message) = get_dns_header(&decoded_data).map_err(|_| DecoderError::Parse { + input: data.as_bytes(), + parser_name: "dns header", + message: "Failed to parse DNS header details", + })?; + + Ok(message) +} - let message_result = get_dns_header(&decoded_data); - match message_result { - Ok((_, result)) => result, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to get dns header structure: {:?}", - err - ); - format!("Failed to get dns header: {}", data) - } +fn remove_err_offset( + error_with_offset: nom::Err>, +) -> nom::Err> { + use nom::Err; + match error_with_offset { + Err::Error(e) => Err::Error(nom::error::Error { + input: e.input.0, + code: e.code, + }), + Err::Failure(e) => Err::Failure(nom::error::Error { + input: e.input.0, + code: e.code, + }), + Err::Incomplete(e) => Err::Incomplete(e), } } /// Get the DNS header data fn get_dns_header(input: &[u8]) -> IResult<&[u8], String> { let (input, id) = be_u16(input)?; - let (input, flag_data) = take(size_of::())(input)?; - - let message_result = get_dns_flags(flag_data); - - let message = match message_result { - Ok(result) => result.1, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to parse DNS header flags. Error: {:?}", - err - ); - String::from("Failed to parse DNS header") - } - }; - - // todo: why parsing here the counts ? while the first 2 bytes are already parsed as dns flags ? - let message_result = parse_counts(input); - let count_message = match message_result { - Ok((_, result)) => result.to_string(), - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to parse DNS header counts. Error: {:?}", - err - ); - String::from("Failed to parse DNS header counts") - } - }; + let (input, flag_data) = take(size_of::())(input)?; + let ((_, _), message) = get_dns_flags(flag_data).map_err(remove_err_offset)?; let (_, flags) = be_u16(flag_data)?; + let (input, count_message) = parse_counts(input)?; + let header_message = format!( "Query ID: {:#X?}, Flags: {:#X?} {}, {}", id, flags, message, count_message @@ -88,7 +72,6 @@ fn get_dns_header(input: &[u8]) -> IResult<&[u8], String> { Ok((input, header_message)) } - /// Parse the DNS bit flags fn get_dns_flags(input: &[u8]) -> IResult<(&[u8], usize), String> { // https://en.wikipedia.org/wiki/Domain_Name_System#DNS_message_format @@ -159,93 +142,65 @@ fn get_dns_flags(input: &[u8]) -> IResult<(&[u8], usize), String> { } /// Base64 decode the domain name. This is normally masked, but may be shown if private data is enabled -pub(crate) fn get_domain_name(data: &str) -> String { - let decoded_data_result = decode_standard(data); - let decoded_data = match decoded_data_result { - Ok(result) => result, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to base64 decode dns name data {}, error: {:?}", - data, err - ); - return String::from("Failed to base64 decode DNS name details"); - } - }; - - let domain_results = extract_string(&decoded_data); - match domain_results { - Ok((_, results)) => { - let mut clean_domain = String::new(); - let non_domain_chars: Vec = vec!['\n', '\t', '\r']; - for unicode in results.chars() { - // skip non-domain characters and replace with '.' - if non_domain_chars.contains(&unicode) || format!("{:?}", unicode).contains("\\u{") - { - clean_domain.push('.'); - continue; - } - clean_domain.push_str(&String::from(unicode)); - } - clean_domain - } - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to extract domain name from logs: {:?}", - err - ); - String::from("Failed to extract domain name from logs") +pub(crate) fn get_domain_name(input: &str) -> Result> { + let decoded_data = decode_standard(input).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns domain name", + message: "Failed to base64 decode DNS name details", + })?; + + let (_, results) = extract_string(&decoded_data).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns domain name", + message: "Failed to extract domain name from logs", + })?; + + let mut clean_domain = String::new(); + let non_domain_chars = ['\n', '\t', '\r']; + for unicode in results.chars() { + // skip non-domain characters and replace with '.' + if non_domain_chars.contains(&unicode) || format!("{:?}", unicode).contains("\\u{") { + clean_domain.push('.'); + continue; } + clean_domain.push_str(&String::from(unicode)); } + Ok(clean_domain) } /// Parse DNS Service Binding record type -pub(crate) fn get_service_binding(data: &str) -> String { - let decoded_data_result = decode_standard(data); - let decoded_data = match decoded_data_result { - Ok(result) => result, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to base64 decode dns svcb data {}, error: {:?}", - data, err - ); - return String::from("Failed to base64 decode DNS svcb details"); - } - }; - - let message_results = parse_svcb(&decoded_data); - match message_results { - Ok((_, results)) => results, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to parse DNS Service Binding data: {:?}", - err - ); - String::from("Failed to parse DNS Service Binding data") - } - } +pub(crate) fn get_service_binding(input: &str) -> Result> { + let decoded_data = decode_standard(input).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns service binding", + message: "Failed to base64 decode DNS svcb details", + })?; + + let (_, result) = parse_svcb(&decoded_data).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns service binding", + message: "Failed to parse DNS Service Binding data", + })?; + + Ok(result) } /// Parse DNS SVC Binding record -fn parse_svcb(data: &[u8]) -> nom::IResult<&[u8], String> { +fn parse_svcb(input: &[u8]) -> nom::IResult<&[u8], String> { // Format/documentation found at https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/00/?include_text=1 - let (dns_data, id_data) = take(size_of::())(data)?; - let (dns_data, unknown_type_data) = take(size_of::())(dns_data)?; + let (input, id) = be_u16(input)?; + let (input, unknown_type) = be_u32(input)?; - let (_, unknown_type) = be_u32(unknown_type_data)?; - let dns_over_https = 8388608; // 0x800000 - if unknown_type == dns_over_https { - let (dns_data, url_entry_size) = take(size_of::())(dns_data)?; - let (_, url_size) = be_u8(url_entry_size)?; - return extract_string_size(dns_data, url_size.into()); + const DNS_OVER_HTTPS: u32 = 0x800000; + if unknown_type == DNS_OVER_HTTPS { + let (input, url_size) = be_u8(input)?; + return extract_string_size(input, url_size.into()); } // ALPN = Application Layer Protocol Negotation - let (dns_data, alpn_total_size) = take(size_of::())(dns_data)?; - - let (_, id) = be_u16(id_data)?; - let (_, alpn_size) = be_u8(alpn_total_size)?; + let (input, alpn_size) = be_u8(input)?; - let (dns_data, alpn_data) = take(alpn_size)(dns_data)?; + let (dns_data, alpn_data) = take(alpn_size)(input)?; let (_, alpn_message) = parse_svcb_alpn(alpn_data)?; let (dns_data, ip_message) = parse_svcb_ip(dns_data)?; @@ -255,59 +210,62 @@ fn parse_svcb(data: &[u8]) -> nom::IResult<&[u8], String> { } /// Parse the Application Layer Protocol Negotation -fn parse_svcb_alpn(dns_data: &[u8]) -> nom::IResult<&[u8], String> { - let mut data = dns_data; +fn parse_svcb_alpn(mut input: &[u8]) -> nom::IResult<&[u8], String> { let mut message = String::from("alpn="); - while !data.is_empty() { - let (alpn_data, entry_size) = take(size_of::())(data)?; - let (_, entry) = be_u8(entry_size)?; - let (alpn_data, alpn_entry) = take(entry)(alpn_data)?; - data = alpn_data; + while !input.is_empty() { + let (i, alpn_entry_size) = be_u8(input)?; + let (i, alpn_entry) = take(alpn_entry_size)(i)?; let (_, alpn_name) = extract_string(alpn_entry)?; - message = format!("{}{},", message, alpn_name); + input = i; + message.push_str(&alpn_name); + message.push(',') } - Ok((data, message)) + Ok((input, message)) } /// Parse the IPs -fn parse_svcb_ip(data: &[u8]) -> nom::IResult<&[u8], String> { - let mut dns_data = data; +fn parse_svcb_ip(mut input: &[u8]) -> nom::IResult<&[u8], String> { + fn ipv4_parser(input: &[u8]) -> nom::IResult<&[u8], Ipv4Addr> { + let (i, ip) = be_u32(input)?; + Ok((i, Ipv4Addr::from(ip))) + } + + fn ipv6_parser(input: &[u8]) -> nom::IResult<&[u8], Ipv6Addr> { + let (i, ip) = be_u128(input)?; + Ok((i, Ipv6Addr::from(ip))) + } + + const IPV4: u16 = 4; + const IPV6: u16 = 6; + let mut ipv4_hint = String::from("ipv4 hint:"); let mut ipv6_hint = String::from("ipv6 hint:"); // IPs can either be IPv4 or/and IPv6 - while !dns_data.is_empty() { - let (remaining_dns_data, ip_type) = take(size_of::())(dns_data)?; - let (_, ip_version) = be_u16(ip_type)?; - - let (remaining_dns_data, total_ip_size) = take(size_of::())(remaining_dns_data)?; - let (_, ip_size) = be_u16(total_ip_size)?; - - let (remaining_dns_data, mut ip_data) = take(ip_size)(remaining_dns_data)?; - dns_data = remaining_dns_data; - let ipv4 = 4; - let ipv6 = 6; - // There can be multiple IPs - while !ip_data.is_empty() { - if ip_version == ipv4 { - let (remaining_ip_data, ipv4_data) = take(size_of::())(ip_data)?; - ip_data = remaining_ip_data; - - let (_, ip) = be_u32(ipv4_data)?; - let ip_addr = Ipv4Addr::from(ip); - ipv4_hint = format!("{}{},", ipv4_hint, ip_addr); - } else if ip_version == ipv6 { - let (remaining_ip_data, ipv6_data) = take(size_of::())(ip_data)?; - ip_data = remaining_ip_data; - - let (_, ip) = be_u128(ipv6_data)?; - let ip_addr = Ipv6Addr::from(ip); - ipv6_hint = format!("{}{},", ipv6_hint, ip_addr); + while !input.is_empty() { + let (i, ip_version) = be_u16(input)?; + let (i, ip_size) = be_u16(i)?; + + let (i, ip_data) = take(ip_size)(i)?; + input = i; + + if ip_version == IPV4 { + let mut iter = iterator(ip_data, ipv4_parser); + for ip in iter.into_iter() { + ipv4_hint = format!("{}{},", ipv4_hint, ip); + } + iter.finish()?; + } else if ip_version == IPV6 { + let mut iter = iterator(ip_data, ipv6_parser); + for ip in iter.into_iter() { + ipv6_hint = format!("{}{},", ipv6_hint, ip); } + iter.finish()?; } } + let message = format!("{} {}", ipv4_hint, ipv6_hint); - Ok((dns_data, message)) + Ok((input, message)) } /// Get the MAC Address from the log data @@ -667,7 +625,7 @@ mod tests { #[test] fn test_parse_dns_header() { let test_data = "uXMBAAABAAAAAAAA"; - let result = parse_dns_header(test_data); + let result = parse_dns_header(test_data).unwrap(); assert_eq!(result, "Query ID: 0xB973, Flags: 0x100 Opcode: QUERY, \n Query Type: 0,\n Authoritative Answer Flag: 0, \n Truncation Flag: 0, \n Recursion Desired: 1, \n Recursion Available: 0, \n Response Code: No Error, Question Count: 1, Answer Record Count: 0, Authority Record Count: 0, Additional Record Count: 0"); } @@ -688,7 +646,7 @@ mod tests { #[test] fn test_get_domain_name() { let test_data = "AzE0NAMxMDEDMTY4AzE5Mgdpbi1hZGRyBGFycGEA"; - let result = get_domain_name(test_data); + let result = get_domain_name(test_data).unwrap(); assert_eq!(result, ".144.101.168.192.in-addr.arpa"); } @@ -696,7 +654,7 @@ mod tests { fn test_get_service_binding() { let test_data = "AAEAAAEAAwJoMgAEAAhoEJRAaBCVQAAGACAmBkcAAAAAAAAAAABoEJRAJgZHAAAAAAAAAAAAaBCVQA=="; - let result = get_service_binding(test_data); + let result = get_service_binding(test_data).unwrap(); assert_eq!(result, "rdata: 1 . alpn=h2, ipv4 hint:104.16.148.64,104.16.149.64, ipv6 hint:2606:4700::6810:9440,2606:4700::6810:9540,"); } diff --git a/src/decoders/mod.rs b/src/decoders/mod.rs index 32c1a90..1f85a3b 100644 --- a/src/decoders/mod.rs +++ b/src/decoders/mod.rs @@ -14,3 +14,39 @@ mod network; mod opendirectory; mod time; mod uuid; + +pub enum DecoderError<'a> { + Parse { + input: &'a [u8], + parser_name: &'a str, + message: &'a str, + }, +} + +impl<'a> std::error::Error for DecoderError<'a> {} + +impl<'a> std::fmt::Display for DecoderError<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Parse { + message, + .. + } => write!(f, "{message}"), + } + } +} + +impl<'a> std::fmt::Debug for DecoderError<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Parse { + parser_name, + message, + input, + } => write!( + f, + "Failed at {parser_name} parser, data {input:?}: {message}" + ), + } + } +} diff --git a/src/error.rs b/src/error.rs index 587f8be..5b0e8bd 100755 --- a/src/error.rs +++ b/src/error.rs @@ -86,13 +86,13 @@ impl std::error::Error for ParserError {} impl fmt::Display for ParserError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - ParserError::Path => write!(f, "Failed to open file path"), - ParserError::Dir => write!(f, "Failed to open directory path"), - ParserError::Tracev3Parse => write!(f, "Failed to parse tracev3 file"), - ParserError::Read => write!(f, "Failed to read file"), - ParserError::Timesync => write!(f, "Failed to parse timesync file"), - ParserError::Dsc => write!(f, "Failed to parse dsc file"), - ParserError::UUIDText => write!(f, "Failedto parse UUIDtext file"), + Self::Path => write!(f, "Failed to open file path"), + Self::Dir => write!(f, "Failed to open directory path"), + Self::Tracev3Parse => write!(f, "Failed to parse tracev3 file"), + Self::Read => write!(f, "Failed to read file"), + Self::Timesync => write!(f, "Failed to parse timesync file"), + Self::Dsc => write!(f, "Failed to parse dsc file"), + Self::UUIDText => write!(f, "Failedto parse UUIDtext file"), } } } diff --git a/src/util.rs b/src/util.rs index 59fb846..e34747f 100755 --- a/src/util.rs +++ b/src/util.rs @@ -32,8 +32,8 @@ pub(crate) fn padding_size_four(data: u64) -> u64 { /// Extract a size based on provided string size from Firehose string item entries pub(crate) fn extract_string_size(data: &[u8], message_size: u64) -> nom::IResult<&[u8], String> { - let null_string = 0; - if message_size == null_string { + const NULL_STRING: u64 = 0; + if message_size == NULL_STRING { return Ok((data, String::from("(null)"))); } @@ -69,11 +69,11 @@ pub(crate) fn extract_string(data: &[u8]) -> nom::IResult<&[u8], String> { let last_value = data.last(); match last_value { Some(value) => { - let has_end_of_string: u8 = 0; + const NULL_BYTE: u8 = 0; // If message data does not end with end of string character (0) // just grab everything and convert what we have to string - if value != &has_end_of_string { + if value != &NULL_BYTE { let (input, path) = take(data.len())(data)?; let path_string = from_utf8(path); match path_string { From 1766a52d1df5f0ee417fad8c567692305e85dc50 Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 23:10:17 +0100 Subject: [PATCH 08/15] dns seems ok --- src/decoders/decoder.rs | 4 +- src/decoders/dns.rs | 129 ++++++++++++++++++---------------------- src/decoders/network.rs | 16 ++--- 3 files changed, 66 insertions(+), 83 deletions(-) diff --git a/src/decoders/decoder.rs b/src/decoders/decoder.rs index 46a5f2c..63edd59 100644 --- a/src/decoders/decoder.rs +++ b/src/decoders/decoder.rs @@ -109,9 +109,9 @@ pub(crate) fn check_objects( } else if format_string.contains("mdnsresponder:domain_name") { get_domain_name(&message_values[index].message_strings) } else if format_string.contains("mdnsresponder:mac_addr") { - Ok(get_dns_mac_addr(&message_values[index].message_strings)) + get_dns_mac_addr(&message_values[index].message_strings) } else if format_string.contains("mdnsresponder:ip_addr") { - Ok(dns_ip_addr(&message_values[index].message_strings)) + dns_ip_addr(&message_values[index].message_strings) } else if format_string.contains("mdns:addrmv") { Ok(dns_addrmv(&message_values[index].message_strings)) } else if format_string.contains("mdns:rrtype") { diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index e32d18d..37c7999 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -13,9 +13,15 @@ use crate::util::{decode_standard, extract_string, extract_string_size}; use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ - bytes::complete::take, combinator::iterator, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, IResult + bytes::complete::take, + combinator::{fail, iterator}, + multi::fold_many0, + number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, + sequence::tuple, + IResult, }; use std::{ + fmt::Write, mem::size_of, net::{Ipv4Addr, Ipv6Addr}, }; @@ -248,10 +254,10 @@ fn parse_svcb_ip(mut input: &[u8]) -> nom::IResult<&[u8], String> { let (i, ip_data) = take(ip_size)(i)?; input = i; - + if ip_version == IPV4 { let mut iter = iterator(ip_data, ipv4_parser); - for ip in iter.into_iter() { + for ip in iter.into_iter() { ipv4_hint = format!("{}{},", ipv4_hint, ip); } iter.finish()?; @@ -269,86 +275,67 @@ fn parse_svcb_ip(mut input: &[u8]) -> nom::IResult<&[u8], String> { } /// Get the MAC Address from the log data -pub(crate) fn get_dns_mac_addr(data: &str) -> String { - let decoded_data_result = decode_standard(data); - let decoded_data = match decoded_data_result { - Ok(result) => result, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to base64 decode dns mac address data {}, error: {:?}", - data, err - ); - return String::from("Failed to base64 decode DNS mac address details"); - } - }; +pub(crate) fn get_dns_mac_addr(input: &str) -> Result> { + let decoded_data = decode_standard(input).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns mac address", + message: "Failed to base64 decode DNS mac address details", + })?; - let message_results = parse_mac_addr(&decoded_data); - match message_results { - Ok((_, results)) => results, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to parse DNS mac address data: {:?}", - err - ); - String::from("Failed to parse DNS mac address data") - } - } + let (_, message_results) = parse_mac_addr(&decoded_data).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns mac address", + message: "Failed to parse DNS mac address data", + })?; + + Ok(message_results) } /// Parse the MAC Address -fn parse_mac_addr(dns_data: &[u8]) -> nom::IResult<&[u8], String> { - let mut mac_data: Vec = Vec::new(); - let mut data = dns_data; - - while !data.is_empty() { - let (remaining_data, addr) = take(size_of::())(data)?; - data = remaining_data; - - let (_, mac_addr) = be_u8(addr)?; - mac_data.push(format!("{:02X?}", mac_addr)); - } - Ok((data, mac_data.join(":"))) +fn parse_mac_addr(input: &[u8]) -> nom::IResult<&[u8], String> { + let (input, mac_string) = fold_many0( + be_u8, + || String::with_capacity(input.len() * 3), // This buffer will not have to reallocate/grow + |mut acc, item| { + if !acc.is_empty() { + acc.push(':'); + } + write!(&mut acc, "{:02X?}", item).ok(); // ignore errors on write in String + acc + }, + )(input)?; + Ok((input, mac_string)) } /// Get IP Address info from log data -pub(crate) fn dns_ip_addr(data: &str) -> String { - let decoded_data_result = decode_standard(data); - let decoded_data = match decoded_data_result { - Ok(result) => result, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to base64 decode dns ip address data {}, error: {:?}", - data, err - ); - return String::from("Failed to base64 decode DNS ip address details"); - } - }; - let message_results = parse_dns_ip_addr(&decoded_data); - match message_results { - Ok((_, results)) => results, - Err(err) => { - error!( - "[macos-unifiedlogs] Failed to parse DNS ip address data: {:?}", - err - ); - String::from("Failed to parse DNS mac address data") - } - } +pub(crate) fn dns_ip_addr(input: &str) -> Result> { + let decoded_data = decode_standard(input).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns ip address", + message: "Failed to base64 decode DNS ip address details", + })?; + + let (_, results) = parse_dns_ip_addr(&decoded_data).map_err(|_| DecoderError::Parse { + input: input.as_bytes(), + parser_name: "dns ip address", + message: "Failed to parse DNS ip address data", + })?; + + Ok(results) } /// Parse IP Address data fn parse_dns_ip_addr(data: &[u8]) -> nom::IResult<&[u8], String> { - let (data, ip_type) = take(size_of::())(data)?; - let (_, ip) = le_u32(ip_type)?; - let ipv4 = 4; - let ipv6 = 6; - if ip == ipv4 { + let (data, ip_version) = le_u32(data)?; + const IPV4: u32 = 4; + const IPV6: u32 = 6; + if ip_version == IPV4 { return get_ip_four(data); - } else if ip == ipv6 { + } else if ip_version == IPV6 { return get_ip_six(data); + } else { + fail(data) } - warn!("[macos-unifiedlogs] Unknown DNS IP Addr type: {}", ip); - Ok((data, format!("Unknown DNS IP Addr type: {}", ip))) } /// Translate DNS add/rmv log values @@ -691,7 +678,7 @@ mod tests { fn test_get_dns_mac_addr() { let test_data = "AAAAAAAA"; - let result = get_dns_mac_addr(test_data); + let result = get_dns_mac_addr(test_data).unwrap(); assert_eq!(result, "00:00:00:00:00:00"); } @@ -707,7 +694,7 @@ mod tests { fn test_dns_ip_addr() { let test_data = "BAAAAMCoZZAAAAAAAAAAAAAAAAA="; - let result = dns_ip_addr(test_data); + let result = dns_ip_addr(test_data).unwrap(); assert_eq!(result, "192.168.101.144"); } diff --git a/src/decoders/network.rs b/src/decoders/network.rs index 88b2fbe..8359b98 100644 --- a/src/decoders/network.rs +++ b/src/decoders/network.rs @@ -150,21 +150,17 @@ fn get_sockaddr_data(data: &[u8]) -> nom::IResult<&[u8], String> { } /// Get the IPv4 data -pub(crate) fn get_ip_four(data: &[u8]) -> nom::IResult<&[u8], String> { - let (ip_data, ip_addr_data) = take(size_of::())(data)?; - let (_, ip) = be_u32(ip_addr_data)?; +pub(crate) fn get_ip_four(input: &[u8]) -> nom::IResult<&[u8], String> { + let (input, ip) = be_u32(input)?; let ip = Ipv4Addr::from(ip); - - Ok((ip_data, ip.to_string())) + Ok((input, ip.to_string())) } /// Get the IPv6 data -pub(crate) fn get_ip_six(data: &[u8]) -> nom::IResult<&[u8], String> { - let (ip_data, ip_addr_data) = take(size_of::())(data)?; - let (_, ip) = be_u128(ip_addr_data)?; +pub(crate) fn get_ip_six(input: &[u8]) -> nom::IResult<&[u8], String> { + let (input, ip) = be_u128(input)?; let ip = Ipv6Addr::from(ip); - - Ok((ip_data, ip.to_string())) + Ok((input, ip.to_string())) } #[cfg(test)] From 75a3c766a1cfd81ad6c7edc5b3f09c61de3df0e6 Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 23:11:42 +0100 Subject: [PATCH 09/15] fmt --- src/decoders/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/decoders/mod.rs b/src/decoders/mod.rs index 1f85a3b..e89e9b9 100644 --- a/src/decoders/mod.rs +++ b/src/decoders/mod.rs @@ -28,10 +28,7 @@ impl<'a> std::error::Error for DecoderError<'a> {} impl<'a> std::fmt::Display for DecoderError<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Parse { - message, - .. - } => write!(f, "{message}"), + Self::Parse { message, .. } => write!(f, "{message}"), } } } From 03b31e16d3a583e109350cd2e8c9519c6047d1e0 Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 23:47:27 +0100 Subject: [PATCH 10/15] map_parser --- src/decoders/dns.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index 37c7999..aa8ecd3 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -14,7 +14,7 @@ use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ bytes::complete::take, - combinator::{fail, iterator}, + combinator::{fail, iterator, map_parser}, multi::fold_many0, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, @@ -205,14 +205,11 @@ fn parse_svcb(input: &[u8]) -> nom::IResult<&[u8], String> { // ALPN = Application Layer Protocol Negotation let (input, alpn_size) = be_u8(input)?; - - let (dns_data, alpn_data) = take(alpn_size)(input)?; - let (_, alpn_message) = parse_svcb_alpn(alpn_data)?; - - let (dns_data, ip_message) = parse_svcb_ip(dns_data)?; + let (input, alpn_message) = map_parser(take(alpn_size), parse_svcb_alpn)(input)?; + let (input, ip_message) = parse_svcb_ip(input)?; let message = format!("rdata: {} . {} {}", id, alpn_message, ip_message); - Ok((dns_data, message)) + Ok((input, message)) } /// Parse the Application Layer Protocol Negotation From ba57606fdbf68fc166b85be51a02d391888bd10b Mon Sep 17 00:00:00 2001 From: jrx Date: Fri, 29 Nov 2024 23:55:26 +0100 Subject: [PATCH 11/15] avoid string reallocation --- src/decoders/dns.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index aa8ecd3..35d70f6 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -255,13 +255,13 @@ fn parse_svcb_ip(mut input: &[u8]) -> nom::IResult<&[u8], String> { if ip_version == IPV4 { let mut iter = iterator(ip_data, ipv4_parser); for ip in iter.into_iter() { - ipv4_hint = format!("{}{},", ipv4_hint, ip); + write!(ipv4_hint, "{},", ip).ok(); // ignore errors on write in String } iter.finish()?; } else if ip_version == IPV6 { let mut iter = iterator(ip_data, ipv6_parser); for ip in iter.into_iter() { - ipv6_hint = format!("{}{},", ipv6_hint, ip); + write!(ipv6_hint, "{},", ip).ok(); // ignore errors on write in String } iter.finish()?; } From eefb469d65c6b274fb200490f984300fb34d6a2f Mon Sep 17 00:00:00 2001 From: jrx Date: Tue, 3 Dec 2024 18:12:00 +0100 Subject: [PATCH 12/15] formatting --- src/decoders/dns.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index 155b5a4..b275445 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -14,8 +14,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ bytes::complete::take, - combinator::{fail, iterator, map, map_parser, verify}, - multi::{fold_many0, many0}, + combinator::{fail, iterator, map_parser, verify}, + multi::fold_many0, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, IResult, From a47e04124f7056f0aad0bb48bd80332689a86e68 Mon Sep 17 00:00:00 2001 From: jrx Date: Wed, 4 Dec 2024 09:54:51 +0100 Subject: [PATCH 13/15] review changes --- src/decoders/decoder.rs | 2 +- src/decoders/dns.rs | 128 +++++++++++++++------------------------- 2 files changed, 49 insertions(+), 81 deletions(-) diff --git a/src/decoders/decoder.rs b/src/decoders/decoder.rs index 63edd59..0717b42 100644 --- a/src/decoders/decoder.rs +++ b/src/decoders/decoder.rs @@ -137,7 +137,7 @@ pub(crate) fn check_objects( match message_value { Ok(value) => value, Err(e) => { - log::error!("[macos-unifiedlogs] Failed to parse DNS header counts. Error: {e:?}"); + log::error!("[macos-unifiedlogs] Failed to decode log object. Error: {e:?}"); e.to_string() } } diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index b275445..0d05d84 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -14,8 +14,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ bytes::complete::take, - combinator::{fail, iterator, map_parser, verify}, - multi::fold_many0, + combinator::{fail, map, map_parser, verify}, + multi::{fold_many0, many0}, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, IResult, @@ -227,95 +227,46 @@ fn parse_svcb_alpn(mut input: &[u8]) -> nom::IResult<&[u8], String> { } /// Parse the IPs -// fn parse_svcb_ip(data: &[u8]) -> nom::IResult<&[u8], String> { -// const IPV4: u16 = 4; -// const IPV6: u16 = 6; - -// let mut dns_data = data; - -// let mut ipv4_addrs = vec![]; -// let mut ipv6_addrs = vec![]; - -// // IPs can either be IPv4 or/and IPv6 -// while !dns_data.is_empty() { -// let (remaining_dns_data, (ip_version, ip_size)) = -// tuple((verify(be_u16, |val| *val == IPV4 || *val == IPV6), be_u16))(dns_data)?; - -// let (remaining_dns_data, ip_data) = take(ip_size)(remaining_dns_data)?; - -// dns_data = remaining_dns_data; - -// // There can be multiple IPs -// match ip_version { -// IPV4 => { -// let (_, mut addrs) = -// many0(map(be_u32, |raw| Ipv4Addr::from(raw).to_string()))(ip_data)?; -// ipv4_addrs.append(&mut addrs); -// } -// IPV6 => { -// let (_, mut addrs) = -// many0(map(be_u128, |raw| Ipv6Addr::from(raw).to_string()))(ip_data)?; -// ipv6_addrs.append(&mut addrs); -// } -// _ => {} -// }; -// } - -// let message = format!( -// "ipv4 hint:{}, ipv6 hint:{}", -// ipv4_addrs.join(","), -// ipv6_addrs.join(",") -// ); -// Ok((dns_data, message)) -// } - -fn parse_svcb_ip(mut input: &[u8]) -> nom::IResult<&[u8], String> { +fn parse_svcb_ip(data: &[u8]) -> nom::IResult<&[u8], String> { const IPV4: u16 = 4; const IPV6: u16 = 6; - fn ipv4_parser(input: &[u8]) -> nom::IResult<&[u8], Ipv4Addr> { - let (i, raw) = be_u32(input)?; - Ok((i, Ipv4Addr::from(raw))) - } - - fn ipv6_parser(input: &[u8]) -> nom::IResult<&[u8], Ipv6Addr> { - let (i, raw) = be_u128(input)?; - Ok((i, Ipv6Addr::from(raw))) - } + let mut dns_data = data; - let mut ipv4s = String::with_capacity(2 * 16); // let's reserve max space for 2 IPV4 addresses - let mut ipv6s = String::with_capacity(2 * 40); // let's reserve max space for 8 IPV6 addresses + let mut ipv4_addrs = vec![]; + let mut ipv6_addrs = vec![]; // IPs can either be IPv4 or/and IPv6 - while !input.is_empty() { - let (i, ip_version) = verify(be_u16, |val| *val == IPV4 || *val == IPV6)(input)?; - let (i, ip_size) = be_u16(i)?; - let (i, ip_data) = take(ip_size)(i)?; - input = i; + while !dns_data.is_empty() { + let (remaining_dns_data, (ip_version, ip_size)) = + tuple((verify(be_u16, |val| *val == IPV4 || *val == IPV6), be_u16))(dns_data)?; - if ip_version == IPV4 { - let mut iter = iterator(ip_data, ipv4_parser); - for ip in iter.into_iter() { - if !ipv4s.is_empty() { - ipv4s.push(','); - } - write!(ipv4s, "{}", ip).ok(); // ignore errors on write in String + let (remaining_dns_data, ip_data) = take(ip_size)(remaining_dns_data)?; + + dns_data = remaining_dns_data; + + // There can be multiple IPs + match ip_version { + IPV4 => { + let (_, mut addrs) = + many0(map(be_u32, |raw| Ipv4Addr::from(raw).to_string()))(ip_data)?; + ipv4_addrs.append(&mut addrs); } - iter.finish()?; - } else if ip_version == IPV6 { - let mut iter = iterator(ip_data, ipv6_parser); - for ip in iter.into_iter() { - if !ipv6s.is_empty() { - ipv6s.push(','); - } - write!(ipv6s, "{}", ip).ok(); // ignore errors on write in String + IPV6 => { + let (_, mut addrs) = + many0(map(be_u128, |raw| Ipv6Addr::from(raw).to_string()))(ip_data)?; + ipv6_addrs.append(&mut addrs); } - iter.finish()?; - } + _ => {} + }; } - let message = format!("ipv4 hint:{ipv4s}, ipv6 hint:{ipv6s}"); - Ok((input, message)) + let message = format!( + "ipv4 hint:{}, ipv6 hint:{}", + ipv4_addrs.join(","), + ipv6_addrs.join(",") + ); + Ok((dns_data, message)) } /// Get the MAC Address from the log data @@ -718,6 +669,23 @@ mod tests { assert_eq!(result, "ipv4 hint:104.16.148.64,104.16.149.64, ipv6 hint:2606:4700::6810:9440,2606:4700::6810:9540"); } + #[test] + fn test_parse_svcb_ip_should_not_infine_loop() { + let test_data = [ + 0, 4, 0, 4, 104, 16, 148, 64, // 104.16.148.64 + 0, 6, 0, 16, 38, 6, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 16, 148, 64, // 2606:4700::6810:9440 + 0, 42, 0, 0 // [invalid data] infinite loop (consuming too much) in the previous version + ]; + + let result = parse_svcb_ip(&test_data); + assert!(result.is_err()); + + // // Previous version would have this behavior : + // let (rest, result) = parse_svcb_ip(&test_data).unwrap(); + // assert_eq!(rest, &[] as &[u8]); + // assert_eq!(result, "ipv4 hint:104.16.148.64, ipv6 hint:2606:4700::6810:9440,"); + } + #[test] fn test_get_dns_mac_addr() { let test_data = "AAAAAAAA"; From 6e24491e6cef263fa91d0c292b82e687cce4e493 Mon Sep 17 00:00:00 2001 From: jrx Date: Wed, 4 Dec 2024 10:00:08 +0100 Subject: [PATCH 14/15] formating --- src/decoders/dns.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index 0d05d84..4f9838d 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -669,12 +669,15 @@ mod tests { assert_eq!(result, "ipv4 hint:104.16.148.64,104.16.149.64, ipv6 hint:2606:4700::6810:9440,2606:4700::6810:9540"); } - #[test] + #[test] fn test_parse_svcb_ip_should_not_infine_loop() { let test_data = [ - 0, 4, 0, 4, 104, 16, 148, 64, // 104.16.148.64 - 0, 6, 0, 16, 38, 6, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 16, 148, 64, // 2606:4700::6810:9440 - 0, 42, 0, 0 // [invalid data] infinite loop (consuming too much) in the previous version + // 104.16.148.64 + 0, 4, 0, 4, 104, 16, 148, 64, // + // 2606:4700::6810:9440 + 0, 6, 0, 16, 38, 6, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 16, 148, 64, + // [invalid data] infinite loop (consuming too much) in the previous version + 0, 42, 0, 0, ]; let result = parse_svcb_ip(&test_data); From b7be85426fa29513fce72d528cc8af3644f70e18 Mon Sep 17 00:00:00 2001 From: jrx Date: Wed, 4 Dec 2024 19:41:14 +0100 Subject: [PATCH 15/15] reviews --- src/decoders/dns.rs | 5 ++--- src/decoders/network.rs | 9 +++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index 4f9838d..a6b0334 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -288,7 +288,7 @@ pub(crate) fn get_dns_mac_addr(input: &str) -> Result> /// Parse the MAC Address fn parse_mac_addr(input: &[u8]) -> nom::IResult<&[u8], String> { - let (input, mac_string) = fold_many0( + fold_many0( be_u8, || String::with_capacity(input.len() * 3), // This buffer will not have to reallocate/grow |mut acc, item| { @@ -298,8 +298,7 @@ fn parse_mac_addr(input: &[u8]) -> nom::IResult<&[u8], String> { write!(&mut acc, "{:02X?}", item).ok(); // ignore errors on write in String acc }, - )(input)?; - Ok((input, mac_string)) + )(input) } /// Get IP Address info from log data diff --git a/src/decoders/network.rs b/src/decoders/network.rs index 8359b98..c28757a 100644 --- a/src/decoders/network.rs +++ b/src/decoders/network.rs @@ -9,6 +9,7 @@ use crate::util::decode_standard; use log::{error, warn}; use nom::{ bytes::complete::take, + combinator::map, number::complete::{be_u128, be_u16, be_u32, be_u8}, }; use std::net::Ipv6Addr; @@ -151,16 +152,12 @@ fn get_sockaddr_data(data: &[u8]) -> nom::IResult<&[u8], String> { /// Get the IPv4 data pub(crate) fn get_ip_four(input: &[u8]) -> nom::IResult<&[u8], String> { - let (input, ip) = be_u32(input)?; - let ip = Ipv4Addr::from(ip); - Ok((input, ip.to_string())) + map(be_u32, |val| Ipv4Addr::from(val).to_string())(input) } /// Get the IPv6 data pub(crate) fn get_ip_six(input: &[u8]) -> nom::IResult<&[u8], String> { - let (input, ip) = be_u128(input)?; - let ip = Ipv6Addr::from(ip); - Ok((input, ip.to_string())) + map(be_u128, |val| Ipv6Addr::from(val).to_string())(input) } #[cfg(test)]