summaryrefslogtreecommitdiffstats
path: root/rust/src/mqtt/logger.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rust/src/mqtt/logger.rs305
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()
+}