From 8448db149b2e007c85a23619ec270dde1bb433a6 Mon Sep 17 00:00:00 2001 From: Dirk Alders Date: Mon, 31 Jul 2023 19:23:12 +0200 Subject: [PATCH] Initial mqtt-sniffer --- .gitmodules | 6 ++++ console_bottombar | 1 + mqtt | 1 + mqtt-sniffer.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 .gitmodules create mode 160000 console_bottombar create mode 160000 mqtt create mode 100644 mqtt-sniffer.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2a59480 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "mqtt"] + path = mqtt + url = https://git.mount-mockery.de/pylib/mqtt.git +[submodule "console_bottombar"] + path = console_bottombar + url = https://git.mount-mockery.de/pylib/console_bottombar.git diff --git a/console_bottombar b/console_bottombar new file mode 160000 index 0000000..ff04343 --- /dev/null +++ b/console_bottombar @@ -0,0 +1 @@ +Subproject commit ff0434370a4229019a2cefcb01bb159325ff96b2 diff --git a/mqtt b/mqtt new file mode 160000 index 0000000..1adfb06 --- /dev/null +++ b/mqtt @@ -0,0 +1 @@ +Subproject commit 1adfb0626e7777c6d29be65d4ad4ce2d57541301 diff --git a/mqtt-sniffer.py b/mqtt-sniffer.py new file mode 100644 index 0000000..939ec6d --- /dev/null +++ b/mqtt-sniffer.py @@ -0,0 +1,73 @@ +import argparse +from console_bottombar import BottomBar +import json +import mqtt +import os +import re +import time + +VERSION = "0.1.0" +STARTTIME = time.time() +# TODO: Implement default values for bottombar_entries +# TODO: Implement the Filter functionality + +HELPTEXT = """ +F1: Get this help message +F2: Set a filter (regular expression) for the topic of a message + Examples: + * "/gfw/*/videv" Get everything with "/gfw/" before "/videv" +F9: Start / Stop logging to mqtt-sniffer.log +F12: Quit the mqtt sniffer +""" + +def rx_mqtt(mc, userdata, message): + global my_bb + global logfile + try: + match = len(re.findall(my_bb.get_entry('msg_re'), message.topic)) > 0 + except re.error: + print('No valid regular expression (%s). No filter active.' % my_bb.get_entry('msg_re')) + match = True + + ts = time.time()-STARTTIME + data = None + try: + data = json.loads(message.payload) + except: + pass + try: + data = message.payload.decode("utf-8") + except: + data = message.payload + + if match: + print("%9.04f::%30s::%s" % (ts, message.topic, data)) + if my_bb.get_entry('log2file'): + logfile.write("%9.04f::%30s::%s\n" % (ts, message.topic, data)) + logfile.flush() + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='This is a mqtt sniffer.') + parser.add_argument('-f', dest='hostname', default='localhost', help='Hostname of the mqtt server') + parser.add_argument('-p', dest='port', default=1883, help='Port of the mqtt server') + parser.add_argument('-n', dest='no_credentials', action='store_true', help='Avoid asking for credentials') + parser.add_argument('-u', dest='username', default=None, help='Set username for mqtt server') + + args = parser.parse_args() + + if not args.no_credentials: + if args.username == None: + args.username = input("Username: ") + password = "" + else: + password = None + + my_bb = BottomBar(VERSION, label='MQTT-Sniffer') + my_bb.add_entry('help', 1, my_bb.FUNC_INFO, label='[F1] Help', infotext=HELPTEXT) + my_bb.add_entry('msg_re', 2, my_bb.FUNC_TEXT, label='[F2] Filter') + my_bb.add_entry('quit', 12, my_bb.FUNC_QUIT, "Quit", label='[F12]', right=True) + my_bb.add_entry('log2file', 9, my_bb.FUNC_BOOL, label='[F9] Log2File', right=True) + with open('sniffer.log', 'w') as logfile: + mc = mqtt.mqtt_client("sniffer", args.hostname, port=args.port, username=args.username, password=password) + mc.add_callback("#", rx_mqtt) + my_bb.run()