diff options
Diffstat (limited to '')
-rw-r--r-- | rust/src/mqtt/logger.rs | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/rust/src/mqtt/logger.rs b/rust/src/mqtt/logger.rs new file mode 100644 index 0000000..af0db17 --- /dev/null +++ b/rust/src/mqtt/logger.rs @@ -0,0 +1,305 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +// written by Sascha Steinbiss <sascha@steinbiss.name> + +use super::mqtt::MQTTTransaction; +use crate::jsonbuilder::{JsonBuilder, JsonError}; +use crate::mqtt::mqtt_message::{MQTTOperation, MQTTSubscribeTopicData}; +use crate::mqtt::parser::FixedHeader; +use std; + +pub const MQTT_LOG_PASSWORDS: u32 = BIT_U32!(0); + +#[inline] +fn log_mqtt_topic(js: &mut JsonBuilder, t: &MQTTSubscribeTopicData) -> Result<(), JsonError> { + js.start_object()?; + js.set_string("topic", &t.topic_name)?; + js.set_uint("qos", t.qos as u64)?; + js.close()?; + return Ok(()); +} + +#[inline] +fn log_mqtt_header(js: &mut JsonBuilder, hdr: &FixedHeader) -> Result<(), JsonError> { + js.set_uint("qos", hdr.qos_level as u64)?; + js.set_bool("retain", hdr.retain)?; + js.set_bool("dup", hdr.dup_flag)?; + return Ok(()); +} + +fn log_mqtt(tx: &MQTTTransaction, flags: u32, js: &mut JsonBuilder) -> Result<(), JsonError> { + js.open_object("mqtt")?; + for msg in tx.msg.iter() { + match msg.op { + MQTTOperation::CONNECT(ref conn) => { + js.open_object("connect")?; + log_mqtt_header(js, &msg.header)?; + js.set_string("protocol_string", &conn.protocol_string)?; + js.set_uint("protocol_version", conn.protocol_version as u64)?; + js.set_string("client_id", &conn.client_id)?; + js.open_object("flags")?; + js.set_bool("username", conn.username_flag)?; + js.set_bool("password", conn.password_flag)?; + js.set_bool("will_retain", conn.will_retain)?; + js.set_bool("will", conn.will_flag)?; + js.set_bool("clean_session", conn.clean_session)?; + js.close()?; // flags + if let Some(user) = &conn.username { + js.set_string("username", user)?; + } + if flags & MQTT_LOG_PASSWORDS != 0 { + if let Some(pass) = &conn.password { + js.set_string_from_bytes("password", pass)?; + } + } + if conn.will_flag { + js.open_object("will")?; + if let Some(will_topic) = &conn.will_topic { + js.set_string("topic", will_topic)?; + } + if let Some(will_message) = &conn.will_message { + js.set_string_from_bytes("message", will_message)?; + } + if let Some(will_properties) = &conn.will_properties { + js.open_object("properties")?; + for prop in will_properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // will + } + if let Some(properties) = &conn.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // connect + } + MQTTOperation::CONNACK(ref connack) => { + js.open_object("connack")?; + log_mqtt_header(js, &msg.header)?; + js.set_bool("session_present", connack.session_present)?; + js.set_uint("return_code", connack.return_code as u64)?; + if let Some(properties) = &connack.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // connack + } + MQTTOperation::PUBLISH(ref publish) => { + js.open_object("publish")?; + log_mqtt_header(js, &msg.header)?; + js.set_string("topic", &publish.topic)?; + if let Some(message_id) = publish.message_id { + js.set_uint("message_id", message_id as u64)?; + } + js.set_string_from_bytes("message", &publish.message)?; + if let Some(properties) = &publish.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // publish + } + MQTTOperation::PUBACK(ref msgidonly) => { + js.open_object("puback")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", msgidonly.message_id as u64)?; + if let Some(reason_code) = &msgidonly.reason_code { + js.set_uint("reason_code", *reason_code as u64)?; + } + if let Some(properties) = &msgidonly.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // puback + } + MQTTOperation::PUBREC(ref msgidonly) => { + js.open_object("pubrec")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", msgidonly.message_id as u64)?; + if let Some(reason_code) = &msgidonly.reason_code { + js.set_uint("reason_code", *reason_code as u64)?; + } + if let Some(properties) = &msgidonly.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // pubrec + } + MQTTOperation::PUBREL(ref msgidonly) => { + js.open_object("pubrel")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", msgidonly.message_id as u64)?; + if let Some(reason_code) = &msgidonly.reason_code { + js.set_uint("reason_code", *reason_code as u64)?; + } + if let Some(properties) = &msgidonly.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // pubrel + } + MQTTOperation::PUBCOMP(ref msgidonly) => { + js.open_object("pubcomp")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", msgidonly.message_id as u64)?; + if let Some(reason_code) = &msgidonly.reason_code { + js.set_uint("reason_code", *reason_code as u64)?; + } + if let Some(properties) = &msgidonly.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // pubcomp + } + MQTTOperation::SUBSCRIBE(ref subs) => { + js.open_object("subscribe")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", subs.message_id as u64)?; + js.open_array("topics")?; + for t in &subs.topics { + log_mqtt_topic(js, t)?; + } + js.close()?; //topics + if let Some(properties) = &subs.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // subscribe + } + MQTTOperation::SUBACK(ref suback) => { + js.open_object("suback")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", suback.message_id as u64)?; + js.open_array("qos_granted")?; + for t in &suback.qoss { + js.append_uint(*t as u64)?; + } + js.close()?; // qos_granted + js.close()?; // suback + } + MQTTOperation::UNSUBSCRIBE(ref unsub) => { + js.open_object("unsubscribe")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", unsub.message_id as u64)?; + js.open_array("topics")?; + for t in &unsub.topics { + js.append_string(t)?; + } + js.close()?; // topics + js.close()?; // unsubscribe + } + MQTTOperation::UNSUBACK(ref unsuback) => { + js.open_object("unsuback")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("message_id", unsuback.message_id as u64)?; + if let Some(codes) = &unsuback.reason_codes { + if !codes.is_empty() { + js.open_array("reason_codes")?; + for t in codes { + js.append_uint(*t as u64)?; + } + js.close()?; // reason_codes + } + } + js.close()?; // unsuback + } + MQTTOperation::PINGREQ => { + js.open_object("pingreq")?; + log_mqtt_header(js, &msg.header)?; + js.close()?; // pingreq + } + MQTTOperation::PINGRESP => { + js.open_object("pingresp")?; + log_mqtt_header(js, &msg.header)?; + js.close()?; // pingresp + } + MQTTOperation::AUTH(ref auth) => { + js.open_object("auth")?; + log_mqtt_header(js, &msg.header)?; + js.set_uint("reason_code", auth.reason_code as u64)?; + if let Some(properties) = &auth.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // auth + } + MQTTOperation::DISCONNECT(ref disco) => { + js.open_object("disconnect")?; + log_mqtt_header(js, &msg.header)?; + if let Some(reason_code) = &disco.reason_code { + js.set_uint("reason_code", *reason_code as u64)?; + } + if let Some(properties) = &disco.properties { + js.open_object("properties")?; + for prop in properties { + prop.set_json(js)?; + } + js.close()?; // properties + } + js.close()?; // disconnect + } + MQTTOperation::TRUNCATED(ref trunc) => { + js.open_object(&trunc.original_message_type.to_lower_str())?; + log_mqtt_header(js, &msg.header)?; + js.set_bool("truncated", true)?; + js.set_uint("skipped_length", trunc.skipped_length as u64)?; + js.close()?; // truncated + } + MQTTOperation::UNASSIGNED => {} + } + } + js.close()?; // mqtt + + return Ok(()); +} + +#[no_mangle] +pub unsafe extern "C" fn rs_mqtt_logger_log( + tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder, +) -> bool { + let tx = cast_pointer!(tx, MQTTTransaction); + log_mqtt(tx, flags, js).is_ok() +} |